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