1/* $XFree86: xc/lib/GL/dri/XF86dri.c,v 1.13 2002/10/30 12:51:25 alanh Exp $ */
2/**************************************************************************
3
4Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
5Copyright 2000 VA Linux Systems, Inc.
6All Rights Reserved.
7
8Permission is hereby granted, free of charge, to any person obtaining a
9copy of this software and associated documentation files (the
10"Software"), to deal in the Software without restriction, including
11without limitation the rights to use, copy, modify, merge, publish,
12distribute, sub license, and/or sell copies of the Software, and to
13permit persons to whom the Software is furnished to do so, subject to
14the following conditions:
15
16The above copyright notice and this permission notice (including the
17next paragraph) shall be included in all copies or substantial portions
18of the Software.
19
20THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
23IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
24ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
25TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
26SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27
28**************************************************************************/
29
30/*
31 * Authors:
32 *   Kevin E. Martin <martin@valinux.com>
33 *   Jens Owen <jens@tungstengraphics.com>
34 *   Rickard E. (Rik) Faith <faith@valinux.com>
35 *
36 */
37
38/*
39 * This file has been copied from the mesa source tree and a little bit
40 * modified by:
41 *
42 * Dodji Seketeli <dodji@openedhand.com>
43 */
44
45#ifdef HAVE_CONFIG_H
46#include <kdrive-config.h>
47#endif
48/*
49 * including some server headers (like kdrive-config.h)
50 * might define the macro _XSERVER64
51 * on 64 bits machines. That macro must _NOT_ be defined for Xlib
52 * client code, otherwise bad things happen.
53 * So let's undef that macro if necessary.
54 */
55#ifdef _XSERVER64
56#undef _XSERVER64
57#endif
58
59/* THIS IS NOT AN X CONSORTIUM STANDARD */
60
61#include <X11/Xlibint.h>
62#include <X11/extensions/Xext.h>
63#include <X11/extensions/extutil.h>
64#include <GL/glx.h>
65#include "xf86dri.h"
66#include <X11/dri/xf86driproto.h>
67
68static XExtensionInfo _xf86dri_info_data;
69static XExtensionInfo *xf86dri_info = &_xf86dri_info_data;
70static char xf86dri_extension_name[] = XF86DRINAME;
71
72#define XF86DRICheckExtension(dpy,i,val) \
73  XextCheckExtension (dpy, i, xf86dri_extension_name, val)
74
75/*****************************************************************************
76 *                                                                           *
77 *			   private utility routines                          *
78 *                                                                           *
79 *****************************************************************************/
80
81static int close_display(Display *dpy, XExtCodes *extCodes);
82static /* const */ XExtensionHooks xf86dri_extension_hooks = {
83    NULL,				/* create_gc */
84    NULL,				/* copy_gc */
85    NULL,				/* flush_gc */
86    NULL,				/* free_gc */
87    NULL,				/* create_font */
88    NULL,				/* free_font */
89    close_display,			/* close_display */
90    NULL,				/* wire_to_event */
91    NULL,				/* event_to_wire */
92    NULL,				/* error */
93    NULL,				/* error_string */
94};
95
96static XEXT_GENERATE_FIND_DISPLAY (find_display, xf86dri_info,
97				   xf86dri_extension_name,
98				   &xf86dri_extension_hooks,
99				   0, NULL)
100
101static XEXT_GENERATE_CLOSE_DISPLAY (close_display, xf86dri_info)
102
103
104/*****************************************************************************
105 *                                                                           *
106 *		    public XFree86-DRI Extension routines                    *
107 *                                                                           *
108 *****************************************************************************/
109
110#if 0
111#include <stdio.h>
112#define TRACE(msg)  fprintf(stderr,"XF86DRI%s\n", msg);
113#else
114#define TRACE(msg)
115#endif
116
117Bool XF86DRIOpenFullScreen(Display *dpy, int screen, Drawable drawable);
118Bool XF86DRICloseFullScreen(Display *dpy, int screen, Drawable drawable);
119
120Bool XF86DRIQueryExtension (Display *dpy, int *event_basep, int *error_basep)
121{
122    XExtDisplayInfo *info = find_display (dpy);
123
124    TRACE("QueryExtension...");
125    if (XextHasExtension(info)) {
126	*event_basep = info->codes->first_event;
127	*error_basep = info->codes->first_error;
128        TRACE("QueryExtension... return True");
129	return True;
130    } else {
131        TRACE("QueryExtension... return False");
132	return False;
133    }
134}
135
136Bool XF86DRIQueryVersion(Display *dpy, int *majorVersion, int *minorVersion,
137                         int *patchVersion)
138{
139    XExtDisplayInfo *info = find_display (dpy);
140    xXF86DRIQueryVersionReply rep;
141    xXF86DRIQueryVersionReq *req;
142
143    TRACE("QueryVersion...");
144    XF86DRICheckExtension (dpy, info, False);
145
146    LockDisplay(dpy);
147    GetReq(XF86DRIQueryVersion, req);
148    req->reqType = info->codes->major_opcode;
149    req->driReqType = X_XF86DRIQueryVersion;
150    if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
151	UnlockDisplay(dpy);
152	SyncHandle();
153        TRACE("QueryVersion... return False");
154	return False;
155    }
156    *majorVersion = rep.majorVersion;
157    *minorVersion = rep.minorVersion;
158    *patchVersion = rep.patchVersion;
159    UnlockDisplay(dpy);
160    SyncHandle();
161    TRACE("QueryVersion... return True");
162    return True;
163}
164
165Bool
166XF86DRIQueryDirectRenderingCapable (Display *dpy, int screen, Bool *isCapable)
167{
168    XExtDisplayInfo *info = find_display (dpy);
169    xXF86DRIQueryDirectRenderingCapableReply rep;
170    xXF86DRIQueryDirectRenderingCapableReq *req;
171
172    TRACE("QueryDirectRenderingCapable...");
173    XF86DRICheckExtension (dpy, info, False);
174
175    LockDisplay(dpy);
176    GetReq(XF86DRIQueryDirectRenderingCapable, req);
177    req->reqType = info->codes->major_opcode;
178    req->driReqType = X_XF86DRIQueryDirectRenderingCapable;
179    req->screen = screen;
180    if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
181        UnlockDisplay(dpy);
182        SyncHandle();
183        TRACE("QueryDirectRenderingCapable... return False");
184        return False;
185    }
186    *isCapable = rep.isCapable;
187    UnlockDisplay(dpy);
188    SyncHandle();
189    TRACE("QueryDirectRenderingCapable... return True");
190    return True;
191}
192
193Bool
194XF86DRIOpenConnection (Display *dpy, int screen,
195                       drm_handle_t *hSAREA,
196                       char **busIdString)
197{
198    XExtDisplayInfo *info = find_display (dpy);
199    xXF86DRIOpenConnectionReply rep;
200    xXF86DRIOpenConnectionReq *req;
201
202    TRACE("OpenConnection...");
203    XF86DRICheckExtension (dpy, info, False);
204
205    LockDisplay(dpy);
206    GetReq(XF86DRIOpenConnection, req);
207    req->reqType = info->codes->major_opcode;
208    req->driReqType = X_XF86DRIOpenConnection;
209    req->screen = screen;
210    if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
211        UnlockDisplay(dpy);
212        SyncHandle();
213        TRACE("OpenConnection... return False");
214        return False;
215    }
216
217    *hSAREA = rep.hSAREALow;
218    if (sizeof(drm_handle_t) == 8) {
219        int shift = 32; /* var to prevent warning on next line */
220        *hSAREA |= ((drm_handle_t) rep.hSAREAHigh) << shift;
221    }
222
223    if (rep.length) {
224        if (!(*busIdString = (char *)calloc(rep.busIdStringLength + 1, 1))) {
225            _XEatData(dpy, ((rep.busIdStringLength+3) & ~3));
226            UnlockDisplay(dpy);
227            SyncHandle();
228            TRACE("OpenConnection... return False");
229            return False;
230        }
231        _XReadPad(dpy, *busIdString, rep.busIdStringLength);
232    } else {
233        *busIdString = NULL;
234    }
235    UnlockDisplay(dpy);
236    SyncHandle();
237    TRACE("OpenConnection... return True");
238    return True;
239}
240
241Bool XF86DRIAuthConnection(Display *dpy, int screen, drm_magic_t magic)
242{
243    XExtDisplayInfo *info = find_display (dpy);
244    xXF86DRIAuthConnectionReq *req;
245    xXF86DRIAuthConnectionReply rep;
246
247    TRACE("AuthConnection...");
248    XF86DRICheckExtension (dpy, info, False);
249
250    LockDisplay(dpy);
251    GetReq(XF86DRIAuthConnection, req);
252    req->reqType = info->codes->major_opcode;
253    req->driReqType = X_XF86DRIAuthConnection;
254    req->screen = screen;
255    req->magic = magic;
256    rep.authenticated = 0;
257    if (!_XReply(dpy, (xReply *)&rep, 0, xFalse) || !rep.authenticated) {
258	UnlockDisplay(dpy);
259	SyncHandle();
260        TRACE("AuthConnection... return False");
261	return False;
262    }
263    UnlockDisplay(dpy);
264    SyncHandle();
265    TRACE("AuthConnection... return True");
266    return True;
267}
268
269Bool XF86DRICloseConnection(Display *dpy, int screen)
270{
271    XExtDisplayInfo *info = find_display (dpy);
272    xXF86DRICloseConnectionReq *req;
273
274    TRACE("CloseConnection...");
275
276    XF86DRICheckExtension (dpy, info, False);
277
278    LockDisplay(dpy);
279    GetReq(XF86DRICloseConnection, req);
280    req->reqType = info->codes->major_opcode;
281    req->driReqType = X_XF86DRICloseConnection;
282    req->screen = screen;
283    UnlockDisplay(dpy);
284    SyncHandle();
285    TRACE("CloseConnection... return True");
286    return True;
287}
288
289Bool XF86DRIGetClientDriverName(Display *dpy, int screen,
290                                int *ddxDriverMajorVersion,
291	                        int *ddxDriverMinorVersion,
292                                int *ddxDriverPatchVersion,
293                                char **clientDriverName)
294{
295    XExtDisplayInfo *info = find_display (dpy);
296    xXF86DRIGetClientDriverNameReply rep;
297    xXF86DRIGetClientDriverNameReq *req;
298
299    TRACE("GetClientDriverName...");
300    XF86DRICheckExtension (dpy, info, False);
301
302    LockDisplay(dpy);
303    GetReq(XF86DRIGetClientDriverName, req);
304    req->reqType = info->codes->major_opcode;
305    req->driReqType = X_XF86DRIGetClientDriverName;
306    req->screen = screen;
307    if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
308	UnlockDisplay(dpy);
309	SyncHandle();
310        TRACE("GetClientDriverName... return False");
311	return False;
312    }
313
314    *ddxDriverMajorVersion = rep.ddxDriverMajorVersion;
315    *ddxDriverMinorVersion = rep.ddxDriverMinorVersion;
316    *ddxDriverPatchVersion = rep.ddxDriverPatchVersion;
317
318    if (rep.length) {
319        if (!(*clientDriverName = (char *)calloc(rep.clientDriverNameLength + 1, 1))) {
320            _XEatData(dpy, ((rep.clientDriverNameLength+3) & ~3));
321            UnlockDisplay(dpy);
322            SyncHandle();
323            TRACE("GetClientDriverName... return False");
324            return False;
325        }
326	_XReadPad(dpy, *clientDriverName, rep.clientDriverNameLength);
327    } else {
328        *clientDriverName = NULL;
329    }
330    UnlockDisplay(dpy);
331    SyncHandle();
332    TRACE("GetClientDriverName... return True");
333    return True;
334}
335
336Bool XF86DRICreateContextWithConfig(Display *dpy, int screen, int configID,
337                                    XID *context, drm_context_t *hHWContext)
338{
339    XExtDisplayInfo *info = find_display (dpy);
340    xXF86DRICreateContextReply rep;
341    xXF86DRICreateContextReq *req;
342
343    TRACE("CreateContext...");
344    XF86DRICheckExtension (dpy, info, False);
345
346    LockDisplay(dpy);
347    GetReq(XF86DRICreateContext, req);
348    req->reqType = info->codes->major_opcode;
349    req->driReqType = X_XF86DRICreateContext;
350    req->visual = configID;
351    req->screen = screen;
352    *context = XAllocID(dpy);
353    req->context = *context;
354    if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
355	UnlockDisplay(dpy);
356	SyncHandle();
357        TRACE("CreateContext... return False");
358	return False;
359    }
360    *hHWContext = rep.hHWContext;
361    UnlockDisplay(dpy);
362    SyncHandle();
363    TRACE("CreateContext... return True");
364    return True;
365}
366
367Bool XF86DRICreateContext(Display *dpy, int screen, Visual *visual,
368                          XID *context, drm_context_t *hHWContext)
369{
370    return XF86DRICreateContextWithConfig( dpy, screen, visual->visualid,
371					   context, hHWContext );
372}
373
374GLboolean XF86DRIDestroyContext( Display *dpy, int screen, XID context)
375{
376    XExtDisplayInfo *info = find_display (dpy);
377    xXF86DRIDestroyContextReq *req;
378
379    TRACE("DestroyContext...");
380    XF86DRICheckExtension (dpy, info, False);
381
382    LockDisplay(dpy);
383    GetReq(XF86DRIDestroyContext, req);
384    req->reqType = info->codes->major_opcode;
385    req->driReqType = X_XF86DRIDestroyContext;
386    req->screen = screen;
387    req->context = context;
388    UnlockDisplay(dpy);
389    SyncHandle();
390    TRACE("DestroyContext... return True");
391    return True;
392}
393
394GLboolean
395XF86DRICreateDrawable (Display *dpy, int screen,
396                       XID drawable, drm_drawable_t * hHWDrawable)
397{
398    XExtDisplayInfo *info = find_display (dpy);
399    xXF86DRICreateDrawableReply rep;
400    xXF86DRICreateDrawableReq *req;
401
402    TRACE("CreateDrawable...");
403    XF86DRICheckExtension (dpy, info, False);
404
405    LockDisplay(dpy);
406    GetReq(XF86DRICreateDrawable, req);
407    req->reqType = info->codes->major_opcode;
408    req->driReqType = X_XF86DRICreateDrawable;
409    req->screen = screen;
410    req->drawable = drawable;
411    if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
412	UnlockDisplay(dpy);
413	SyncHandle();
414        TRACE("CreateDrawable... return False");
415	return False;
416    }
417    *hHWDrawable = rep.hHWDrawable;
418    UnlockDisplay(dpy);
419    SyncHandle();
420    TRACE("CreateDrawable... return True");
421    return True;
422}
423
424static int noopErrorHandler(Display *dpy, XErrorEvent *xerr)
425{
426    return 0;
427}
428
429GLboolean XF86DRIDestroyDrawable( Display *dpy, int screen,
430    XID drawable )
431{
432    XExtDisplayInfo *info = find_display (dpy);
433    xXF86DRIDestroyDrawableReq *req;
434    int (*oldXErrorHandler)(Display *, XErrorEvent *);
435
436    TRACE("DestroyDrawable...");
437    XF86DRICheckExtension (dpy, info, False);
438
439    /* This is called from the DRI driver, which used call it like this
440     *
441     *   if (windowExists(drawable))
442     *     destroyDrawable(drawable);
443     *
444     * which is a textbook race condition - the window may disappear
445     * from the server between checking for its existance and
446     * destroying it.  Instead we change the semantics of
447     * __DRIinterfaceMethodsRec::destroyDrawable() to succeed even if
448     * the windows is gone, by wrapping the destroy call in an error
449     * handler. */
450
451    XSync(dpy, GL_FALSE);
452    oldXErrorHandler = XSetErrorHandler(noopErrorHandler);
453
454    LockDisplay(dpy);
455    GetReq(XF86DRIDestroyDrawable, req);
456    req->reqType = info->codes->major_opcode;
457    req->driReqType = X_XF86DRIDestroyDrawable;
458    req->screen = screen;
459    req->drawable = drawable;
460    UnlockDisplay(dpy);
461    SyncHandle();
462
463    XSetErrorHandler(oldXErrorHandler);
464
465    TRACE("DestroyDrawable... return True");
466    return True;
467}
468
469Bool XF86DRIGetDrawableInfo(Display* dpy, int screen, Drawable drawable,
470    unsigned int* index, unsigned int* stamp,
471    int* X, int* Y, int* W, int* H,
472    int* numClipRects, drm_clip_rect_t ** pClipRects,
473    int* backX, int* backY,
474    int* numBackClipRects, drm_clip_rect_t ** pBackClipRects )
475{
476    XExtDisplayInfo *info = find_display (dpy);
477    xXF86DRIGetDrawableInfoReply rep;
478    xXF86DRIGetDrawableInfoReq *req=NULL;
479    int total_rects;
480
481    TRACE("GetDrawableInfo...");
482    XF86DRICheckExtension (dpy, info, False);
483
484    LockDisplay(dpy);
485    GetReq(XF86DRIGetDrawableInfo, req);
486    req->reqType = info->codes->major_opcode;
487    req->driReqType = X_XF86DRIGetDrawableInfo;
488    req->screen = screen;
489    req->drawable = drawable;
490
491    if (!_XReply(dpy, (xReply *)&rep, 1, xFalse))
492    {
493	UnlockDisplay(dpy);
494	SyncHandle();
495        TRACE("GetDrawableInfo... return False");
496	return False;
497    }
498    *index = rep.drawableTableIndex;
499    *stamp = rep.drawableTableStamp;
500    *X = (int)rep.drawableX;
501    *Y = (int)rep.drawableY;
502    *W = (int)rep.drawableWidth;
503    *H = (int)rep.drawableHeight;
504    *numClipRects = rep.numClipRects;
505    total_rects = *numClipRects;
506
507    *backX = rep.backX;
508    *backY = rep.backY;
509    *numBackClipRects = rep.numBackClipRects;
510    total_rects += *numBackClipRects;
511
512#if 0
513    /* Because of the fix in Xserver/GL/dri/xf86dri.c, this check breaks
514     * backwards compatibility (Because of the >> 2 shift) but the fix
515     * enables multi-threaded apps to work.
516     */
517    if (rep.length !=  ((((SIZEOF(xXF86DRIGetDrawableInfoReply) -
518		       SIZEOF(xGenericReply) +
519		       total_rects * sizeof(drm_clip_rect_t)) + 3) & ~3) >> 2)) {
520        _XEatData(dpy, rep.length);
521	UnlockDisplay(dpy);
522	SyncHandle();
523        TRACE("GetDrawableInfo... return False");
524        return False;
525    }
526#endif
527
528    if (*numClipRects) {
529       int len = sizeof(drm_clip_rect_t) * (*numClipRects);
530
531       *pClipRects = (drm_clip_rect_t *)calloc(len, 1);
532       if (*pClipRects)
533	  _XRead(dpy, (char*)*pClipRects, len);
534    } else {
535        *pClipRects = NULL;
536    }
537
538    if (*numBackClipRects) {
539       int len = sizeof(drm_clip_rect_t) * (*numBackClipRects);
540
541       *pBackClipRects = (drm_clip_rect_t *)calloc(len, 1);
542       if (*pBackClipRects)
543	  _XRead(dpy, (char*)*pBackClipRects, len);
544    } else {
545        *pBackClipRects = NULL;
546    }
547
548    UnlockDisplay(dpy);
549    SyncHandle();
550    TRACE("GetDrawableInfo... return True");
551    return True;
552}
553
554Bool
555XF86DRIGetDeviceInfo (Display *dpy, int screen, drm_handle_t *hFrameBuffer,
556                      int *fbOrigin, int *fbSize, int *fbStride,
557                      int *devPrivateSize, void **pDevPrivate)
558{
559    XExtDisplayInfo *info = find_display (dpy);
560    xXF86DRIGetDeviceInfoReply rep;
561    xXF86DRIGetDeviceInfoReq *req;
562
563    TRACE("GetDeviceInfo...");
564    XF86DRICheckExtension (dpy, info, False);
565
566    LockDisplay(dpy);
567    GetReq(XF86DRIGetDeviceInfo, req);
568    req->reqType = info->codes->major_opcode;
569    req->driReqType = X_XF86DRIGetDeviceInfo;
570    req->screen = screen;
571    if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
572	UnlockDisplay(dpy);
573	SyncHandle();
574        TRACE("GetDeviceInfo... return False");
575	return False;
576    }
577
578    *hFrameBuffer = rep.hFrameBufferLow;
579    if (sizeof(drm_handle_t) == 8) {
580       int shift = 32; /* var to prevent warning on next line */
581       *hFrameBuffer |= ((drm_handle_t) rep.hFrameBufferHigh) << shift;
582    }
583
584    *fbOrigin = rep.framebufferOrigin;
585    *fbSize = rep.framebufferSize;
586    *fbStride = rep.framebufferStride;
587    *devPrivateSize = rep.devPrivateSize;
588
589    if (rep.length) {
590        if (!(*pDevPrivate = (void *)calloc(rep.devPrivateSize, 1))) {
591            _XEatData(dpy, ((rep.devPrivateSize+3) & ~3));
592            UnlockDisplay(dpy);
593            SyncHandle();
594            TRACE("GetDeviceInfo... return False");
595            return False;
596        }
597	_XRead(dpy, (char*)*pDevPrivate, rep.devPrivateSize);
598    } else {
599        *pDevPrivate = NULL;
600    }
601
602    UnlockDisplay(dpy);
603    SyncHandle();
604    TRACE("GetDeviceInfo... return True");
605    return True;
606}
607
608Bool
609XF86DRIOpenFullScreen(Display *dpy, int screen, Drawable drawable)
610{
611    /* This function and the underlying X protocol are deprecated.
612     */
613    (void) dpy;
614    (void) screen;
615    (void) drawable;
616    return False;
617}
618
619Bool
620XF86DRICloseFullScreen(Display *dpy, int screen, Drawable drawable)
621{
622    /* This function and the underlying X protocol are deprecated.
623     */
624    (void) dpy;
625    (void) screen;
626    (void) drawable;
627    return True;
628}
629