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