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