dri_glx.c revision 115203281cf791221f586f03c14cfe4e0a44dd7a
1cf2cfa174ca878c144e17e9fc60ca8e9070d7dededisonn@google.com/**************************************************************************
2cf2cfa174ca878c144e17e9fc60ca8e9070d7dededisonn@google.com
3cf2cfa174ca878c144e17e9fc60ca8e9070d7dededisonn@google.comCopyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
4cf2cfa174ca878c144e17e9fc60ca8e9070d7dededisonn@google.comAll Rights Reserved.
5cf2cfa174ca878c144e17e9fc60ca8e9070d7dededisonn@google.com
6cf2cfa174ca878c144e17e9fc60ca8e9070d7dededisonn@google.comPermission is hereby granted, free of charge, to any person obtaining a
7cf2cfa174ca878c144e17e9fc60ca8e9070d7dededisonn@google.comcopy of this software and associated documentation files (the
8cf2cfa174ca878c144e17e9fc60ca8e9070d7dededisonn@google.com"Software"), to deal in the Software without restriction, including
9cf2cfa174ca878c144e17e9fc60ca8e9070d7dededisonn@google.comwithout limitation the rights to use, copy, modify, merge, publish,
108cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comdistribute, sub license, and/or sell copies of the Software, and to
118cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.compermit persons to whom the Software is furnished to do so, subject to
128cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comthe following conditions:
138cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
148cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comThe above copyright notice and this permission notice (including the
158cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comnext paragraph) shall be included in all copies or substantial portions
168cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comof the Software.
178cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
188cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
198cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
208cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
218cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comIN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
228cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
238cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
248cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
258cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
268cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com**************************************************************************/
278cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
288cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com/*
298cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com * Authors:
308cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com *   Kevin E. Martin <kevin@precisioninsight.com>
318cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com *   Brian Paul <brian@precisioninsight.com>
32cf2cfa174ca878c144e17e9fc60ca8e9070d7dededisonn@google.com *
33 */
34
35#ifdef GLX_DIRECT_RENDERING
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
50typedef struct __GLXDRIdisplayPrivateRec __GLXDRIdisplayPrivate;
51typedef struct __GLXDRIcontextPrivateRec __GLXDRIcontextPrivate;
52
53struct __GLXDRIdisplayPrivateRec
54{
55   __GLXDRIdisplay base;
56
57   /*
58    ** XFree86-DRI version information
59    */
60   int driMajor;
61   int driMinor;
62   int driPatch;
63};
64
65struct __GLXDRIcontextPrivateRec
66{
67   __GLXDRIcontext base;
68   __DRIcontext *driContext;
69   XID hwContextID;
70   __GLXscreenConfigs *psc;
71};
72
73/*
74 * Given a display pointer and screen number, determine the name of
75 * the DRI driver for the screen. (I.e. "r128", "tdfx", etc).
76 * Return True for success, False for failure.
77 */
78static Bool
79driGetDriverName(Display * dpy, int scrNum, char **driverName)
80{
81   int directCapable;
82   Bool b;
83   int event, error;
84   int driverMajor, driverMinor, driverPatch;
85
86   *driverName = NULL;
87
88   if (XF86DRIQueryExtension(dpy, &event, &error)) {    /* DRI1 */
89      if (!XF86DRIQueryDirectRenderingCapable(dpy, scrNum, &directCapable)) {
90         ErrorMessageF("XF86DRIQueryDirectRenderingCapable failed\n");
91         return False;
92      }
93      if (!directCapable) {
94         ErrorMessageF("XF86DRIQueryDirectRenderingCapable returned false\n");
95         return False;
96      }
97
98      b = XF86DRIGetClientDriverName(dpy, scrNum, &driverMajor, &driverMinor,
99                                     &driverPatch, driverName);
100      if (!b) {
101         ErrorMessageF("Cannot determine driver name for screen %d\n",
102                       scrNum);
103         return False;
104      }
105
106      InfoMessageF("XF86DRIGetClientDriverName: %d.%d.%d %s (screen %d)\n",
107                   driverMajor, driverMinor, driverPatch, *driverName,
108                   scrNum);
109
110      return True;
111   }
112   else if (DRI2QueryExtension(dpy, &event, &error)) {  /* DRI2 */
113      char *dev;
114      Bool ret = DRI2Connect(dpy, RootWindow(dpy, scrNum), driverName, &dev);
115
116      if (ret)
117         Xfree(dev);
118
119      return ret;
120   }
121
122   return False;
123}
124
125/*
126 * Exported function for querying the DRI driver for a given screen.
127 *
128 * The returned char pointer points to a static array that will be
129 * overwritten by subsequent calls.
130 */
131PUBLIC const char *
132glXGetScreenDriver(Display * dpy, int scrNum)
133{
134   static char ret[32];
135   char *driverName;
136   if (driGetDriverName(dpy, scrNum, &driverName)) {
137      int len;
138      if (!driverName)
139         return NULL;
140      len = strlen(driverName);
141      if (len >= 31)
142         return NULL;
143      memcpy(ret, driverName, len + 1);
144      Xfree(driverName);
145      return ret;
146   }
147   return NULL;
148}
149
150/*
151 * Exported function for obtaining a driver's option list (UTF-8 encoded XML).
152 *
153 * The returned char pointer points directly into the driver. Therefore
154 * it should be treated as a constant.
155 *
156 * If the driver was not found or does not support configuration NULL is
157 * returned.
158 *
159 * Note: The driver remains opened after this function returns.
160 */
161PUBLIC const char *
162glXGetDriverConfig(const char *driverName)
163{
164   void *handle = driOpenDriver(driverName);
165   if (handle)
166      return dlsym(handle, "__driConfigOptions");
167   else
168      return NULL;
169}
170
171#ifdef XDAMAGE_1_1_INTERFACE
172
173static GLboolean
174has_damage_post(Display * dpy)
175{
176   static GLboolean inited = GL_FALSE;
177   static GLboolean has_damage;
178
179   if (!inited) {
180      int major, minor;
181
182      if (XDamageQueryVersion(dpy, &major, &minor) &&
183          major == 1 && minor >= 1) {
184         has_damage = GL_TRUE;
185      }
186      else {
187         has_damage = GL_FALSE;
188      }
189      inited = GL_TRUE;
190   }
191
192   return has_damage;
193}
194
195static void
196__glXReportDamage(__DRIdrawable * driDraw,
197                  int x, int y,
198                  drm_clip_rect_t * rects, int num_rects,
199                  GLboolean front_buffer, void *loaderPrivate)
200{
201   XRectangle *xrects;
202   XserverRegion region;
203   int i;
204   int x_off, y_off;
205   __GLXDRIdrawable *glxDraw = loaderPrivate;
206   __GLXscreenConfigs *psc = glxDraw->psc;
207   Display *dpy = psc->dpy;
208   Drawable drawable;
209
210   if (!has_damage_post(dpy))
211      return;
212
213   if (front_buffer) {
214      x_off = x;
215      y_off = y;
216      drawable = RootWindow(dpy, psc->scr);
217   }
218   else {
219      x_off = 0;
220      y_off = 0;
221      drawable = glxDraw->xDrawable;
222   }
223
224   xrects = malloc(sizeof(XRectangle) * num_rects);
225   if (xrects == NULL)
226      return;
227
228   for (i = 0; i < num_rects; i++) {
229      xrects[i].x = rects[i].x1 + x_off;
230      xrects[i].y = rects[i].y1 + y_off;
231      xrects[i].width = rects[i].x2 - rects[i].x1;
232      xrects[i].height = rects[i].y2 - rects[i].y1;
233   }
234   region = XFixesCreateRegion(dpy, xrects, num_rects);
235   free(xrects);
236   XDamageAdd(dpy, drawable, region);
237   XFixesDestroyRegion(dpy, region);
238}
239
240static const __DRIdamageExtension damageExtension = {
241   {__DRI_DAMAGE, __DRI_DAMAGE_VERSION},
242   __glXReportDamage,
243};
244
245#endif
246
247static GLboolean
248__glXDRIGetDrawableInfo(__DRIdrawable * drawable,
249                        unsigned int *index, unsigned int *stamp,
250                        int *X, int *Y, int *W, int *H,
251                        int *numClipRects, drm_clip_rect_t ** pClipRects,
252                        int *backX, int *backY,
253                        int *numBackClipRects,
254                        drm_clip_rect_t ** pBackClipRects,
255                        void *loaderPrivate)
256{
257   __GLXDRIdrawable *glxDraw = loaderPrivate;
258   __GLXscreenConfigs *psc = glxDraw->psc;
259   Display *dpy = psc->dpy;
260
261   return XF86DRIGetDrawableInfo(dpy, psc->scr, glxDraw->drawable,
262                                 index, stamp, X, Y, W, H,
263                                 numClipRects, pClipRects,
264                                 backX, backY,
265                                 numBackClipRects, pBackClipRects);
266}
267
268static const __DRIgetDrawableInfoExtension getDrawableInfoExtension = {
269   {__DRI_GET_DRAWABLE_INFO, __DRI_GET_DRAWABLE_INFO_VERSION},
270   __glXDRIGetDrawableInfo
271};
272
273static const __DRIextension *loader_extensions[] = {
274   &systemTimeExtension.base,
275   &getDrawableInfoExtension.base,
276#ifdef XDAMAGE_1_1_INTERFACE
277   &damageExtension.base,
278#endif
279   NULL
280};
281
282/**
283 * Perform the required libGL-side initialization and call the client-side
284 * driver's \c __driCreateNewScreen function.
285 *
286 * \param dpy    Display pointer.
287 * \param scrn   Screen number on the display.
288 * \param psc    DRI screen information.
289 * \param driDpy DRI display information.
290 * \param createNewScreen  Pointer to the client-side driver's
291 *               \c __driCreateNewScreen function.
292 * \returns A pointer to the \c __DRIscreen structure returned by
293 *          the client-side driver on success, or \c NULL on failure.
294 */
295static void *
296CallCreateNewScreen(Display * dpy, int scrn, __GLXscreenConfigs * psc,
297                    __GLXDRIdisplayPrivate * driDpy)
298{
299   void *psp = NULL;
300   drm_handle_t hSAREA;
301   drmAddress pSAREA = MAP_FAILED;
302   char *BusID;
303   __DRIversion ddx_version;
304   __DRIversion dri_version;
305   __DRIversion drm_version;
306   __DRIframebuffer framebuffer;
307   int fd = -1;
308   int status;
309
310   drm_magic_t magic;
311   drmVersionPtr version;
312   int newlyopened;
313   char *driverName;
314   drm_handle_t hFB;
315   int junk;
316   const __DRIconfig **driver_configs;
317   __GLcontextModes *visual;
318
319   /* DRI protocol version. */
320   dri_version.major = driDpy->driMajor;
321   dri_version.minor = driDpy->driMinor;
322   dri_version.patch = driDpy->driPatch;
323
324   framebuffer.base = MAP_FAILED;
325   framebuffer.dev_priv = NULL;
326   framebuffer.size = 0;
327
328   if (!XF86DRIOpenConnection(dpy, scrn, &hSAREA, &BusID)) {
329      ErrorMessageF("XF86DRIOpenConnection failed\n");
330      goto handle_error;
331   }
332
333   fd = drmOpenOnce(NULL, BusID, &newlyopened);
334
335   Xfree(BusID);                /* No longer needed */
336
337   if (fd < 0) {
338      ErrorMessageF("drmOpenOnce failed (%s)\n", strerror(-fd));
339      goto handle_error;
340   }
341
342   if (drmGetMagic(fd, &magic)) {
343      ErrorMessageF("drmGetMagic failed\n");
344      goto handle_error;
345   }
346
347   version = drmGetVersion(fd);
348   if (version) {
349      drm_version.major = version->version_major;
350      drm_version.minor = version->version_minor;
351      drm_version.patch = version->version_patchlevel;
352      drmFreeVersion(version);
353   }
354   else {
355      drm_version.major = -1;
356      drm_version.minor = -1;
357      drm_version.patch = -1;
358   }
359
360   if (newlyopened && !XF86DRIAuthConnection(dpy, scrn, magic)) {
361      ErrorMessageF("XF86DRIAuthConnection failed\n");
362      goto handle_error;
363   }
364
365   /* Get device name (like "tdfx") and the ddx version numbers.
366    * We'll check the version in each DRI driver's "createNewScreen"
367    * function. */
368   if (!XF86DRIGetClientDriverName(dpy, scrn,
369                                   &ddx_version.major,
370                                   &ddx_version.minor,
371                                   &ddx_version.patch, &driverName)) {
372      ErrorMessageF("XF86DRIGetClientDriverName failed\n");
373      goto handle_error;
374   }
375
376   Xfree(driverName);           /* No longer needed. */
377
378   /*
379    * Get device-specific info.  pDevPriv will point to a struct
380    * (such as DRIRADEONRec in xfree86/driver/ati/radeon_dri.h) that
381    * has information about the screen size, depth, pitch, ancilliary
382    * buffers, DRM mmap handles, etc.
383    */
384   if (!XF86DRIGetDeviceInfo(dpy, scrn, &hFB, &junk,
385                             &framebuffer.size, &framebuffer.stride,
386                             &framebuffer.dev_priv_size,
387                             &framebuffer.dev_priv)) {
388      ErrorMessageF("XF86DRIGetDeviceInfo failed");
389      goto handle_error;
390   }
391
392   framebuffer.width = DisplayWidth(dpy, scrn);
393   framebuffer.height = DisplayHeight(dpy, scrn);
394
395   /* Map the framebuffer region. */
396   status = drmMap(fd, hFB, framebuffer.size,
397                   (drmAddressPtr) & framebuffer.base);
398   if (status != 0) {
399      ErrorMessageF("drmMap of framebuffer failed (%s)", strerror(-status));
400      goto handle_error;
401   }
402
403   /* Map the SAREA region.  Further mmap regions may be setup in
404    * each DRI driver's "createNewScreen" function.
405    */
406   status = drmMap(fd, hSAREA, SAREA_MAX, &pSAREA);
407   if (status != 0) {
408      ErrorMessageF("drmMap of SAREA failed (%s)", strerror(-status));
409      goto handle_error;
410   }
411
412   psp = (*psc->legacy->createNewScreen) (scrn,
413                                          &ddx_version,
414                                          &dri_version,
415                                          &drm_version,
416                                          &framebuffer,
417                                          pSAREA,
418                                          fd,
419                                          loader_extensions,
420                                          &driver_configs, psc);
421
422   if (psp == NULL) {
423      ErrorMessageF("Calling driver entry point failed");
424      goto handle_error;
425   }
426
427   psc->configs = driConvertConfigs(psc->core, psc->configs, driver_configs);
428   psc->visuals = driConvertConfigs(psc->core, psc->visuals, driver_configs);
429
430   psc->driver_configs = driver_configs;
431
432   /* Visuals with depth != screen depth are subject to automatic compositing
433    * in the X server, so DRI1 can't render to them properly. Mark them as
434    * non-conformant to prevent apps from picking them up accidentally.
435    */
436   for (visual = psc->visuals; visual; visual = visual->next) {
437      XVisualInfo template;
438      XVisualInfo *visuals;
439      int num_visuals;
440      long mask;
441
442      template.visualid = visual->visualID;
443      mask = VisualIDMask;
444      visuals = XGetVisualInfo(dpy, mask, &template, &num_visuals);
445
446      if (visuals) {
447         if (num_visuals > 0 && visuals->depth != DefaultDepth(dpy, scrn))
448            visual->visualRating = GLX_NON_CONFORMANT_CONFIG;
449
450         XFree(visuals);
451      }
452   }
453
454   return psp;
455
456 handle_error:
457   if (pSAREA != MAP_FAILED)
458      drmUnmap(pSAREA, SAREA_MAX);
459
460   if (framebuffer.base != MAP_FAILED)
461      drmUnmap((drmAddress) framebuffer.base, framebuffer.size);
462
463   if (framebuffer.dev_priv != NULL)
464      Xfree(framebuffer.dev_priv);
465
466   if (fd >= 0)
467      drmCloseOnce(fd);
468
469   XF86DRICloseConnection(dpy, scrn);
470
471   ErrorMessageF("reverting to software direct rendering\n");
472
473   return NULL;
474}
475
476static void
477driDestroyContext(__GLXDRIcontext * context,
478                  __GLXscreenConfigs * psc, Display * dpy)
479{
480   __GLXDRIcontextPrivate *pcp = (__GLXDRIcontextPrivate *) context;
481
482   (*psc->core->destroyContext) (pcp->driContext);
483
484   XF86DRIDestroyContext(psc->dpy, psc->scr, pcp->hwContextID);
485   Xfree(pcp);
486}
487
488static Bool
489driBindContext(__GLXDRIcontext * context,
490               __GLXDRIdrawable * draw, __GLXDRIdrawable * read)
491{
492   __GLXDRIcontextPrivate *pcp = (__GLXDRIcontextPrivate *) context;
493   const __DRIcoreExtension *core = pcp->psc->core;
494
495   return (*core->bindContext) (pcp->driContext,
496                                draw->driDrawable, read->driDrawable);
497}
498
499static void
500driUnbindContext(__GLXDRIcontext * context)
501{
502   __GLXDRIcontextPrivate *pcp = (__GLXDRIcontextPrivate *) context;
503   const __DRIcoreExtension *core = pcp->psc->core;
504
505   (*core->unbindContext) (pcp->driContext);
506}
507
508static __GLXDRIcontext *
509driCreateContext(__GLXscreenConfigs * psc,
510                 const __GLcontextModes * mode,
511                 GLXContext gc, GLXContext shareList, int renderType)
512{
513   __GLXDRIcontextPrivate *pcp, *pcp_shared;
514   drm_context_t hwContext;
515   __DRIcontext *shared = NULL;
516   __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) mode;
517
518   if (!psc || !psc->driScreen)
519      return NULL;
520
521   if (shareList) {
522      pcp_shared = (__GLXDRIcontextPrivate *) shareList->driContext;
523      shared = pcp_shared->driContext;
524   }
525
526   pcp = Xmalloc(sizeof *pcp);
527   if (pcp == NULL)
528      return NULL;
529
530   pcp->psc = psc;
531   if (!XF86DRICreateContextWithConfig(psc->dpy, psc->scr,
532                                       mode->visualID,
533                                       &pcp->hwContextID, &hwContext)) {
534      Xfree(pcp);
535      return NULL;
536   }
537
538   pcp->driContext =
539      (*psc->legacy->createNewContext) (psc->__driScreen,
540                                        config->driConfig,
541                                        renderType, shared, hwContext, pcp);
542   if (pcp->driContext == NULL) {
543      XF86DRIDestroyContext(psc->dpy, psc->scr, pcp->hwContextID);
544      Xfree(pcp);
545      return NULL;
546   }
547
548   pcp->base.destroyContext = driDestroyContext;
549   pcp->base.bindContext = driBindContext;
550   pcp->base.unbindContext = driUnbindContext;
551
552   return &pcp->base;
553}
554
555static void
556driDestroyDrawable(__GLXDRIdrawable * pdraw)
557{
558   __GLXscreenConfigs *psc = pdraw->psc;
559
560   (*psc->core->destroyDrawable) (pdraw->driDrawable);
561   XF86DRIDestroyDrawable(psc->dpy, psc->scr, pdraw->drawable);
562   Xfree(pdraw);
563}
564
565static __GLXDRIdrawable *
566driCreateDrawable(__GLXscreenConfigs * psc,
567                  XID xDrawable,
568                  GLXDrawable drawable, const __GLcontextModes * modes)
569{
570   __GLXDRIdrawable *pdraw;
571   drm_drawable_t hwDrawable;
572   void *empty_attribute_list = NULL;
573   __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) modes;
574
575   /* Old dri can't handle GLX 1.3+ drawable constructors. */
576   if (xDrawable != drawable)
577      return NULL;
578
579   pdraw = Xmalloc(sizeof(*pdraw));
580   if (!pdraw)
581      return NULL;
582
583   pdraw->drawable = drawable;
584   pdraw->psc = psc;
585
586   if (!XF86DRICreateDrawable(psc->dpy, psc->scr, drawable, &hwDrawable)) {
587      Xfree(pdraw);
588      return NULL;
589   }
590
591   /* Create a new drawable */
592   pdraw->driDrawable =
593      (*psc->legacy->createNewDrawable) (psc->__driScreen,
594                                         config->driConfig,
595                                         hwDrawable,
596                                         GLX_WINDOW_BIT,
597                                         empty_attribute_list, pdraw);
598
599   if (!pdraw->driDrawable) {
600      XF86DRIDestroyDrawable(psc->dpy, psc->scr, drawable);
601      Xfree(pdraw);
602      return NULL;
603   }
604
605   pdraw->destroyDrawable = driDestroyDrawable;
606
607   return pdraw;
608}
609
610static int64_t
611driSwapBuffers(__GLXDRIdrawable * pdraw, int64_t unused1, int64_t unused2,
612	       int64_t unused3)
613{
614   (*pdraw->psc->core->swapBuffers) (pdraw->driDrawable);
615   return 0;
616}
617
618static void
619driCopySubBuffer(__GLXDRIdrawable * pdraw,
620                 int x, int y, int width, int height)
621{
622   (*pdraw->psc->driCopySubBuffer->copySubBuffer) (pdraw->driDrawable,
623                                                   x, y, width, height);
624}
625
626static void
627driDestroyScreen(__GLXscreenConfigs * psc)
628{
629   /* Free the direct rendering per screen data */
630   if (psc->__driScreen)
631      (*psc->core->destroyScreen) (psc->__driScreen);
632   psc->__driScreen = NULL;
633   if (psc->driver)
634      dlclose(psc->driver);
635}
636
637static __GLXDRIscreen *
638driCreateScreen(__GLXscreenConfigs * psc, int screen,
639                __GLXdisplayPrivate * priv)
640{
641   __GLXDRIdisplayPrivate *pdp;
642   __GLXDRIscreen *psp;
643   const __DRIextension **extensions;
644   char *driverName;
645   int i;
646
647   psp = Xcalloc(1, sizeof *psp);
648   if (psp == NULL)
649      return NULL;
650
651   if (!driGetDriverName(priv->dpy, screen, &driverName)) {
652      Xfree(psp);
653      return NULL;
654   }
655
656   psc->driver = driOpenDriver(driverName);
657   Xfree(driverName);
658   if (psc->driver == NULL) {
659      Xfree(psp);
660      return NULL;
661   }
662
663   extensions = dlsym(psc->driver, __DRI_DRIVER_EXTENSIONS);
664   if (extensions == NULL) {
665      ErrorMessageF("driver exports no extensions (%s)\n", dlerror());
666      Xfree(psp);
667      return NULL;
668   }
669
670   for (i = 0; extensions[i]; i++) {
671      if (strcmp(extensions[i]->name, __DRI_CORE) == 0)
672	 psc->core = (__DRIcoreExtension *) extensions[i];
673      if (strcmp(extensions[i]->name, __DRI_LEGACY) == 0)
674	 psc->legacy = (__DRIlegacyExtension *) extensions[i];
675   }
676
677   if (psc->core == NULL || psc->legacy == NULL) {
678      Xfree(psp);
679      return NULL;
680   }
681
682   pdp = (__GLXDRIdisplayPrivate *) priv->driDisplay;
683   psc->__driScreen = CallCreateNewScreen(psc->dpy, screen, psc, pdp);
684   if (psc->__driScreen == NULL) {
685      dlclose(psc->driver);
686      Xfree(psp);
687      return NULL;
688   }
689
690   driBindExtensions(psc);
691   driBindCommonExtensions(psc);
692
693   if (psc->driCopySubBuffer)
694      psp->copySubBuffer = driCopySubBuffer;
695
696   psp->destroyScreen = driDestroyScreen;
697   psp->createContext = driCreateContext;
698   psp->createDrawable = driCreateDrawable;
699   psp->swapBuffers = driSwapBuffers;
700   psp->waitX = NULL;
701   psp->waitGL = NULL;
702
703   return psp;
704}
705
706/* Called from __glXFreeDisplayPrivate.
707 */
708static void
709driDestroyDisplay(__GLXDRIdisplay * dpy)
710{
711   Xfree(dpy);
712}
713
714/*
715 * Allocate, initialize and return a __DRIdisplayPrivate object.
716 * This is called from __glXInitialize() when we are given a new
717 * display pointer.
718 */
719_X_HIDDEN __GLXDRIdisplay *
720driCreateDisplay(Display * dpy)
721{
722   __GLXDRIdisplayPrivate *pdpyp;
723   int eventBase, errorBase;
724   int major, minor, patch;
725
726   if (!XF86DRIQueryExtension(dpy, &eventBase, &errorBase)) {
727      return NULL;
728   }
729
730   if (!XF86DRIQueryVersion(dpy, &major, &minor, &patch)) {
731      return NULL;
732   }
733
734   pdpyp = Xmalloc(sizeof *pdpyp);
735   if (!pdpyp) {
736      return NULL;
737   }
738
739   pdpyp->driMajor = major;
740   pdpyp->driMinor = minor;
741   pdpyp->driPatch = patch;
742
743   pdpyp->base.destroyDisplay = driDestroyDisplay;
744   pdpyp->base.createScreen = driCreateScreen;
745
746   return &pdpyp->base;
747}
748
749#endif /* GLX_DIRECT_RENDERING */
750