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