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