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 <jowen@vmware.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#include <limits.h>
47
48static XExtensionInfo _xf86dri_info_data;
49static XExtensionInfo *xf86dri_info = &_xf86dri_info_data;
50static char xf86dri_extension_name[] = XF86DRINAME;
51
52#define XF86DRICheckExtension(dpy,i,val) \
53  XextCheckExtension (dpy, i, xf86dri_extension_name, val)
54
55/*****************************************************************************
56 *                                                                           *
57 *			   private utility routines                          *
58 *                                                                           *
59 *****************************************************************************/
60
61static int close_display(Display * dpy, XExtCodes * extCodes);
62static /* const */ XExtensionHooks xf86dri_extension_hooks = {
63   NULL,                        /* create_gc */
64   NULL,                        /* copy_gc */
65   NULL,                        /* flush_gc */
66   NULL,                        /* free_gc */
67   NULL,                        /* create_font */
68   NULL,                        /* free_font */
69   close_display,               /* close_display */
70   NULL,                        /* wire_to_event */
71   NULL,                        /* event_to_wire */
72   NULL,                        /* error */
73   NULL,                        /* error_string */
74};
75
76static
77XEXT_GENERATE_FIND_DISPLAY(find_display, xf86dri_info,
78                           xf86dri_extension_name,
79                           &xf86dri_extension_hooks, 0, NULL)
80
81static
82XEXT_GENERATE_CLOSE_DISPLAY(close_display, xf86dri_info)
83
84
85/*****************************************************************************
86 *                                                                           *
87 *		    public XFree86-DRI Extension routines                    *
88 *                                                                           *
89 *****************************************************************************/
90#if 0
91#include <stdio.h>
92#define TRACE(msg)  fprintf(stderr,"XF86DRI%s\n", msg);
93#else
94#define TRACE(msg)
95#endif
96
97Bool
98XF86DRIQueryExtension(Display * dpy, int *event_basep,
99                      int *error_basep)
100{
101   XExtDisplayInfo *info = find_display(dpy);
102
103   TRACE("QueryExtension...");
104   if (XextHasExtension(info)) {
105      *event_basep = info->codes->first_event;
106      *error_basep = info->codes->first_error;
107      TRACE("QueryExtension... return True");
108      return True;
109   }
110   else {
111      TRACE("QueryExtension... return False");
112      return False;
113   }
114}
115
116Bool
117XF86DRIQueryVersion(Display * dpy, int *majorVersion, int *minorVersion,
118                    int *patchVersion)
119{
120   XExtDisplayInfo *info = find_display(dpy);
121   xXF86DRIQueryVersionReply rep;
122   xXF86DRIQueryVersionReq *req;
123
124   TRACE("QueryVersion...");
125   XF86DRICheckExtension(dpy, info, False);
126
127   LockDisplay(dpy);
128   GetReq(XF86DRIQueryVersion, req);
129   req->reqType = info->codes->major_opcode;
130   req->driReqType = X_XF86DRIQueryVersion;
131   if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) {
132      UnlockDisplay(dpy);
133      SyncHandle();
134      TRACE("QueryVersion... return False");
135      return False;
136   }
137   *majorVersion = rep.majorVersion;
138   *minorVersion = rep.minorVersion;
139   *patchVersion = rep.patchVersion;
140   UnlockDisplay(dpy);
141   SyncHandle();
142   TRACE("QueryVersion... return True");
143   return True;
144}
145
146Bool
147XF86DRIQueryDirectRenderingCapable(Display * dpy, int screen,
148                                   Bool * isCapable)
149{
150   XExtDisplayInfo *info = find_display(dpy);
151   xXF86DRIQueryDirectRenderingCapableReply rep;
152   xXF86DRIQueryDirectRenderingCapableReq *req;
153
154   TRACE("QueryDirectRenderingCapable...");
155   XF86DRICheckExtension(dpy, info, False);
156
157   LockDisplay(dpy);
158   GetReq(XF86DRIQueryDirectRenderingCapable, req);
159   req->reqType = info->codes->major_opcode;
160   req->driReqType = X_XF86DRIQueryDirectRenderingCapable;
161   req->screen = screen;
162   if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) {
163      UnlockDisplay(dpy);
164      SyncHandle();
165      TRACE("QueryDirectRenderingCapable... return False");
166      return False;
167   }
168   *isCapable = rep.isCapable;
169   UnlockDisplay(dpy);
170   SyncHandle();
171   TRACE("QueryDirectRenderingCapable... return True");
172   return True;
173}
174
175Bool
176XF86DRIOpenConnection(Display * dpy, int screen, drm_handle_t * hSAREA,
177                      char **busIdString)
178{
179   XExtDisplayInfo *info = find_display(dpy);
180   xXF86DRIOpenConnectionReply rep;
181   xXF86DRIOpenConnectionReq *req;
182
183   TRACE("OpenConnection...");
184   XF86DRICheckExtension(dpy, info, False);
185
186   LockDisplay(dpy);
187   GetReq(XF86DRIOpenConnection, req);
188   req->reqType = info->codes->major_opcode;
189   req->driReqType = X_XF86DRIOpenConnection;
190   req->screen = screen;
191   if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) {
192      UnlockDisplay(dpy);
193      SyncHandle();
194      TRACE("OpenConnection... return False");
195      return False;
196   }
197
198   *hSAREA = rep.hSAREALow;
199   if (sizeof(drm_handle_t) == 8) {
200      int shift = 32;           /* var to prevent warning on next line */
201      *hSAREA |= ((drm_handle_t) rep.hSAREAHigh) << shift;
202   }
203
204   if (rep.length) {
205      if (rep.busIdStringLength < INT_MAX)
206         *busIdString = calloc(rep.busIdStringLength + 1, 1);
207      else
208         *busIdString = NULL;
209      if (*busIdString == NULL) {
210         _XEatData(dpy, ((rep.busIdStringLength + 3) & ~3));
211         UnlockDisplay(dpy);
212         SyncHandle();
213         TRACE("OpenConnection... return False");
214         return False;
215      }
216      _XReadPad(dpy, *busIdString, rep.busIdStringLength);
217   }
218   else {
219      *busIdString = NULL;
220   }
221   UnlockDisplay(dpy);
222   SyncHandle();
223   TRACE("OpenConnection... return True");
224   return True;
225}
226
227Bool
228XF86DRIAuthConnection(Display * dpy, int screen, drm_magic_t magic)
229{
230   XExtDisplayInfo *info = find_display(dpy);
231   xXF86DRIAuthConnectionReq *req;
232   xXF86DRIAuthConnectionReply rep;
233
234   TRACE("AuthConnection...");
235   XF86DRICheckExtension(dpy, info, False);
236
237   LockDisplay(dpy);
238   GetReq(XF86DRIAuthConnection, req);
239   req->reqType = info->codes->major_opcode;
240   req->driReqType = X_XF86DRIAuthConnection;
241   req->screen = screen;
242   req->magic = magic;
243   rep.authenticated = 0;
244   if (!_XReply(dpy, (xReply *) & rep, 0, xFalse) || !rep.authenticated) {
245      UnlockDisplay(dpy);
246      SyncHandle();
247      TRACE("AuthConnection... return False");
248      return False;
249   }
250   UnlockDisplay(dpy);
251   SyncHandle();
252   TRACE("AuthConnection... return True");
253   return True;
254}
255
256Bool
257XF86DRICloseConnection(Display * dpy, int screen)
258{
259   XExtDisplayInfo *info = find_display(dpy);
260   xXF86DRICloseConnectionReq *req;
261
262   TRACE("CloseConnection...");
263
264   XF86DRICheckExtension(dpy, info, False);
265
266   LockDisplay(dpy);
267   GetReq(XF86DRICloseConnection, req);
268   req->reqType = info->codes->major_opcode;
269   req->driReqType = X_XF86DRICloseConnection;
270   req->screen = screen;
271   UnlockDisplay(dpy);
272   SyncHandle();
273   TRACE("CloseConnection... return True");
274   return True;
275}
276
277Bool
278XF86DRIGetClientDriverName(Display * dpy, int screen,
279                           int *ddxDriverMajorVersion,
280                           int *ddxDriverMinorVersion,
281                           int *ddxDriverPatchVersion,
282                           char **clientDriverName)
283{
284   XExtDisplayInfo *info = find_display(dpy);
285   xXF86DRIGetClientDriverNameReply rep;
286   xXF86DRIGetClientDriverNameReq *req;
287
288   TRACE("GetClientDriverName...");
289   XF86DRICheckExtension(dpy, info, False);
290
291   LockDisplay(dpy);
292   GetReq(XF86DRIGetClientDriverName, req);
293   req->reqType = info->codes->major_opcode;
294   req->driReqType = X_XF86DRIGetClientDriverName;
295   req->screen = screen;
296   if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) {
297      UnlockDisplay(dpy);
298      SyncHandle();
299      TRACE("GetClientDriverName... return False");
300      return False;
301   }
302
303   *ddxDriverMajorVersion = rep.ddxDriverMajorVersion;
304   *ddxDriverMinorVersion = rep.ddxDriverMinorVersion;
305   *ddxDriverPatchVersion = rep.ddxDriverPatchVersion;
306
307   if (rep.length) {
308      if (rep.clientDriverNameLength < INT_MAX)
309         *clientDriverName = calloc(rep.clientDriverNameLength + 1, 1);
310      else
311         *clientDriverName = NULL;
312      if (*clientDriverName == NULL) {
313         _XEatData(dpy, ((rep.clientDriverNameLength + 3) & ~3));
314         UnlockDisplay(dpy);
315         SyncHandle();
316         TRACE("GetClientDriverName... return False");
317         return False;
318      }
319      _XReadPad(dpy, *clientDriverName, rep.clientDriverNameLength);
320   }
321   else {
322      *clientDriverName = NULL;
323   }
324   UnlockDisplay(dpy);
325   SyncHandle();
326   TRACE("GetClientDriverName... return True");
327   return True;
328}
329
330Bool
331XF86DRICreateContextWithConfig(Display * dpy, int screen, int configID,
332                               XID * context, drm_context_t * hHWContext)
333{
334   XExtDisplayInfo *info = find_display(dpy);
335   xXF86DRICreateContextReply rep;
336   xXF86DRICreateContextReq *req;
337
338   TRACE("CreateContext...");
339   XF86DRICheckExtension(dpy, info, False);
340
341   LockDisplay(dpy);
342   GetReq(XF86DRICreateContext, req);
343   req->reqType = info->codes->major_opcode;
344   req->driReqType = X_XF86DRICreateContext;
345   req->visual = configID;
346   req->screen = screen;
347   *context = XAllocID(dpy);
348   req->context = *context;
349   if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) {
350      UnlockDisplay(dpy);
351      SyncHandle();
352      TRACE("CreateContext... return False");
353      return False;
354   }
355   *hHWContext = rep.hHWContext;
356   UnlockDisplay(dpy);
357   SyncHandle();
358   TRACE("CreateContext... return True");
359   return True;
360}
361
362Bool
363XF86DRICreateContext(Display * dpy, int screen, Visual * visual,
364                     XID * context, drm_context_t * hHWContext)
365{
366   return XF86DRICreateContextWithConfig(dpy, screen, visual->visualid,
367                                         context, hHWContext);
368}
369
370Bool
371XF86DRIDestroyContext(Display * dpy, int screen, XID context)
372{
373   XExtDisplayInfo *info = find_display(dpy);
374   xXF86DRIDestroyContextReq *req;
375
376   TRACE("DestroyContext...");
377   XF86DRICheckExtension(dpy, info, False);
378
379   LockDisplay(dpy);
380   GetReq(XF86DRIDestroyContext, req);
381   req->reqType = info->codes->major_opcode;
382   req->driReqType = X_XF86DRIDestroyContext;
383   req->screen = screen;
384   req->context = context;
385   UnlockDisplay(dpy);
386   SyncHandle();
387   TRACE("DestroyContext... return True");
388   return True;
389}
390
391Bool
392XF86DRICreateDrawable(Display * dpy, int screen,
393                      XID drawable, drm_drawable_t * hHWDrawable)
394{
395   XExtDisplayInfo *info = find_display(dpy);
396   xXF86DRICreateDrawableReply rep;
397   xXF86DRICreateDrawableReq *req;
398
399   TRACE("CreateDrawable...");
400   XF86DRICheckExtension(dpy, info, False);
401
402   LockDisplay(dpy);
403   GetReq(XF86DRICreateDrawable, req);
404   req->reqType = info->codes->major_opcode;
405   req->driReqType = X_XF86DRICreateDrawable;
406   req->screen = screen;
407   req->drawable = drawable;
408   if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) {
409      UnlockDisplay(dpy);
410      SyncHandle();
411      TRACE("CreateDrawable... return False");
412      return False;
413   }
414   *hHWDrawable = rep.hHWDrawable;
415   UnlockDisplay(dpy);
416   SyncHandle();
417   TRACE("CreateDrawable... return True");
418   return True;
419}
420
421static int
422noopErrorHandler(Display * dpy, XErrorEvent * xerr)
423{
424   return 0;
425}
426
427Bool
428XF86DRIDestroyDrawable(Display * dpy, int screen, XID drawable)
429{
430   XExtDisplayInfo *info = find_display(dpy);
431   xXF86DRIDestroyDrawableReq *req;
432   int (*oldXErrorHandler) (Display *, XErrorEvent *);
433
434   TRACE("DestroyDrawable...");
435   XF86DRICheckExtension(dpy, info, False);
436
437   /* This is called from the DRI driver, which used call it like this
438    *
439    *   if (windowExists(drawable))
440    *     destroyDrawable(drawable);
441    *
442    * which is a textbook race condition - the window may disappear
443    * from the server between checking for its existence and
444    * destroying it.  Instead we change the semantics of
445    * __DRIinterfaceMethodsRec::destroyDrawable() to succeed even if
446    * the windows is gone, by wrapping the destroy call in an error
447    * handler. */
448
449   XSync(dpy, False);
450   oldXErrorHandler = XSetErrorHandler(noopErrorHandler);
451
452   LockDisplay(dpy);
453   GetReq(XF86DRIDestroyDrawable, req);
454   req->reqType = info->codes->major_opcode;
455   req->driReqType = X_XF86DRIDestroyDrawable;
456   req->screen = screen;
457   req->drawable = drawable;
458   UnlockDisplay(dpy);
459   SyncHandle();
460
461   XSetErrorHandler(oldXErrorHandler);
462
463   TRACE("DestroyDrawable... return True");
464   return True;
465}
466
467Bool
468XF86DRIGetDrawableInfo(Display * dpy, int screen, Drawable drawable,
469                       unsigned int *index, unsigned int *stamp,
470                       int *X, int *Y, int *W, int *H,
471                       int *numClipRects, drm_clip_rect_t ** pClipRects,
472                       int *backX, int *backY,
473                       int *numBackClipRects,
474                       drm_clip_rect_t ** pBackClipRects)
475{
476   XExtDisplayInfo *info = find_display(dpy);
477   xXF86DRIGetDrawableInfoReply rep;
478   xXF86DRIGetDrawableInfoReq *req;
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      UnlockDisplay(dpy);
493      SyncHandle();
494      TRACE("GetDrawableInfo... return False");
495      return False;
496   }
497   *index = rep.drawableTableIndex;
498   *stamp = rep.drawableTableStamp;
499   *X = (int) rep.drawableX;
500   *Y = (int) rep.drawableY;
501   *W = (int) rep.drawableWidth;
502   *H = (int) rep.drawableHeight;
503   *numClipRects = rep.numClipRects;
504   total_rects = *numClipRects;
505
506   *backX = rep.backX;
507   *backY = rep.backY;
508   *numBackClipRects = rep.numBackClipRects;
509   total_rects += *numBackClipRects;
510
511#if 0
512   /* Because of the fix in Xserver/GL/dri/xf86dri.c, this check breaks
513    * backwards compatibility (Because of the >> 2 shift) but the fix
514    * enables multi-threaded apps to work.
515    */
516   if (rep.length != ((((SIZEOF(xXF86DRIGetDrawableInfoReply) -
517                         SIZEOF(xGenericReply) +
518                         total_rects * sizeof(drm_clip_rect_t)) +
519                        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 = calloc(len, 1);
532      if (*pClipRects)
533         _XRead(dpy, (char *) *pClipRects, len);
534   }
535   else {
536      *pClipRects = NULL;
537   }
538
539   if (*numBackClipRects) {
540      int len = sizeof(drm_clip_rect_t) * (*numBackClipRects);
541
542      *pBackClipRects = calloc(len, 1);
543      if (*pBackClipRects)
544         _XRead(dpy, (char *) *pBackClipRects, len);
545   }
546   else {
547      *pBackClipRects = NULL;
548   }
549
550   UnlockDisplay(dpy);
551   SyncHandle();
552   TRACE("GetDrawableInfo... return True");
553   return True;
554}
555
556Bool
557XF86DRIGetDeviceInfo(Display * dpy, int screen, drm_handle_t * hFrameBuffer,
558                     int *fbOrigin, int *fbSize, int *fbStride,
559                     int *devPrivateSize, void **pDevPrivate)
560{
561   XExtDisplayInfo *info = find_display(dpy);
562   xXF86DRIGetDeviceInfoReply rep;
563   xXF86DRIGetDeviceInfoReq *req;
564
565   TRACE("GetDeviceInfo...");
566   XF86DRICheckExtension(dpy, info, False);
567
568   LockDisplay(dpy);
569   GetReq(XF86DRIGetDeviceInfo, req);
570   req->reqType = info->codes->major_opcode;
571   req->driReqType = X_XF86DRIGetDeviceInfo;
572   req->screen = screen;
573   if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) {
574      UnlockDisplay(dpy);
575      SyncHandle();
576      TRACE("GetDeviceInfo... return False");
577      return False;
578   }
579
580   *hFrameBuffer = rep.hFrameBufferLow;
581   if (sizeof(drm_handle_t) == 8) {
582      int shift = 32;           /* var to prevent warning on next line */
583      *hFrameBuffer |= ((drm_handle_t) rep.hFrameBufferHigh) << shift;
584   }
585
586   *fbOrigin = rep.framebufferOrigin;
587   *fbSize = rep.framebufferSize;
588   *fbStride = rep.framebufferStride;
589   *devPrivateSize = rep.devPrivateSize;
590
591   if (rep.length) {
592      if (!(*pDevPrivate = calloc(rep.devPrivateSize, 1))) {
593         _XEatData(dpy, ((rep.devPrivateSize + 3) & ~3));
594         UnlockDisplay(dpy);
595         SyncHandle();
596         TRACE("GetDeviceInfo... return False");
597         return False;
598      }
599      _XRead(dpy, (char *) *pDevPrivate, rep.devPrivateSize);
600   }
601   else {
602      *pDevPrivate = NULL;
603   }
604
605   UnlockDisplay(dpy);
606   SyncHandle();
607   TRACE("GetDeviceInfo... return True");
608   return True;
609}
610
611Bool
612XF86DRIOpenFullScreen(Display * dpy, int screen, Drawable drawable)
613{
614   /* This function and the underlying X protocol are deprecated.
615    */
616   (void) dpy;
617   (void) screen;
618   (void) drawable;
619   return False;
620}
621
622Bool
623XF86DRICloseFullScreen(Display * dpy, int screen, Drawable drawable)
624{
625   /* This function and the underlying X protocol are deprecated.
626    */
627   (void) dpy;
628   (void) screen;
629   (void) drawable;
630   return True;
631}
632
633#endif /* GLX_DIRECT_RENDERING */
634