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