dri_glx.c revision bc34aa6128b9d509a25232d70dc826f1921fd221
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};
86
87struct dri_drawable
88{
89   __GLXDRIdrawable base;
90
91   __DRIdrawable *driDrawable;
92};
93
94static const struct glx_context_vtable dri_context_vtable;
95
96/*
97 * Given a display pointer and screen number, determine the name of
98 * the DRI driver for the screen. (I.e. "r128", "tdfx", etc).
99 * Return True for success, False for failure.
100 */
101static Bool
102driGetDriverName(Display * dpy, int scrNum, char **driverName)
103{
104   int directCapable;
105   Bool b;
106   int event, error;
107   int driverMajor, driverMinor, driverPatch;
108
109   *driverName = NULL;
110
111   if (XF86DRIQueryExtension(dpy, &event, &error)) {    /* DRI1 */
112      if (!XF86DRIQueryDirectRenderingCapable(dpy, scrNum, &directCapable)) {
113         ErrorMessageF("XF86DRIQueryDirectRenderingCapable failed\n");
114         return False;
115      }
116      if (!directCapable) {
117         ErrorMessageF("XF86DRIQueryDirectRenderingCapable returned false\n");
118         return False;
119      }
120
121      b = XF86DRIGetClientDriverName(dpy, scrNum, &driverMajor, &driverMinor,
122                                     &driverPatch, driverName);
123      if (!b) {
124         ErrorMessageF("Cannot determine driver name for screen %d\n",
125                       scrNum);
126         return False;
127      }
128
129      InfoMessageF("XF86DRIGetClientDriverName: %d.%d.%d %s (screen %d)\n",
130                   driverMajor, driverMinor, driverPatch, *driverName,
131                   scrNum);
132
133      return True;
134   }
135   else if (DRI2QueryExtension(dpy, &event, &error)) {  /* DRI2 */
136      char *dev;
137      Bool ret = DRI2Connect(dpy, RootWindow(dpy, scrNum), driverName, &dev);
138
139      if (ret)
140         Xfree(dev);
141
142      return ret;
143   }
144
145   return False;
146}
147
148/*
149 * Exported function for querying the DRI driver for a given screen.
150 *
151 * The returned char pointer points to a static array that will be
152 * overwritten by subsequent calls.
153 */
154PUBLIC const char *
155glXGetScreenDriver(Display * dpy, int scrNum)
156{
157   static char ret[32];
158   char *driverName;
159   if (driGetDriverName(dpy, scrNum, &driverName)) {
160      int len;
161      if (!driverName)
162         return NULL;
163      len = strlen(driverName);
164      if (len >= 31)
165         return NULL;
166      memcpy(ret, driverName, len + 1);
167      Xfree(driverName);
168      return ret;
169   }
170   return NULL;
171}
172
173/*
174 * Exported function for obtaining a driver's option list (UTF-8 encoded XML).
175 *
176 * The returned char pointer points directly into the driver. Therefore
177 * it should be treated as a constant.
178 *
179 * If the driver was not found or does not support configuration NULL is
180 * returned.
181 *
182 * Note: The driver remains opened after this function returns.
183 */
184PUBLIC const char *
185glXGetDriverConfig(const char *driverName)
186{
187   void *handle = driOpenDriver(driverName);
188   if (handle)
189      return dlsym(handle, "__driConfigOptions");
190   else
191      return NULL;
192}
193
194#ifdef XDAMAGE_1_1_INTERFACE
195
196static GLboolean
197has_damage_post(Display * dpy)
198{
199   static GLboolean inited = GL_FALSE;
200   static GLboolean has_damage;
201
202   if (!inited) {
203      int major, minor;
204
205      if (XDamageQueryVersion(dpy, &major, &minor) &&
206          major == 1 && minor >= 1) {
207         has_damage = GL_TRUE;
208      }
209      else {
210         has_damage = GL_FALSE;
211      }
212      inited = GL_TRUE;
213   }
214
215   return has_damage;
216}
217
218static void
219__glXReportDamage(__DRIdrawable * driDraw,
220                  int x, int y,
221                  drm_clip_rect_t * rects, int num_rects,
222                  GLboolean front_buffer, void *loaderPrivate)
223{
224   XRectangle *xrects;
225   XserverRegion region;
226   int i;
227   int x_off, y_off;
228   __GLXDRIdrawable *glxDraw = loaderPrivate;
229   __GLXscreenConfigs *psc = glxDraw->psc;
230   Display *dpy = psc->dpy;
231   Drawable drawable;
232
233   if (!has_damage_post(dpy))
234      return;
235
236   if (front_buffer) {
237      x_off = x;
238      y_off = y;
239      drawable = RootWindow(dpy, psc->scr);
240   }
241   else {
242      x_off = 0;
243      y_off = 0;
244      drawable = glxDraw->xDrawable;
245   }
246
247   xrects = malloc(sizeof(XRectangle) * num_rects);
248   if (xrects == NULL)
249      return;
250
251   for (i = 0; i < num_rects; i++) {
252      xrects[i].x = rects[i].x1 + x_off;
253      xrects[i].y = rects[i].y1 + y_off;
254      xrects[i].width = rects[i].x2 - rects[i].x1;
255      xrects[i].height = rects[i].y2 - rects[i].y1;
256   }
257   region = XFixesCreateRegion(dpy, xrects, num_rects);
258   free(xrects);
259   XDamageAdd(dpy, drawable, region);
260   XFixesDestroyRegion(dpy, region);
261}
262
263static const __DRIdamageExtension damageExtension = {
264   {__DRI_DAMAGE, __DRI_DAMAGE_VERSION},
265   __glXReportDamage,
266};
267
268#endif
269
270static GLboolean
271__glXDRIGetDrawableInfo(__DRIdrawable * drawable,
272                        unsigned int *index, unsigned int *stamp,
273                        int *X, int *Y, int *W, int *H,
274                        int *numClipRects, drm_clip_rect_t ** pClipRects,
275                        int *backX, int *backY,
276                        int *numBackClipRects,
277                        drm_clip_rect_t ** pBackClipRects,
278                        void *loaderPrivate)
279{
280   __GLXDRIdrawable *glxDraw = loaderPrivate;
281   __GLXscreenConfigs *psc = glxDraw->psc;
282   Display *dpy = psc->dpy;
283
284   return XF86DRIGetDrawableInfo(dpy, psc->scr, glxDraw->drawable,
285                                 index, stamp, X, Y, W, H,
286                                 numClipRects, pClipRects,
287                                 backX, backY,
288                                 numBackClipRects, pBackClipRects);
289}
290
291static const __DRIgetDrawableInfoExtension getDrawableInfoExtension = {
292   {__DRI_GET_DRAWABLE_INFO, __DRI_GET_DRAWABLE_INFO_VERSION},
293   __glXDRIGetDrawableInfo
294};
295
296static const __DRIextension *loader_extensions[] = {
297   &systemTimeExtension.base,
298   &getDrawableInfoExtension.base,
299#ifdef XDAMAGE_1_1_INTERFACE
300   &damageExtension.base,
301#endif
302   NULL
303};
304
305/**
306 * Perform the required libGL-side initialization and call the client-side
307 * driver's \c __driCreateNewScreen function.
308 *
309 * \param dpy    Display pointer.
310 * \param scrn   Screen number on the display.
311 * \param psc    DRI screen information.
312 * \param driDpy DRI display information.
313 * \param createNewScreen  Pointer to the client-side driver's
314 *               \c __driCreateNewScreen function.
315 * \returns A pointer to the \c __DRIscreen structure returned by
316 *          the client-side driver on success, or \c NULL on failure.
317 */
318static void *
319CallCreateNewScreen(Display *dpy, int scrn, struct dri_screen *psc,
320                    struct dri_display * driDpy)
321{
322   void *psp = NULL;
323   drm_handle_t hSAREA;
324   drmAddress pSAREA = MAP_FAILED;
325   char *BusID;
326   __DRIversion ddx_version;
327   __DRIversion dri_version;
328   __DRIversion drm_version;
329   __DRIframebuffer framebuffer;
330   int fd = -1;
331   int status;
332
333   drm_magic_t magic;
334   drmVersionPtr version;
335   int newlyopened;
336   char *driverName;
337   drm_handle_t hFB;
338   int junk;
339   const __DRIconfig **driver_configs;
340   __GLcontextModes *visual;
341
342   /* DRI protocol version. */
343   dri_version.major = driDpy->driMajor;
344   dri_version.minor = driDpy->driMinor;
345   dri_version.patch = driDpy->driPatch;
346
347   framebuffer.base = MAP_FAILED;
348   framebuffer.dev_priv = NULL;
349   framebuffer.size = 0;
350
351   if (!XF86DRIOpenConnection(dpy, scrn, &hSAREA, &BusID)) {
352      ErrorMessageF("XF86DRIOpenConnection failed\n");
353      goto handle_error;
354   }
355
356   fd = drmOpenOnce(NULL, BusID, &newlyopened);
357
358   Xfree(BusID);                /* No longer needed */
359
360   if (fd < 0) {
361      ErrorMessageF("drmOpenOnce failed (%s)\n", strerror(-fd));
362      goto handle_error;
363   }
364
365   if (drmGetMagic(fd, &magic)) {
366      ErrorMessageF("drmGetMagic failed\n");
367      goto handle_error;
368   }
369
370   version = drmGetVersion(fd);
371   if (version) {
372      drm_version.major = version->version_major;
373      drm_version.minor = version->version_minor;
374      drm_version.patch = version->version_patchlevel;
375      drmFreeVersion(version);
376   }
377   else {
378      drm_version.major = -1;
379      drm_version.minor = -1;
380      drm_version.patch = -1;
381   }
382
383   if (newlyopened && !XF86DRIAuthConnection(dpy, scrn, magic)) {
384      ErrorMessageF("XF86DRIAuthConnection failed\n");
385      goto handle_error;
386   }
387
388   /* Get device name (like "tdfx") and the ddx version numbers.
389    * We'll check the version in each DRI driver's "createNewScreen"
390    * function. */
391   if (!XF86DRIGetClientDriverName(dpy, scrn,
392                                   &ddx_version.major,
393                                   &ddx_version.minor,
394                                   &ddx_version.patch, &driverName)) {
395      ErrorMessageF("XF86DRIGetClientDriverName failed\n");
396      goto handle_error;
397   }
398
399   Xfree(driverName);           /* No longer needed. */
400
401   /*
402    * Get device-specific info.  pDevPriv will point to a struct
403    * (such as DRIRADEONRec in xfree86/driver/ati/radeon_dri.h) that
404    * has information about the screen size, depth, pitch, ancilliary
405    * buffers, DRM mmap handles, etc.
406    */
407   if (!XF86DRIGetDeviceInfo(dpy, scrn, &hFB, &junk,
408                             &framebuffer.size, &framebuffer.stride,
409                             &framebuffer.dev_priv_size,
410                             &framebuffer.dev_priv)) {
411      ErrorMessageF("XF86DRIGetDeviceInfo failed");
412      goto handle_error;
413   }
414
415   framebuffer.width = DisplayWidth(dpy, scrn);
416   framebuffer.height = DisplayHeight(dpy, scrn);
417
418   /* Map the framebuffer region. */
419   status = drmMap(fd, hFB, framebuffer.size,
420                   (drmAddressPtr) & framebuffer.base);
421   if (status != 0) {
422      ErrorMessageF("drmMap of framebuffer failed (%s)", strerror(-status));
423      goto handle_error;
424   }
425
426   /* Map the SAREA region.  Further mmap regions may be setup in
427    * each DRI driver's "createNewScreen" function.
428    */
429   status = drmMap(fd, hSAREA, SAREA_MAX, &pSAREA);
430   if (status != 0) {
431      ErrorMessageF("drmMap of SAREA failed (%s)", strerror(-status));
432      goto handle_error;
433   }
434
435   psp = (*psc->legacy->createNewScreen) (scrn,
436                                          &ddx_version,
437                                          &dri_version,
438                                          &drm_version,
439                                          &framebuffer,
440                                          pSAREA,
441                                          fd,
442                                          loader_extensions,
443                                          &driver_configs, psc);
444
445   if (psp == NULL) {
446      ErrorMessageF("Calling driver entry point failed");
447      goto handle_error;
448   }
449
450   psc->base.configs =
451      driConvertConfigs(psc->core, psc->base.configs, driver_configs);
452   psc->base.visuals =
453      driConvertConfigs(psc->core, psc->base.visuals, driver_configs);
454
455   psc->driver_configs = driver_configs;
456
457   /* Visuals with depth != screen depth are subject to automatic compositing
458    * in the X server, so DRI1 can't render to them properly. Mark them as
459    * non-conformant to prevent apps from picking them up accidentally.
460    */
461   for (visual = psc->base.visuals; visual; visual = visual->next) {
462      XVisualInfo template;
463      XVisualInfo *visuals;
464      int num_visuals;
465      long mask;
466
467      template.visualid = visual->visualID;
468      mask = VisualIDMask;
469      visuals = XGetVisualInfo(dpy, mask, &template, &num_visuals);
470
471      if (visuals) {
472         if (num_visuals > 0 && visuals->depth != DefaultDepth(dpy, scrn))
473            visual->visualRating = GLX_NON_CONFORMANT_CONFIG;
474
475         XFree(visuals);
476      }
477   }
478
479   return psp;
480
481 handle_error:
482   if (pSAREA != MAP_FAILED)
483      drmUnmap(pSAREA, SAREA_MAX);
484
485   if (framebuffer.base != MAP_FAILED)
486      drmUnmap((drmAddress) framebuffer.base, framebuffer.size);
487
488   if (framebuffer.dev_priv != NULL)
489      Xfree(framebuffer.dev_priv);
490
491   if (fd >= 0)
492      drmCloseOnce(fd);
493
494   XF86DRICloseConnection(dpy, scrn);
495
496   ErrorMessageF("reverting to software direct rendering\n");
497
498   return NULL;
499}
500
501static void
502dri_destroy_context(__GLXcontext * context)
503{
504   struct dri_context *pcp = (struct dri_context *) context;
505   struct dri_screen *psc = (struct dri_screen *) context->psc;
506
507   if (context->xid)
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->base.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->base.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