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