dri_glx.c revision 559e4f8ebcb186b491d7d687ac43f22a62448fc1
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   driReleaseDrawables(&pcp->base);
507
508   if (context->xid)
509      glx_send_destroy_context(psc->base.dpy, context->xid);
510
511   if (context->extensions)
512      XFree((char *) context->extensions);
513
514   (*psc->core->destroyContext) (pcp->driContext);
515
516   XF86DRIDestroyContext(psc->base.dpy, psc->base.scr, pcp->hwContextID);
517   Xfree(pcp);
518}
519
520static int
521dri_bind_context(struct glx_context *context, struct glx_context *old,
522		 GLXDrawable draw, GLXDrawable read)
523{
524   struct dri_context *pcp = (struct dri_context *) context;
525   struct dri_screen *psc = (struct dri_screen *) pcp->base.psc;
526   struct dri_drawable *pdraw, *pread;
527
528   pdraw = (struct dri_drawable *) driFetchDrawable(context, draw);
529   pread = (struct dri_drawable *) driFetchDrawable(context, read);
530
531   driReleaseDrawables(&pcp->base);
532
533   if (pdraw == NULL || pread == NULL)
534      return GLXBadDrawable;
535
536   if ((*psc->core->bindContext) (pcp->driContext,
537				  pdraw->driDrawable, pread->driDrawable))
538      return Success;
539
540   return GLXBadContext;
541}
542
543static void
544dri_unbind_context(struct glx_context *context, struct glx_context *new)
545{
546   struct dri_context *pcp = (struct dri_context *) context;
547   struct dri_screen *psc = (struct dri_screen *) pcp->base.psc;
548
549   (*psc->core->unbindContext) (pcp->driContext);
550}
551
552static const struct glx_context_vtable dri_context_vtable = {
553   dri_destroy_context,
554   dri_bind_context,
555   dri_unbind_context,
556   NULL,
557   NULL,
558   DRI_glXUseXFont,
559   NULL,
560   NULL,
561   NULL, /* get_proc_address */
562};
563
564static struct glx_context *
565dri_create_context(struct glx_screen *base,
566		   struct glx_config *config_base,
567		   struct glx_context *shareList, int renderType)
568{
569   struct dri_context *pcp, *pcp_shared;
570   struct dri_screen *psc = (struct dri_screen *) base;
571   drm_context_t hwContext;
572   __DRIcontext *shared = NULL;
573   __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base;
574
575   if (!psc->base.driScreen)
576      return NULL;
577
578   if (shareList) {
579      pcp_shared = (struct dri_context *) shareList;
580      shared = pcp_shared->driContext;
581   }
582
583   pcp = Xmalloc(sizeof *pcp);
584   if (pcp == NULL)
585      return NULL;
586
587   memset(pcp, 0, sizeof *pcp);
588   if (!glx_context_init(&pcp->base, &psc->base, &config->base)) {
589      Xfree(pcp);
590      return NULL;
591   }
592
593   if (!XF86DRICreateContextWithConfig(psc->base.dpy, psc->base.scr,
594                                       config->base.visualID,
595                                       &pcp->hwContextID, &hwContext)) {
596      Xfree(pcp);
597      return NULL;
598   }
599
600   pcp->driContext =
601      (*psc->legacy->createNewContext) (psc->driScreen,
602                                        config->driConfig,
603                                        renderType, shared, hwContext, pcp);
604   if (pcp->driContext == NULL) {
605      XF86DRIDestroyContext(psc->base.dpy, psc->base.scr, pcp->hwContextID);
606      Xfree(pcp);
607      return NULL;
608   }
609
610   pcp->base.vtable = &dri_context_vtable;
611
612   return &pcp->base;
613}
614
615static void
616driDestroyDrawable(__GLXDRIdrawable * pdraw)
617{
618   struct dri_screen *psc = (struct dri_screen *) pdraw->psc;
619   struct dri_drawable *pdp = (struct dri_drawable *) pdraw;
620
621   (*psc->core->destroyDrawable) (pdp->driDrawable);
622   XF86DRIDestroyDrawable(psc->base.dpy, psc->base.scr, pdraw->drawable);
623   Xfree(pdraw);
624}
625
626static __GLXDRIdrawable *
627driCreateDrawable(struct glx_screen *base,
628                  XID xDrawable,
629                  GLXDrawable drawable, struct glx_config *config_base)
630{
631   drm_drawable_t hwDrawable;
632   void *empty_attribute_list = NULL;
633   __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base;
634   struct dri_screen *psc = (struct dri_screen *) base;
635   struct dri_drawable *pdp;
636
637   /* Old dri can't handle GLX 1.3+ drawable constructors. */
638   if (xDrawable != drawable)
639      return NULL;
640
641   pdp = Xmalloc(sizeof *pdp);
642   if (!pdp)
643      return NULL;
644
645   memset(pdp, 0, sizeof *pdp);
646   pdp->base.drawable = drawable;
647   pdp->base.psc = &psc->base;
648
649   if (!XF86DRICreateDrawable(psc->base.dpy, psc->base.scr,
650			      drawable, &hwDrawable)) {
651      Xfree(pdp);
652      return NULL;
653   }
654
655   /* Create a new drawable */
656   pdp->driDrawable =
657      (*psc->legacy->createNewDrawable) (psc->driScreen,
658                                         config->driConfig,
659                                         hwDrawable,
660                                         GLX_WINDOW_BIT,
661                                         empty_attribute_list, pdp);
662
663   if (!pdp->driDrawable) {
664      XF86DRIDestroyDrawable(psc->base.dpy, psc->base.scr, drawable);
665      Xfree(pdp);
666      return NULL;
667   }
668
669   pdp->base.destroyDrawable = driDestroyDrawable;
670
671   return &pdp->base;
672}
673
674static int64_t
675driSwapBuffers(__GLXDRIdrawable * pdraw, int64_t unused1, int64_t unused2,
676	       int64_t unused3)
677{
678   struct dri_screen *psc = (struct dri_screen *) pdraw->psc;
679   struct dri_drawable *pdp = (struct dri_drawable *) pdraw;
680
681   (*psc->core->swapBuffers) (pdp->driDrawable);
682   return 0;
683}
684
685static void
686driCopySubBuffer(__GLXDRIdrawable * pdraw,
687                 int x, int y, int width, int height)
688{
689   struct dri_drawable *pdp = (struct dri_drawable *) pdraw;
690   struct dri_screen *psc = (struct dri_screen *) pdp->base.psc;
691
692   (*psc->driCopySubBuffer->copySubBuffer) (pdp->driDrawable,
693					    x, y, width, height);
694}
695
696static void
697driDestroyScreen(struct glx_screen *base)
698{
699   struct dri_screen *psc = (struct dri_screen *) base;
700
701   /* Free the direct rendering per screen data */
702   if (psc->driScreen)
703      (*psc->core->destroyScreen) (psc->driScreen);
704   driDestroyConfigs(psc->driver_configs);
705   psc->driScreen = NULL;
706   if (psc->driver)
707      dlclose(psc->driver);
708}
709
710#ifdef __DRI_SWAP_BUFFER_COUNTER
711
712static int
713driDrawableGetMSC(struct glx_screen *base, __GLXDRIdrawable *pdraw,
714		   int64_t *ust, int64_t *msc, int64_t *sbc)
715{
716   struct dri_screen *psc = (struct dri_screen *) base;
717   struct dri_drawable *pdp = (struct dri_drawable *) pdraw;
718
719   if (pdp && psc->sbc && psc->msc)
720      return ( (*psc->msc->getMSC)(psc->driScreen, msc) == 0 &&
721	       (*psc->sbc->getSBC)(pdp->driDrawable, sbc) == 0 &&
722	       __glXGetUST(ust) == 0 );
723}
724
725static int
726driWaitForMSC(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor,
727	       int64_t remainder, int64_t *ust, int64_t *msc, int64_t *sbc)
728{
729   struct dri_screen *psc = (struct dri_screen *) pdraw->psc;
730   struct dri_drawable *pdp = (struct dri_drawable *) pdraw;
731
732   if (pdp != NULL && psc->msc != NULL) {
733      ret = (*psc->msc->waitForMSC) (pdp->driDrawable, target_msc,
734				     divisor, remainder, msc, sbc);
735
736      /* __glXGetUST returns zero on success and non-zero on failure.
737       * This function returns True on success and False on failure.
738       */
739      return ret == 0 && __glXGetUST(ust) == 0;
740   }
741}
742
743static int
744driWaitForSBC(__GLXDRIdrawable *pdraw, int64_t target_sbc, int64_t *ust,
745	       int64_t *msc, int64_t *sbc)
746{
747   struct dri_drawable *pdp = (struct dri_drawable *) pdraw;
748
749   if (pdp != NULL && psc->sbc != NULL) {
750      ret =
751         (*psc->sbc->waitForSBC) (pdp->driDrawable, target_sbc, msc, sbc);
752
753      /* __glXGetUST returns zero on success and non-zero on failure.
754       * This function returns True on success and False on failure.
755       */
756      return ((ret == 0) && (__glXGetUST(ust) == 0));
757   }
758
759   return DRI2WaitSBC(pdp->base.psc->dpy,
760		      pdp->base.xDrawable, target_sbc, ust, msc, sbc);
761}
762
763#endif
764
765static int
766driSetSwapInterval(__GLXDRIdrawable *pdraw, int interval)
767{
768   struct dri_drawable *pdp = (struct dri_drawable *) pdraw;
769   struct dri_screen *psc = (struct dri_screen *) pdraw->psc;
770
771   if (psc->swapControl != NULL && pdraw != NULL) {
772      psc->swapControl->setSwapInterval(pdp->driDrawable, interval);
773      return 0;
774   }
775
776   return GLX_BAD_CONTEXT;
777}
778
779static int
780driGetSwapInterval(__GLXDRIdrawable *pdraw)
781{
782   struct dri_drawable *pdp = (struct dri_drawable *) pdraw;
783   struct dri_screen *psc = (struct dri_screen *) pdraw->psc;
784
785   if (psc->swapControl != NULL && pdraw != NULL)
786      return psc->swapControl->getSwapInterval(pdp->driDrawable);
787
788   return 0;
789}
790
791/* Bind DRI1 specific extensions */
792static void
793driBindExtensions(struct dri_screen *psc, const __DRIextension **extensions)
794{
795   int i;
796
797   for (i = 0; extensions[i]; i++) {
798      /* No DRI2 support for swap_control at the moment, since SwapBuffers
799       * is done by the X server */
800      if (strcmp(extensions[i]->name, __DRI_SWAP_CONTROL) == 0) {
801	 psc->swapControl = (__DRIswapControlExtension *) extensions[i];
802	 __glXEnableDirectExtension(&psc->base, "GLX_SGI_swap_control");
803	 __glXEnableDirectExtension(&psc->base, "GLX_MESA_swap_control");
804      }
805
806      if (strcmp(extensions[i]->name, __DRI_MEDIA_STREAM_COUNTER) == 0) {
807         psc->msc = (__DRImediaStreamCounterExtension *) extensions[i];
808         __glXEnableDirectExtension(&psc->base, "GLX_SGI_video_sync");
809      }
810
811      if (strcmp(extensions[i]->name, __DRI_COPY_SUB_BUFFER) == 0) {
812	 psc->driCopySubBuffer = (__DRIcopySubBufferExtension *) extensions[i];
813	 __glXEnableDirectExtension(&psc->base, "GLX_MESA_copy_sub_buffer");
814      }
815
816      if (strcmp(extensions[i]->name, __DRI_READ_DRAWABLE) == 0) {
817	 __glXEnableDirectExtension(&psc->base, "GLX_SGI_make_current_read");
818      }
819      /* Ignore unknown extensions */
820   }
821}
822
823static const struct glx_screen_vtable dri_screen_vtable = {
824   dri_create_context
825};
826
827static struct glx_screen *
828driCreateScreen(int screen, struct glx_display *priv)
829{
830   struct dri_display *pdp;
831   __GLXDRIscreen *psp;
832   const __DRIextension **extensions;
833   struct dri_screen *psc;
834   char *driverName;
835   int i;
836
837   psc = Xcalloc(1, sizeof *psc);
838   if (psc == NULL)
839      return NULL;
840
841   memset(psc, 0, sizeof *psc);
842   if (!glx_screen_init(&psc->base, screen, priv)) {
843      Xfree(psc);
844      return NULL;
845   }
846
847   if (!driGetDriverName(priv->dpy, screen, &driverName)) {
848      goto cleanup;
849   }
850
851   psc->driver = driOpenDriver(driverName);
852   Xfree(driverName);
853   if (psc->driver == NULL)
854      goto cleanup;
855
856   extensions = dlsym(psc->driver, __DRI_DRIVER_EXTENSIONS);
857   if (extensions == NULL) {
858      ErrorMessageF("driver exports no extensions (%s)\n", dlerror());
859      goto cleanup;
860   }
861
862   for (i = 0; extensions[i]; i++) {
863      if (strcmp(extensions[i]->name, __DRI_CORE) == 0)
864	 psc->core = (__DRIcoreExtension *) extensions[i];
865      if (strcmp(extensions[i]->name, __DRI_LEGACY) == 0)
866	 psc->legacy = (__DRIlegacyExtension *) extensions[i];
867   }
868
869   if (psc->core == NULL || psc->legacy == NULL)
870      goto cleanup;
871
872   pdp = (struct dri_display *) priv->driDisplay;
873   psc->driScreen =
874      CallCreateNewScreen(psc->base.dpy, screen, psc, pdp);
875   if (psc->driScreen == NULL)
876      goto cleanup;
877
878   extensions = psc->core->getExtensions(psc->driScreen);
879   driBindExtensions(psc, extensions);
880
881   psc->base.vtable = &dri_screen_vtable;
882   psp = &psc->vtable;
883   psc->base.driScreen = psp;
884   if (psc->driCopySubBuffer)
885      psp->copySubBuffer = driCopySubBuffer;
886
887   psp->destroyScreen = driDestroyScreen;
888   psp->createDrawable = driCreateDrawable;
889   psp->swapBuffers = driSwapBuffers;
890
891#ifdef __DRI_SWAP_BUFFER_COUNTER
892   psp->getDrawableMSC = driDrawableGetMSC;
893   psp->waitForMSC = driWaitForMSC;
894   psp->waitForSBC = driWaitForSBC;
895#endif
896
897   psp->setSwapInterval = driSetSwapInterval;
898   psp->getSwapInterval = driGetSwapInterval;
899
900   return &psc->base;
901
902cleanup:
903   if (psc->driver)
904      dlclose(psc->driver);
905   glx_screen_cleanup(&psc->base);
906   Xfree(psc);
907
908   return NULL;
909}
910
911/* Called from __glXFreeDisplayPrivate.
912 */
913static void
914driDestroyDisplay(__GLXDRIdisplay * dpy)
915{
916   Xfree(dpy);
917}
918
919/*
920 * Allocate, initialize and return a __DRIdisplayPrivate object.
921 * This is called from __glXInitialize() when we are given a new
922 * display pointer.
923 */
924_X_HIDDEN __GLXDRIdisplay *
925driCreateDisplay(Display * dpy)
926{
927   struct dri_display *pdpyp;
928   int eventBase, errorBase;
929   int major, minor, patch;
930
931   if (!XF86DRIQueryExtension(dpy, &eventBase, &errorBase)) {
932      return NULL;
933   }
934
935   if (!XF86DRIQueryVersion(dpy, &major, &minor, &patch)) {
936      return NULL;
937   }
938
939   pdpyp = Xmalloc(sizeof *pdpyp);
940   if (!pdpyp) {
941      return NULL;
942   }
943
944   pdpyp->driMajor = major;
945   pdpyp->driMinor = minor;
946   pdpyp->driPatch = patch;
947
948   pdpyp->base.destroyDisplay = driDestroyDisplay;
949   pdpyp->base.createScreen = driCreateScreen;
950
951   return &pdpyp->base;
952}
953
954#endif /* GLX_DIRECT_RENDERING */
955