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