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