dri_glx.c revision 6393a33944ec9983426cecd5f6c9f05ac089e1ae
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 *
553dri_create_context(__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   memset(pdp, 0, sizeof *pdp);
637   pdp->base.drawable = drawable;
638   pdp->base.psc = &psc->base;
639
640   if (!XF86DRICreateDrawable(psc->base.dpy, psc->base.scr,
641			      drawable, &hwDrawable)) {
642      Xfree(pdp);
643      return NULL;
644   }
645
646   /* Create a new drawable */
647   pdp->driDrawable =
648      (*psc->legacy->createNewDrawable) (psc->driScreen,
649                                         config->driConfig,
650                                         hwDrawable,
651                                         GLX_WINDOW_BIT,
652                                         empty_attribute_list, pdp);
653
654   if (!pdp->driDrawable) {
655      XF86DRIDestroyDrawable(psc->base.dpy, psc->base.scr, drawable);
656      Xfree(pdp);
657      return NULL;
658   }
659
660   pdp->base.destroyDrawable = driDestroyDrawable;
661
662   return &pdp->base;
663}
664
665static int64_t
666driSwapBuffers(__GLXDRIdrawable * pdraw, int64_t unused1, int64_t unused2,
667	       int64_t unused3)
668{
669   struct dri_screen *psc = (struct dri_screen *) pdraw->psc;
670   struct dri_drawable *pdp = (struct dri_drawable *) pdraw;
671
672   (*psc->core->swapBuffers) (pdp->driDrawable);
673   return 0;
674}
675
676static void
677driCopySubBuffer(__GLXDRIdrawable * pdraw,
678                 int x, int y, int width, int height)
679{
680   struct dri_drawable *pdp = (struct dri_drawable *) pdraw;
681   struct dri_screen *psc = (struct dri_screen *) pdp->base.psc;
682
683   (*psc->driCopySubBuffer->copySubBuffer) (pdp->driDrawable,
684					    x, y, width, height);
685}
686
687static void
688driDestroyScreen(__GLXscreenConfigs *base)
689{
690   struct dri_screen *psc = (struct dri_screen *) base;
691
692   /* Free the direct rendering per screen data */
693   if (psc->driScreen)
694      (*psc->core->destroyScreen) (psc->driScreen);
695   driDestroyConfigs(psc->driver_configs);
696   psc->driScreen = NULL;
697   if (psc->driver)
698      dlclose(psc->driver);
699}
700
701#ifdef __DRI_SWAP_BUFFER_COUNTER
702
703static int
704driDrawableGetMSC(__GLXscreenConfigs *base, __GLXDRIdrawable *pdraw,
705		   int64_t *ust, int64_t *msc, int64_t *sbc)
706{
707   struct dri_screen *psc = (struct dri_screen *) base;
708   struct dri_drawable *pdp = (struct dri_drawable *) pdraw;
709
710   if (pdp && psc->sbc && psc->msc)
711      return ( (*psc->msc->getMSC)(psc->driScreen, msc) == 0 &&
712	       (*psc->sbc->getSBC)(pdp->driDrawable, sbc) == 0 &&
713	       __glXGetUST(ust) == 0 );
714}
715
716static int
717driWaitForMSC(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor,
718	       int64_t remainder, int64_t *ust, int64_t *msc, int64_t *sbc)
719{
720   struct dri_screen *psc = (struct dri_screen *) pdraw->psc;
721   struct dri_drawable *pdp = (struct dri_drawable *) pdraw;
722
723   if (pdp != NULL && psc->msc != NULL) {
724      ret = (*psc->msc->waitForMSC) (pdp->driDrawable, target_msc,
725				     divisor, remainder, msc, sbc);
726
727      /* __glXGetUST returns zero on success and non-zero on failure.
728       * This function returns True on success and False on failure.
729       */
730      return ret == 0 && __glXGetUST(ust) == 0;
731   }
732}
733
734static int
735driWaitForSBC(__GLXDRIdrawable *pdraw, int64_t target_sbc, int64_t *ust,
736	       int64_t *msc, int64_t *sbc)
737{
738   struct dri_drawable *pdp = (struct dri_drawable *) pdraw;
739
740   if (pdp != NULL && psc->sbc != NULL) {
741      ret =
742         (*psc->sbc->waitForSBC) (pdp->driDrawable, target_sbc, msc, sbc);
743
744      /* __glXGetUST returns zero on success and non-zero on failure.
745       * This function returns True on success and False on failure.
746       */
747      return ((ret == 0) && (__glXGetUST(ust) == 0));
748   }
749
750   return DRI2WaitSBC(pdp->base.psc->dpy,
751		      pdp->base.xDrawable, target_sbc, ust, msc, sbc);
752}
753
754#endif
755
756static int
757driSetSwapInterval(__GLXDRIdrawable *pdraw, int interval)
758{
759   GLXContext gc = __glXGetCurrentContext();
760   struct dri_drawable *pdp = (struct dri_drawable *) pdraw;
761   struct dri_screen *psc;
762
763   if (gc->driContext) {
764      psc = (struct dri_screen *) pdraw->psc;
765
766      if (psc->swapControl != NULL && pdraw != NULL) {
767	 psc->swapControl->setSwapInterval(pdp->driDrawable, interval);
768	 return 0;
769      }
770   }
771
772   return GLX_BAD_CONTEXT;
773}
774
775static int
776driGetSwapInterval(__GLXDRIdrawable *pdraw)
777{
778   GLXContext gc = __glXGetCurrentContext();
779   struct dri_drawable *pdp = (struct dri_drawable *) pdraw;
780   struct dri_screen *psc;
781
782   if (gc != NULL && gc->driContext) {
783      psc = (struct dri_screen *) pdraw->psc;
784
785      if (psc->swapControl != NULL && pdraw != NULL) {
786	 return psc->swapControl->getSwapInterval(pdp->driDrawable);
787      }
788   }
789
790   return 0;
791}
792
793/* Bind DRI1 specific extensions */
794static void
795driBindExtensions(struct dri_screen *psc, const __DRIextension **extensions)
796{
797   int i;
798
799   for (i = 0; extensions[i]; i++) {
800      /* No DRI2 support for swap_control at the moment, since SwapBuffers
801       * is done by the X server */
802      if (strcmp(extensions[i]->name, __DRI_SWAP_CONTROL) == 0) {
803	 psc->swapControl = (__DRIswapControlExtension *) extensions[i];
804	 __glXEnableDirectExtension(&psc->base, "GLX_SGI_swap_control");
805	 __glXEnableDirectExtension(&psc->base, "GLX_MESA_swap_control");
806      }
807
808      if (strcmp(extensions[i]->name, __DRI_MEDIA_STREAM_COUNTER) == 0) {
809         psc->msc = (__DRImediaStreamCounterExtension *) extensions[i];
810         __glXEnableDirectExtension(&psc->base, "GLX_SGI_video_sync");
811      }
812
813      if (strcmp(extensions[i]->name, __DRI_COPY_SUB_BUFFER) == 0) {
814	 psc->driCopySubBuffer = (__DRIcopySubBufferExtension *) extensions[i];
815	 __glXEnableDirectExtension(&psc->base, "GLX_MESA_copy_sub_buffer");
816      }
817
818      if (strcmp(extensions[i]->name, __DRI_READ_DRAWABLE) == 0) {
819	 __glXEnableDirectExtension(&psc->base, "GLX_SGI_make_current_read");
820      }
821      /* Ignore unknown extensions */
822   }
823}
824
825static const struct glx_screen_vtable dri_screen_vtable = {
826   dri_create_context
827};
828
829static __GLXscreenConfigs *
830driCreateScreen(int screen, __GLXdisplayPrivate *priv)
831{
832   struct dri_display *pdp;
833   __GLXDRIscreen *psp;
834   const __DRIextension **extensions;
835   struct dri_screen *psc;
836   char *driverName;
837   int i;
838
839   psc = Xcalloc(1, sizeof *psc);
840   if (psc == NULL)
841      return NULL;
842
843   memset(psc, 0, sizeof *psc);
844   if (!glx_screen_init(&psc->base, screen, priv))
845       return NULL;
846
847   if (!driGetDriverName(priv->dpy, screen, &driverName)) {
848      Xfree(psc);
849      return NULL;
850   }
851
852   psc->driver = driOpenDriver(driverName);
853   Xfree(driverName);
854   if (psc->driver == NULL) {
855      Xfree(psc);
856      return NULL;
857   }
858
859   extensions = dlsym(psc->driver, __DRI_DRIVER_EXTENSIONS);
860   if (extensions == NULL) {
861      ErrorMessageF("driver exports no extensions (%s)\n", dlerror());
862      Xfree(psc);
863      return NULL;
864   }
865
866   for (i = 0; extensions[i]; i++) {
867      if (strcmp(extensions[i]->name, __DRI_CORE) == 0)
868	 psc->core = (__DRIcoreExtension *) extensions[i];
869      if (strcmp(extensions[i]->name, __DRI_LEGACY) == 0)
870	 psc->legacy = (__DRIlegacyExtension *) extensions[i];
871   }
872
873   if (psc->core == NULL || psc->legacy == NULL) {
874      Xfree(psc);
875      return NULL;
876   }
877
878   pdp = (struct dri_display *) priv->driDisplay;
879   psc->driScreen =
880      CallCreateNewScreen(psc->base.dpy, screen, psc, pdp);
881   if (psc->driScreen == NULL) {
882      dlclose(psc->driver);
883      Xfree(psc);
884      return NULL;
885   }
886
887   extensions = psc->core->getExtensions(psc->driScreen);
888   driBindExtensions(psc, extensions);
889
890   psc->base.vtable = &dri_screen_vtable;
891   psp = &psc->vtable;
892   psc->base.driScreen = psp;
893   if (psc->driCopySubBuffer)
894      psp->copySubBuffer = driCopySubBuffer;
895
896   psp->destroyScreen = driDestroyScreen;
897   psp->createDrawable = driCreateDrawable;
898   psp->swapBuffers = driSwapBuffers;
899
900#ifdef __DRI_SWAP_BUFFER_COUNTER
901   psp->getDrawableMSC = driDrawableGetMSC;
902   psp->waitForMSC = driWaitForMSC;
903   psp->waitForSBC = driWaitForSBC;
904#endif
905
906   psp->setSwapInterval = driSetSwapInterval;
907   psp->getSwapInterval = driGetSwapInterval;
908
909   return &psc->base;
910}
911
912/* Called from __glXFreeDisplayPrivate.
913 */
914static void
915driDestroyDisplay(__GLXDRIdisplay * dpy)
916{
917   Xfree(dpy);
918}
919
920/*
921 * Allocate, initialize and return a __DRIdisplayPrivate object.
922 * This is called from __glXInitialize() when we are given a new
923 * display pointer.
924 */
925_X_HIDDEN __GLXDRIdisplay *
926driCreateDisplay(Display * dpy)
927{
928   struct dri_display *pdpyp;
929   int eventBase, errorBase;
930   int major, minor, patch;
931
932   if (!XF86DRIQueryExtension(dpy, &eventBase, &errorBase)) {
933      return NULL;
934   }
935
936   if (!XF86DRIQueryVersion(dpy, &major, &minor, &patch)) {
937      return NULL;
938   }
939
940   pdpyp = Xmalloc(sizeof *pdpyp);
941   if (!pdpyp) {
942      return NULL;
943   }
944
945   pdpyp->driMajor = major;
946   pdpyp->driMinor = minor;
947   pdpyp->driPatch = patch;
948
949   pdpyp->base.destroyDisplay = driDestroyDisplay;
950   pdpyp->base.createScreen = driCreateScreen;
951
952   return &pdpyp->base;
953}
954
955#endif /* GLX_DIRECT_RENDERING */
956