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