dri_glx.c revision 7b7845a076c933e096ac511b4184141ba194449a
1/**************************************************************************
2
3Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
4All Rights Reserved.
5
6Permission is hereby granted, free of charge, to any person obtaining a
7copy of this software and associated documentation files (the
8"Software"), to deal in the Software without restriction, including
9without limitation the rights to use, copy, modify, merge, publish,
10distribute, sub license, and/or sell copies of the Software, and to
11permit persons to whom the Software is furnished to do so, subject to
12the following conditions:
13
14The above copyright notice and this permission notice (including the
15next paragraph) shall be included in all copies or substantial portions
16of the Software.
17
18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
22ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
26**************************************************************************/
27
28/*
29 * Authors:
30 *   Kevin E. Martin <kevin@precisioninsight.com>
31 *   Brian Paul <brian@precisioninsight.com>
32 *
33 */
34
35#if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL)
36
37#include <X11/Xlib.h>
38#include <X11/extensions/Xfixes.h>
39#include <X11/extensions/Xdamage.h>
40#include "glxclient.h"
41#include "xf86dri.h"
42#include "dri2.h"
43#include "sarea.h"
44#include <dlfcn.h>
45#include <sys/types.h>
46#include <sys/mman.h>
47#include "xf86drm.h"
48#include "dri_common.h"
49
50struct dri_display
51{
52   __GLXDRIdisplay base;
53
54   /*
55    ** XFree86-DRI version information
56    */
57   int driMajor;
58   int driMinor;
59   int driPatch;
60};
61
62struct dri_screen
63{
64   __GLXscreenConfigs base;
65
66   __DRIscreen *driScreen;
67   __GLXDRIscreen vtable;
68   const __DRIlegacyExtension *legacy;
69   const __DRIcoreExtension *core;
70   const __DRIswapControlExtension *swapControl;
71   const __DRImediaStreamCounterExtension *msc;
72   const __DRIconfig **driver_configs;
73   const __DRIcopySubBufferExtension *driCopySubBuffer;
74
75   void *driver;
76   int fd;
77};
78
79struct dri_context
80{
81   __GLXcontext base;
82   __GLXDRIcontext dri_vtable;
83   __DRIcontext *driContext;
84   XID hwContextID;
85   __GLXscreenConfigs *psc;
86};
87
88struct dri_drawable
89{
90   __GLXDRIdrawable base;
91
92   __DRIdrawable *driDrawable;
93};
94
95static const struct glx_context_vtable dri_context_vtable = {
96   NULL,
97   NULL,
98   DRI_glXUseXFont,
99   NULL,
100   NULL,
101};
102
103/*
104 * Given a display pointer and screen number, determine the name of
105 * the DRI driver for the screen. (I.e. "r128", "tdfx", etc).
106 * Return True for success, False for failure.
107 */
108static Bool
109driGetDriverName(Display * dpy, int scrNum, char **driverName)
110{
111   int directCapable;
112   Bool b;
113   int event, error;
114   int driverMajor, driverMinor, driverPatch;
115
116   *driverName = NULL;
117
118   if (XF86DRIQueryExtension(dpy, &event, &error)) {    /* DRI1 */
119      if (!XF86DRIQueryDirectRenderingCapable(dpy, scrNum, &directCapable)) {
120         ErrorMessageF("XF86DRIQueryDirectRenderingCapable failed\n");
121         return False;
122      }
123      if (!directCapable) {
124         ErrorMessageF("XF86DRIQueryDirectRenderingCapable returned false\n");
125         return False;
126      }
127
128      b = XF86DRIGetClientDriverName(dpy, scrNum, &driverMajor, &driverMinor,
129                                     &driverPatch, driverName);
130      if (!b) {
131         ErrorMessageF("Cannot determine driver name for screen %d\n",
132                       scrNum);
133         return False;
134      }
135
136      InfoMessageF("XF86DRIGetClientDriverName: %d.%d.%d %s (screen %d)\n",
137                   driverMajor, driverMinor, driverPatch, *driverName,
138                   scrNum);
139
140      return True;
141   }
142   else if (DRI2QueryExtension(dpy, &event, &error)) {  /* DRI2 */
143      char *dev;
144      Bool ret = DRI2Connect(dpy, RootWindow(dpy, scrNum), driverName, &dev);
145
146      if (ret)
147         Xfree(dev);
148
149      return ret;
150   }
151
152   return False;
153}
154
155/*
156 * Exported function for querying the DRI driver for a given screen.
157 *
158 * The returned char pointer points to a static array that will be
159 * overwritten by subsequent calls.
160 */
161PUBLIC const char *
162glXGetScreenDriver(Display * dpy, int scrNum)
163{
164   static char ret[32];
165   char *driverName;
166   if (driGetDriverName(dpy, scrNum, &driverName)) {
167      int len;
168      if (!driverName)
169         return NULL;
170      len = strlen(driverName);
171      if (len >= 31)
172         return NULL;
173      memcpy(ret, driverName, len + 1);
174      Xfree(driverName);
175      return ret;
176   }
177   return NULL;
178}
179
180/*
181 * Exported function for obtaining a driver's option list (UTF-8 encoded XML).
182 *
183 * The returned char pointer points directly into the driver. Therefore
184 * it should be treated as a constant.
185 *
186 * If the driver was not found or does not support configuration NULL is
187 * returned.
188 *
189 * Note: The driver remains opened after this function returns.
190 */
191PUBLIC const char *
192glXGetDriverConfig(const char *driverName)
193{
194   void *handle = driOpenDriver(driverName);
195   if (handle)
196      return dlsym(handle, "__driConfigOptions");
197   else
198      return NULL;
199}
200
201#ifdef XDAMAGE_1_1_INTERFACE
202
203static GLboolean
204has_damage_post(Display * dpy)
205{
206   static GLboolean inited = GL_FALSE;
207   static GLboolean has_damage;
208
209   if (!inited) {
210      int major, minor;
211
212      if (XDamageQueryVersion(dpy, &major, &minor) &&
213          major == 1 && minor >= 1) {
214         has_damage = GL_TRUE;
215      }
216      else {
217         has_damage = GL_FALSE;
218      }
219      inited = GL_TRUE;
220   }
221
222   return has_damage;
223}
224
225static void
226__glXReportDamage(__DRIdrawable * driDraw,
227                  int x, int y,
228                  drm_clip_rect_t * rects, int num_rects,
229                  GLboolean front_buffer, void *loaderPrivate)
230{
231   XRectangle *xrects;
232   XserverRegion region;
233   int i;
234   int x_off, y_off;
235   __GLXDRIdrawable *glxDraw = loaderPrivate;
236   __GLXscreenConfigs *psc = glxDraw->psc;
237   Display *dpy = psc->dpy;
238   Drawable drawable;
239
240   if (!has_damage_post(dpy))
241      return;
242
243   if (front_buffer) {
244      x_off = x;
245      y_off = y;
246      drawable = RootWindow(dpy, psc->scr);
247   }
248   else {
249      x_off = 0;
250      y_off = 0;
251      drawable = glxDraw->xDrawable;
252   }
253
254   xrects = malloc(sizeof(XRectangle) * num_rects);
255   if (xrects == NULL)
256      return;
257
258   for (i = 0; i < num_rects; i++) {
259      xrects[i].x = rects[i].x1 + x_off;
260      xrects[i].y = rects[i].y1 + y_off;
261      xrects[i].width = rects[i].x2 - rects[i].x1;
262      xrects[i].height = rects[i].y2 - rects[i].y1;
263   }
264   region = XFixesCreateRegion(dpy, xrects, num_rects);
265   free(xrects);
266   XDamageAdd(dpy, drawable, region);
267   XFixesDestroyRegion(dpy, region);
268}
269
270static const __DRIdamageExtension damageExtension = {
271   {__DRI_DAMAGE, __DRI_DAMAGE_VERSION},
272   __glXReportDamage,
273};
274
275#endif
276
277static GLboolean
278__glXDRIGetDrawableInfo(__DRIdrawable * drawable,
279                        unsigned int *index, unsigned int *stamp,
280                        int *X, int *Y, int *W, int *H,
281                        int *numClipRects, drm_clip_rect_t ** pClipRects,
282                        int *backX, int *backY,
283                        int *numBackClipRects,
284                        drm_clip_rect_t ** pBackClipRects,
285                        void *loaderPrivate)
286{
287   __GLXDRIdrawable *glxDraw = loaderPrivate;
288   __GLXscreenConfigs *psc = glxDraw->psc;
289   Display *dpy = psc->dpy;
290
291   return XF86DRIGetDrawableInfo(dpy, psc->scr, glxDraw->drawable,
292                                 index, stamp, X, Y, W, H,
293                                 numClipRects, pClipRects,
294                                 backX, backY,
295                                 numBackClipRects, pBackClipRects);
296}
297
298static const __DRIgetDrawableInfoExtension getDrawableInfoExtension = {
299   {__DRI_GET_DRAWABLE_INFO, __DRI_GET_DRAWABLE_INFO_VERSION},
300   __glXDRIGetDrawableInfo
301};
302
303static const __DRIextension *loader_extensions[] = {
304   &systemTimeExtension.base,
305   &getDrawableInfoExtension.base,
306#ifdef XDAMAGE_1_1_INTERFACE
307   &damageExtension.base,
308#endif
309   NULL
310};
311
312/**
313 * Perform the required libGL-side initialization and call the client-side
314 * driver's \c __driCreateNewScreen function.
315 *
316 * \param dpy    Display pointer.
317 * \param scrn   Screen number on the display.
318 * \param psc    DRI screen information.
319 * \param driDpy DRI display information.
320 * \param createNewScreen  Pointer to the client-side driver's
321 *               \c __driCreateNewScreen function.
322 * \returns A pointer to the \c __DRIscreen structure returned by
323 *          the client-side driver on success, or \c NULL on failure.
324 */
325static void *
326CallCreateNewScreen(Display *dpy, int scrn, struct dri_screen *psc,
327                    struct dri_display * driDpy)
328{
329   void *psp = NULL;
330   drm_handle_t hSAREA;
331   drmAddress pSAREA = MAP_FAILED;
332   char *BusID;
333   __DRIversion ddx_version;
334   __DRIversion dri_version;
335   __DRIversion drm_version;
336   __DRIframebuffer framebuffer;
337   int fd = -1;
338   int status;
339
340   drm_magic_t magic;
341   drmVersionPtr version;
342   int newlyopened;
343   char *driverName;
344   drm_handle_t hFB;
345   int junk;
346   const __DRIconfig **driver_configs;
347   __GLcontextModes *visual;
348
349   /* DRI protocol version. */
350   dri_version.major = driDpy->driMajor;
351   dri_version.minor = driDpy->driMinor;
352   dri_version.patch = driDpy->driPatch;
353
354   framebuffer.base = MAP_FAILED;
355   framebuffer.dev_priv = NULL;
356   framebuffer.size = 0;
357
358   if (!XF86DRIOpenConnection(dpy, scrn, &hSAREA, &BusID)) {
359      ErrorMessageF("XF86DRIOpenConnection failed\n");
360      goto handle_error;
361   }
362
363   fd = drmOpenOnce(NULL, BusID, &newlyopened);
364
365   Xfree(BusID);                /* No longer needed */
366
367   if (fd < 0) {
368      ErrorMessageF("drmOpenOnce failed (%s)\n", strerror(-fd));
369      goto handle_error;
370   }
371
372   if (drmGetMagic(fd, &magic)) {
373      ErrorMessageF("drmGetMagic failed\n");
374      goto handle_error;
375   }
376
377   version = drmGetVersion(fd);
378   if (version) {
379      drm_version.major = version->version_major;
380      drm_version.minor = version->version_minor;
381      drm_version.patch = version->version_patchlevel;
382      drmFreeVersion(version);
383   }
384   else {
385      drm_version.major = -1;
386      drm_version.minor = -1;
387      drm_version.patch = -1;
388   }
389
390   if (newlyopened && !XF86DRIAuthConnection(dpy, scrn, magic)) {
391      ErrorMessageF("XF86DRIAuthConnection failed\n");
392      goto handle_error;
393   }
394
395   /* Get device name (like "tdfx") and the ddx version numbers.
396    * We'll check the version in each DRI driver's "createNewScreen"
397    * function. */
398   if (!XF86DRIGetClientDriverName(dpy, scrn,
399                                   &ddx_version.major,
400                                   &ddx_version.minor,
401                                   &ddx_version.patch, &driverName)) {
402      ErrorMessageF("XF86DRIGetClientDriverName failed\n");
403      goto handle_error;
404   }
405
406   Xfree(driverName);           /* No longer needed. */
407
408   /*
409    * Get device-specific info.  pDevPriv will point to a struct
410    * (such as DRIRADEONRec in xfree86/driver/ati/radeon_dri.h) that
411    * has information about the screen size, depth, pitch, ancilliary
412    * buffers, DRM mmap handles, etc.
413    */
414   if (!XF86DRIGetDeviceInfo(dpy, scrn, &hFB, &junk,
415                             &framebuffer.size, &framebuffer.stride,
416                             &framebuffer.dev_priv_size,
417                             &framebuffer.dev_priv)) {
418      ErrorMessageF("XF86DRIGetDeviceInfo failed");
419      goto handle_error;
420   }
421
422   framebuffer.width = DisplayWidth(dpy, scrn);
423   framebuffer.height = DisplayHeight(dpy, scrn);
424
425   /* Map the framebuffer region. */
426   status = drmMap(fd, hFB, framebuffer.size,
427                   (drmAddressPtr) & framebuffer.base);
428   if (status != 0) {
429      ErrorMessageF("drmMap of framebuffer failed (%s)", strerror(-status));
430      goto handle_error;
431   }
432
433   /* Map the SAREA region.  Further mmap regions may be setup in
434    * each DRI driver's "createNewScreen" function.
435    */
436   status = drmMap(fd, hSAREA, SAREA_MAX, &pSAREA);
437   if (status != 0) {
438      ErrorMessageF("drmMap of SAREA failed (%s)", strerror(-status));
439      goto handle_error;
440   }
441
442   psp = (*psc->legacy->createNewScreen) (scrn,
443                                          &ddx_version,
444                                          &dri_version,
445                                          &drm_version,
446                                          &framebuffer,
447                                          pSAREA,
448                                          fd,
449                                          loader_extensions,
450                                          &driver_configs, psc);
451
452   if (psp == NULL) {
453      ErrorMessageF("Calling driver entry point failed");
454      goto handle_error;
455   }
456
457   psc->base.configs =
458      driConvertConfigs(psc->core, psc->base.configs, driver_configs);
459   psc->base.visuals =
460      driConvertConfigs(psc->core, psc->base.visuals, driver_configs);
461
462   psc->driver_configs = driver_configs;
463
464   /* Visuals with depth != screen depth are subject to automatic compositing
465    * in the X server, so DRI1 can't render to them properly. Mark them as
466    * non-conformant to prevent apps from picking them up accidentally.
467    */
468   for (visual = psc->base.visuals; visual; visual = visual->next) {
469      XVisualInfo template;
470      XVisualInfo *visuals;
471      int num_visuals;
472      long mask;
473
474      template.visualid = visual->visualID;
475      mask = VisualIDMask;
476      visuals = XGetVisualInfo(dpy, mask, &template, &num_visuals);
477
478      if (visuals) {
479         if (num_visuals > 0 && visuals->depth != DefaultDepth(dpy, scrn))
480            visual->visualRating = GLX_NON_CONFORMANT_CONFIG;
481
482         XFree(visuals);
483      }
484   }
485
486   return psp;
487
488 handle_error:
489   if (pSAREA != MAP_FAILED)
490      drmUnmap(pSAREA, SAREA_MAX);
491
492   if (framebuffer.base != MAP_FAILED)
493      drmUnmap((drmAddress) framebuffer.base, framebuffer.size);
494
495   if (framebuffer.dev_priv != NULL)
496      Xfree(framebuffer.dev_priv);
497
498   if (fd >= 0)
499      drmCloseOnce(fd);
500
501   XF86DRICloseConnection(dpy, scrn);
502
503   ErrorMessageF("reverting to software direct rendering\n");
504
505   return NULL;
506}
507
508static void
509driDestroyContext(__GLXcontext * context)
510{
511   struct dri_context *pcp = (struct dri_context *) context;
512   struct dri_screen *psc = (struct dri_screen *) context->psc;
513
514   (*psc->core->destroyContext) (pcp->driContext);
515
516   XF86DRIDestroyContext(psc->base.dpy, psc->base.scr, pcp->hwContextID);
517   Xfree(pcp);
518}
519
520static Bool
521driBindContext(__GLXcontext *context,
522	       __GLXDRIdrawable *draw, __GLXDRIdrawable *read)
523{
524   struct dri_context *pcp = (struct dri_context *) context;
525   struct dri_screen *psc = (struct dri_screen *) pcp->psc;
526   struct dri_drawable *pdr = (struct dri_drawable *) draw;
527   struct dri_drawable *prd = (struct dri_drawable *) read;
528
529   return (*psc->core->bindContext) (pcp->driContext,
530				     pdr->driDrawable, prd->driDrawable);
531}
532
533static void
534driUnbindContext(__GLXcontext * context)
535{
536   struct dri_context *pcp = (struct dri_context *) context;
537   struct dri_screen *psc = (struct dri_screen *) pcp->psc;
538
539   (*psc->core->unbindContext) (pcp->driContext);
540}
541
542static __GLXcontext *
543driCreateContext(__GLXscreenConfigs *base,
544                 const __GLcontextModes * mode,
545                 GLXContext shareList, int renderType)
546{
547   struct dri_context *pcp, *pcp_shared;
548   struct dri_screen *psc = (struct dri_screen *) base;
549   drm_context_t hwContext;
550   __DRIcontext *shared = NULL;
551   __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) mode;
552
553   if (!psc->base.driScreen)
554      return NULL;
555
556   if (shareList) {
557      pcp_shared = (struct dri_context *) shareList->driContext;
558      shared = pcp_shared->driContext;
559   }
560
561   pcp = Xmalloc(sizeof *pcp);
562   if (pcp == NULL)
563      return NULL;
564
565   memset(pcp, 0, sizeof *pcp);
566   if (!glx_context_init(&pcp->base, &psc->base, mode)) {
567      Xfree(pcp);
568      return NULL;
569   }
570
571   if (!XF86DRICreateContextWithConfig(psc->base.dpy, psc->base.scr,
572                                       mode->visualID,
573                                       &pcp->hwContextID, &hwContext)) {
574      Xfree(pcp);
575      return NULL;
576   }
577
578   pcp->driContext =
579      (*psc->legacy->createNewContext) (psc->driScreen,
580                                        config->driConfig,
581                                        renderType, shared, hwContext, pcp);
582   if (pcp->driContext == NULL) {
583      XF86DRIDestroyContext(psc->base.dpy, psc->base.scr, pcp->hwContextID);
584      Xfree(pcp);
585      return NULL;
586   }
587
588   pcp->base.vtable = &dri_context_vtable;
589   pcp->base.driContext = &pcp->dri_vtable;
590   pcp->dri_vtable.destroyContext = driDestroyContext;
591   pcp->dri_vtable.bindContext = driBindContext;
592   pcp->dri_vtable.unbindContext = driUnbindContext;
593
594   return &pcp->base;
595}
596
597static void
598driDestroyDrawable(__GLXDRIdrawable * pdraw)
599{
600   struct dri_screen *psc = (struct dri_screen *) pdraw->psc;
601   struct dri_drawable *pdp = (struct dri_drawable *) pdraw;
602
603   (*psc->core->destroyDrawable) (pdp->driDrawable);
604   XF86DRIDestroyDrawable(psc->base.dpy, psc->base.scr, pdraw->drawable);
605   Xfree(pdraw);
606}
607
608static __GLXDRIdrawable *
609driCreateDrawable(__GLXscreenConfigs *base,
610                  XID xDrawable,
611                  GLXDrawable drawable, const __GLcontextModes * modes)
612{
613   drm_drawable_t hwDrawable;
614   void *empty_attribute_list = NULL;
615   __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) modes;
616   struct dri_screen *psc = (struct dri_screen *) base;
617   struct dri_drawable *pdp;
618
619   /* Old dri can't handle GLX 1.3+ drawable constructors. */
620   if (xDrawable != drawable)
621      return NULL;
622
623   pdp = Xmalloc(sizeof *pdp);
624   if (!pdp)
625      return NULL;
626
627   pdp->base.drawable = drawable;
628   pdp->base.psc = &psc->base;
629
630   if (!XF86DRICreateDrawable(psc->base.dpy, psc->base.scr,
631			      drawable, &hwDrawable)) {
632      Xfree(pdp);
633      return NULL;
634   }
635
636   /* Create a new drawable */
637   pdp->driDrawable =
638      (*psc->legacy->createNewDrawable) (psc->driScreen,
639                                         config->driConfig,
640                                         hwDrawable,
641                                         GLX_WINDOW_BIT,
642                                         empty_attribute_list, pdp);
643
644   if (!pdp->driDrawable) {
645      XF86DRIDestroyDrawable(psc->base.dpy, psc->base.scr, drawable);
646      Xfree(pdp);
647      return NULL;
648   }
649
650   pdp->base.destroyDrawable = driDestroyDrawable;
651
652   return &pdp->base;
653}
654
655static int64_t
656driSwapBuffers(__GLXDRIdrawable * pdraw, int64_t unused1, int64_t unused2,
657	       int64_t unused3)
658{
659   struct dri_screen *psc = (struct dri_screen *) pdraw->psc;
660   struct dri_drawable *pdp = (struct dri_drawable *) pdraw;
661
662   (*psc->core->swapBuffers) (pdp->driDrawable);
663   return 0;
664}
665
666static void
667driCopySubBuffer(__GLXDRIdrawable * pdraw,
668                 int x, int y, int width, int height)
669{
670   struct dri_drawable *pdp = (struct dri_drawable *) pdraw;
671   struct dri_screen *psc = (struct dri_screen *) pdp->base.psc;
672
673   (*psc->driCopySubBuffer->copySubBuffer) (pdp->driDrawable,
674					    x, y, width, height);
675}
676
677static void
678driDestroyScreen(__GLXscreenConfigs *base)
679{
680   struct dri_screen *psc = (struct dri_screen *) base;
681
682   /* Free the direct rendering per screen data */
683   if (psc->driScreen)
684      (*psc->core->destroyScreen) (psc->driScreen);
685   driDestroyConfigs(psc->driver_configs);
686   psc->driScreen = NULL;
687   if (psc->driver)
688      dlclose(psc->driver);
689}
690
691#ifdef __DRI_SWAP_BUFFER_COUNTER
692
693static int
694driDrawableGetMSC(__GLXscreenConfigs *base, __GLXDRIdrawable *pdraw,
695		   int64_t *ust, int64_t *msc, int64_t *sbc)
696{
697   struct dri_screen *psc = (struct dri_screen *) base;
698   struct dri_drawable *pdp = (struct dri_drawable *) pdraw;
699
700   if (pdp && psc->sbc && psc->msc)
701      return ( (*psc->msc->getMSC)(psc->driScreen, msc) == 0 &&
702	       (*psc->sbc->getSBC)(pdp->driDrawable, sbc) == 0 &&
703	       __glXGetUST(ust) == 0 );
704}
705
706static int
707driWaitForMSC(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor,
708	       int64_t remainder, int64_t *ust, int64_t *msc, int64_t *sbc)
709{
710   struct dri_screen *psc = (struct dri_screen *) pdraw->psc;
711   struct dri_drawable *pdp = (struct dri_drawable *) pdraw;
712
713   if (pdp != NULL && psc->msc != NULL) {
714      ret = (*psc->msc->waitForMSC) (pdp->driDrawable, target_msc,
715				     divisor, remainder, msc, sbc);
716
717      /* __glXGetUST returns zero on success and non-zero on failure.
718       * This function returns True on success and False on failure.
719       */
720      return ret == 0 && __glXGetUST(ust) == 0;
721   }
722}
723
724static int
725driWaitForSBC(__GLXDRIdrawable *pdraw, int64_t target_sbc, int64_t *ust,
726	       int64_t *msc, int64_t *sbc)
727{
728   struct dri_drawable *pdp = (struct dri_drawable *) pdraw;
729
730   if (pdp != NULL && psc->sbc != NULL) {
731      ret =
732         (*psc->sbc->waitForSBC) (pdp->driDrawable, target_sbc, msc, sbc);
733
734      /* __glXGetUST returns zero on success and non-zero on failure.
735       * This function returns True on success and False on failure.
736       */
737      return ((ret == 0) && (__glXGetUST(ust) == 0));
738   }
739
740   return DRI2WaitSBC(pdp->base.psc->dpy,
741		      pdp->base.xDrawable, target_sbc, ust, msc, sbc);
742}
743
744#endif
745
746static int
747driSetSwapInterval(__GLXDRIdrawable *pdraw, int interval)
748{
749   GLXContext gc = __glXGetCurrentContext();
750   struct dri_drawable *pdp = (struct dri_drawable *) pdraw;
751   struct dri_screen *psc;
752
753   if (gc->driContext) {
754      psc = (struct dri_screen *) pdraw->psc;
755
756      if (psc->swapControl != NULL && pdraw != NULL) {
757	 psc->swapControl->setSwapInterval(pdp->driDrawable, interval);
758	 return 0;
759      }
760   }
761
762   return GLX_BAD_CONTEXT;
763}
764
765static int
766driGetSwapInterval(__GLXDRIdrawable *pdraw)
767{
768   GLXContext gc = __glXGetCurrentContext();
769   struct dri_drawable *pdp = (struct dri_drawable *) pdraw;
770   struct dri_screen *psc;
771
772   if (gc != NULL && gc->driContext) {
773      psc = (struct dri_screen *) pdraw->psc;
774
775      if (psc->swapControl != NULL && pdraw != NULL) {
776	 return psc->swapControl->getSwapInterval(pdp->driDrawable);
777      }
778   }
779
780   return 0;
781}
782
783/* Bind DRI1 specific extensions */
784static void
785driBindExtensions(struct dri_screen *psc, const __DRIextension **extensions)
786{
787   int i;
788
789   for (i = 0; extensions[i]; i++) {
790      /* No DRI2 support for swap_control at the moment, since SwapBuffers
791       * is done by the X server */
792      if (strcmp(extensions[i]->name, __DRI_SWAP_CONTROL) == 0) {
793	 psc->swapControl = (__DRIswapControlExtension *) extensions[i];
794	 __glXEnableDirectExtension(&psc->base, "GLX_SGI_swap_control");
795	 __glXEnableDirectExtension(&psc->base, "GLX_MESA_swap_control");
796      }
797
798      if (strcmp(extensions[i]->name, __DRI_MEDIA_STREAM_COUNTER) == 0) {
799         psc->msc = (__DRImediaStreamCounterExtension *) extensions[i];
800         __glXEnableDirectExtension(&psc->base, "GLX_SGI_video_sync");
801      }
802
803      if (strcmp(extensions[i]->name, __DRI_COPY_SUB_BUFFER) == 0) {
804	 psc->driCopySubBuffer = (__DRIcopySubBufferExtension *) extensions[i];
805	 __glXEnableDirectExtension(&psc->base, "GLX_MESA_copy_sub_buffer");
806      }
807
808      if (strcmp(extensions[i]->name, __DRI_READ_DRAWABLE) == 0) {
809	 __glXEnableDirectExtension(&psc->base, "GLX_SGI_make_current_read");
810      }
811      /* Ignore unknown extensions */
812   }
813}
814
815static __GLXscreenConfigs *
816driCreateScreen(int screen, __GLXdisplayPrivate *priv)
817{
818   struct dri_display *pdp;
819   __GLXDRIscreen *psp;
820   const __DRIextension **extensions;
821   struct dri_screen *psc;
822   char *driverName;
823   int i;
824
825   psc = Xcalloc(1, sizeof *psc);
826   if (psc == NULL)
827      return NULL;
828
829   memset(psc, 0, sizeof *psc);
830   if (!glx_screen_init(&psc->base, screen, priv))
831       return NULL;
832
833   if (!driGetDriverName(priv->dpy, screen, &driverName)) {
834      Xfree(psc);
835      return NULL;
836   }
837
838   psc->driver = driOpenDriver(driverName);
839   Xfree(driverName);
840   if (psc->driver == NULL) {
841      Xfree(psc);
842      return NULL;
843   }
844
845   extensions = dlsym(psc->driver, __DRI_DRIVER_EXTENSIONS);
846   if (extensions == NULL) {
847      ErrorMessageF("driver exports no extensions (%s)\n", dlerror());
848      Xfree(psc);
849      return NULL;
850   }
851
852   for (i = 0; extensions[i]; i++) {
853      if (strcmp(extensions[i]->name, __DRI_CORE) == 0)
854	 psc->core = (__DRIcoreExtension *) extensions[i];
855      if (strcmp(extensions[i]->name, __DRI_LEGACY) == 0)
856	 psc->legacy = (__DRIlegacyExtension *) extensions[i];
857   }
858
859   if (psc->core == NULL || psc->legacy == NULL) {
860      Xfree(psc);
861      return NULL;
862   }
863
864   pdp = (struct dri_display *) priv->driDisplay;
865   psc->driScreen =
866      CallCreateNewScreen(psc->base.dpy, screen, psc, pdp);
867   if (psc->driScreen == NULL) {
868      dlclose(psc->driver);
869      Xfree(psc);
870      return NULL;
871   }
872
873   extensions = psc->core->getExtensions(psc->driScreen);
874   driBindExtensions(psc, extensions);
875
876   psp = &psc->vtable;
877   psc->base.driScreen = psp;
878   if (psc->driCopySubBuffer)
879      psp->copySubBuffer = driCopySubBuffer;
880
881   psp->destroyScreen = driDestroyScreen;
882   psp->createContext = driCreateContext;
883   psp->createDrawable = driCreateDrawable;
884   psp->swapBuffers = driSwapBuffers;
885
886#ifdef __DRI_SWAP_BUFFER_COUNTER
887   psp->getDrawableMSC = driDrawableGetMSC;
888   psp->waitForMSC = driWaitForMSC;
889   psp->waitForSBC = driWaitForSBC;
890#endif
891
892   psp->setSwapInterval = driSetSwapInterval;
893   psp->getSwapInterval = driGetSwapInterval;
894
895   return &psc->base;
896}
897
898/* Called from __glXFreeDisplayPrivate.
899 */
900static void
901driDestroyDisplay(__GLXDRIdisplay * dpy)
902{
903   Xfree(dpy);
904}
905
906/*
907 * Allocate, initialize and return a __DRIdisplayPrivate object.
908 * This is called from __glXInitialize() when we are given a new
909 * display pointer.
910 */
911_X_HIDDEN __GLXDRIdisplay *
912driCreateDisplay(Display * dpy)
913{
914   struct dri_display *pdpyp;
915   int eventBase, errorBase;
916   int major, minor, patch;
917
918   if (!XF86DRIQueryExtension(dpy, &eventBase, &errorBase)) {
919      return NULL;
920   }
921
922   if (!XF86DRIQueryVersion(dpy, &major, &minor, &patch)) {
923      return NULL;
924   }
925
926   pdpyp = Xmalloc(sizeof *pdpyp);
927   if (!pdpyp) {
928      return NULL;
929   }
930
931   pdpyp->driMajor = major;
932   pdpyp->driMinor = minor;
933   pdpyp->driPatch = patch;
934
935   pdpyp->base.destroyDisplay = driDestroyDisplay;
936   pdpyp->base.createScreen = driCreateScreen;
937
938   return &pdpyp->base;
939}
940
941#endif /* GLX_DIRECT_RENDERING */
942