dri_glx.c revision 6e8897ff9f90601ebf6eed500ad942c11b54d1f7
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#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
327   if (!XF86DRIOpenConnection(dpy, scrn, &hSAREA, &BusID)) {
328      ErrorMessageF("XF86DRIOpenConnection failed\n");
329      goto handle_error;
330   }
331
332   fd = drmOpenOnce(NULL, BusID, &newlyopened);
333
334   Xfree(BusID);                /* No longer needed */
335
336   if (fd < 0) {
337      ErrorMessageF("drmOpenOnce failed (%s)\n", strerror(-fd));
338      goto handle_error;
339   }
340
341   if (drmGetMagic(fd, &magic)) {
342      ErrorMessageF("drmGetMagic failed\n");
343      goto handle_error;
344   }
345
346   version = drmGetVersion(fd);
347   if (version) {
348      drm_version.major = version->version_major;
349      drm_version.minor = version->version_minor;
350      drm_version.patch = version->version_patchlevel;
351      drmFreeVersion(version);
352   }
353   else {
354      drm_version.major = -1;
355      drm_version.minor = -1;
356      drm_version.patch = -1;
357   }
358
359   if (newlyopened && !XF86DRIAuthConnection(dpy, scrn, magic)) {
360      ErrorMessageF("XF86DRIAuthConnection failed\n");
361      goto handle_error;
362   }
363
364   /* Get device name (like "tdfx") and the ddx version numbers.
365    * We'll check the version in each DRI driver's "createNewScreen"
366    * function. */
367   if (!XF86DRIGetClientDriverName(dpy, scrn,
368                                   &ddx_version.major,
369                                   &ddx_version.minor,
370                                   &ddx_version.patch, &driverName)) {
371      ErrorMessageF("XF86DRIGetClientDriverName failed\n");
372      goto handle_error;
373   }
374
375   Xfree(driverName);           /* No longer needed. */
376
377   /*
378    * Get device-specific info.  pDevPriv will point to a struct
379    * (such as DRIRADEONRec in xfree86/driver/ati/radeon_dri.h) that
380    * has information about the screen size, depth, pitch, ancilliary
381    * buffers, DRM mmap handles, etc.
382    */
383   if (!XF86DRIGetDeviceInfo(dpy, scrn, &hFB, &junk,
384                             &framebuffer.size, &framebuffer.stride,
385                             &framebuffer.dev_priv_size,
386                             &framebuffer.dev_priv)) {
387      ErrorMessageF("XF86DRIGetDeviceInfo failed");
388      goto handle_error;
389   }
390
391   framebuffer.width = DisplayWidth(dpy, scrn);
392   framebuffer.height = DisplayHeight(dpy, scrn);
393
394   /* Map the framebuffer region. */
395   status = drmMap(fd, hFB, framebuffer.size,
396                   (drmAddressPtr) & framebuffer.base);
397   if (status != 0) {
398      ErrorMessageF("drmMap of framebuffer failed (%s)", strerror(-status));
399      goto handle_error;
400   }
401
402   /* Map the SAREA region.  Further mmap regions may be setup in
403    * each DRI driver's "createNewScreen" function.
404    */
405   status = drmMap(fd, hSAREA, SAREA_MAX, &pSAREA);
406   if (status != 0) {
407      ErrorMessageF("drmMap of SAREA failed (%s)", strerror(-status));
408      goto handle_error;
409   }
410
411   psp = (*psc->legacy->createNewScreen) (scrn,
412                                          &ddx_version,
413                                          &dri_version,
414                                          &drm_version,
415                                          &framebuffer,
416                                          pSAREA,
417                                          fd,
418                                          loader_extensions,
419                                          &driver_configs, psc);
420
421   if (psp == NULL) {
422      ErrorMessageF("Calling driver entry point failed");
423      goto handle_error;
424   }
425
426   psc->configs = driConvertConfigs(psc->core, psc->configs, driver_configs);
427   psc->visuals = driConvertConfigs(psc->core, psc->visuals, driver_configs);
428
429   psc->driver_configs = driver_configs;
430
431   /* Visuals with depth != screen depth are subject to automatic compositing
432    * in the X server, so DRI1 can't render to them properly. Mark them as
433    * non-conformant to prevent apps from picking them up accidentally.
434    */
435   for (visual = psc->visuals; visual; visual = visual->next) {
436      XVisualInfo template;
437      XVisualInfo *visuals;
438      int num_visuals;
439      long mask;
440
441      template.visualid = visual->visualID;
442      mask = VisualIDMask;
443      visuals = XGetVisualInfo(dpy, mask, &template, &num_visuals);
444
445      if (visuals) {
446         if (num_visuals > 0 && visuals->depth != DefaultDepth(dpy, scrn))
447            visual->visualRating = GLX_NON_CONFORMANT_CONFIG;
448
449         XFree(visuals);
450      }
451   }
452
453   return psp;
454
455 handle_error:
456   if (pSAREA != MAP_FAILED)
457      drmUnmap(pSAREA, SAREA_MAX);
458
459   if (framebuffer.base != MAP_FAILED)
460      drmUnmap((drmAddress) framebuffer.base, framebuffer.size);
461
462   if (framebuffer.dev_priv != NULL)
463      Xfree(framebuffer.dev_priv);
464
465   if (fd >= 0)
466      drmCloseOnce(fd);
467
468   XF86DRICloseConnection(dpy, scrn);
469
470   ErrorMessageF("reverting to software direct rendering\n");
471
472   return NULL;
473}
474
475static void
476driDestroyContext(__GLXDRIcontext * context,
477                  __GLXscreenConfigs * psc, Display * dpy)
478{
479   __GLXDRIcontextPrivate *pcp = (__GLXDRIcontextPrivate *) context;
480
481   (*psc->core->destroyContext) (pcp->driContext);
482
483   XF86DRIDestroyContext(psc->dpy, psc->scr, pcp->hwContextID);
484   Xfree(pcp);
485}
486
487static Bool
488driBindContext(__GLXDRIcontext * context,
489               __GLXDRIdrawable * draw, __GLXDRIdrawable * read)
490{
491   __GLXDRIcontextPrivate *pcp = (__GLXDRIcontextPrivate *) context;
492   const __DRIcoreExtension *core = pcp->psc->core;
493
494   return (*core->bindContext) (pcp->driContext,
495                                draw->driDrawable, read->driDrawable);
496}
497
498static void
499driUnbindContext(__GLXDRIcontext * context)
500{
501   __GLXDRIcontextPrivate *pcp = (__GLXDRIcontextPrivate *) context;
502   const __DRIcoreExtension *core = pcp->psc->core;
503
504   (*core->unbindContext) (pcp->driContext);
505}
506
507static __GLXDRIcontext *
508driCreateContext(__GLXscreenConfigs * psc,
509                 const __GLcontextModes * mode,
510                 GLXContext gc, GLXContext shareList, int renderType)
511{
512   __GLXDRIcontextPrivate *pcp, *pcp_shared;
513   drm_context_t hwContext;
514   __DRIcontext *shared = NULL;
515   __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) mode;
516
517   if (!psc || !psc->driScreen)
518      return NULL;
519
520   if (shareList) {
521      pcp_shared = (__GLXDRIcontextPrivate *) shareList->driContext;
522      shared = pcp_shared->driContext;
523   }
524
525   pcp = Xmalloc(sizeof *pcp);
526   if (pcp == NULL)
527      return NULL;
528
529   pcp->psc = psc;
530   if (!XF86DRICreateContextWithConfig(psc->dpy, psc->scr,
531                                       mode->visualID,
532                                       &pcp->hwContextID, &hwContext)) {
533      Xfree(pcp);
534      return NULL;
535   }
536
537   pcp->driContext =
538      (*psc->legacy->createNewContext) (psc->__driScreen,
539                                        config->driConfig,
540                                        renderType, shared, hwContext, pcp);
541   if (pcp->driContext == NULL) {
542      XF86DRIDestroyContext(psc->dpy, psc->scr, pcp->hwContextID);
543      Xfree(pcp);
544      return NULL;
545   }
546
547   pcp->base.destroyContext = driDestroyContext;
548   pcp->base.bindContext = driBindContext;
549   pcp->base.unbindContext = driUnbindContext;
550
551   return &pcp->base;
552}
553
554static void
555driDestroyDrawable(__GLXDRIdrawable * pdraw)
556{
557   __GLXscreenConfigs *psc = pdraw->psc;
558
559   (*psc->core->destroyDrawable) (pdraw->driDrawable);
560   XF86DRIDestroyDrawable(psc->dpy, psc->scr, pdraw->drawable);
561   Xfree(pdraw);
562}
563
564static __GLXDRIdrawable *
565driCreateDrawable(__GLXscreenConfigs * psc,
566                  XID xDrawable,
567                  GLXDrawable drawable, const __GLcontextModes * modes)
568{
569   __GLXDRIdrawable *pdraw;
570   drm_drawable_t hwDrawable;
571   void *empty_attribute_list = NULL;
572   __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) modes;
573
574   /* Old dri can't handle GLX 1.3+ drawable constructors. */
575   if (xDrawable != drawable)
576      return NULL;
577
578   pdraw = Xmalloc(sizeof(*pdraw));
579   if (!pdraw)
580      return NULL;
581
582   pdraw->drawable = drawable;
583   pdraw->psc = psc;
584
585   if (!XF86DRICreateDrawable(psc->dpy, psc->scr, drawable, &hwDrawable)) {
586      Xfree(pdraw);
587      return NULL;
588   }
589
590   /* Create a new drawable */
591   pdraw->driDrawable =
592      (*psc->legacy->createNewDrawable) (psc->__driScreen,
593                                         config->driConfig,
594                                         hwDrawable,
595                                         GLX_WINDOW_BIT,
596                                         empty_attribute_list, pdraw);
597
598   if (!pdraw->driDrawable) {
599      XF86DRIDestroyDrawable(psc->dpy, psc->scr, drawable);
600      Xfree(pdraw);
601      return NULL;
602   }
603
604   pdraw->destroyDrawable = driDestroyDrawable;
605
606   return pdraw;
607}
608
609static int64_t
610driSwapBuffers(__GLXDRIdrawable * pdraw, int64_t unused1, int64_t unused2,
611	       int64_t unused3)
612{
613   (*pdraw->psc->core->swapBuffers) (pdraw->driDrawable);
614   return 0;
615}
616
617static void
618driCopySubBuffer(__GLXDRIdrawable * pdraw,
619                 int x, int y, int width, int height)
620{
621   (*pdraw->psc->driCopySubBuffer->copySubBuffer) (pdraw->driDrawable,
622                                                   x, y, width, height);
623}
624
625static void
626driDestroyScreen(__GLXscreenConfigs * psc)
627{
628   /* Free the direct rendering per screen data */
629   if (psc->__driScreen)
630      (*psc->core->destroyScreen) (psc->__driScreen);
631   psc->__driScreen = NULL;
632   if (psc->driver)
633      dlclose(psc->driver);
634}
635
636static __GLXDRIscreen *
637driCreateScreen(__GLXscreenConfigs * psc, int screen,
638                __GLXdisplayPrivate * priv)
639{
640   __GLXDRIdisplayPrivate *pdp;
641   __GLXDRIscreen *psp;
642   const __DRIextension **extensions;
643   char *driverName;
644   int i;
645
646   psp = Xcalloc(1, sizeof *psp);
647   if (psp == NULL)
648      return NULL;
649
650   /* Initialize per screen dynamic client GLX extensions */
651   psc->ext_list_first_time = GL_TRUE;
652
653   if (!driGetDriverName(priv->dpy, screen, &driverName)) {
654      Xfree(psp);
655      return NULL;
656   }
657
658   psc->driver = driOpenDriver(driverName);
659   Xfree(driverName);
660   if (psc->driver == NULL) {
661      Xfree(psp);
662      return NULL;
663   }
664
665   extensions = dlsym(psc->driver, __DRI_DRIVER_EXTENSIONS);
666   if (extensions == NULL) {
667      ErrorMessageF("driver exports no extensions (%s)\n", dlerror());
668      Xfree(psp);
669      return NULL;
670   }
671
672   for (i = 0; extensions[i]; i++) {
673      if (strcmp(extensions[i]->name, __DRI_CORE) == 0)
674	 psc->core = (__DRIcoreExtension *) extensions[i];
675      if (strcmp(extensions[i]->name, __DRI_LEGACY) == 0)
676	 psc->legacy = (__DRIlegacyExtension *) extensions[i];
677   }
678
679   if (psc->core == NULL || psc->legacy == NULL) {
680      Xfree(psp);
681      return NULL;
682   }
683
684   pdp = (__GLXDRIdisplayPrivate *) priv->driDisplay;
685   psc->__driScreen = CallCreateNewScreen(psc->dpy, screen, psc, pdp);
686   if (psc->__driScreen == NULL) {
687      dlclose(psc->driver);
688      Xfree(psp);
689      return NULL;
690   }
691
692   driBindExtensions(psc);
693   driBindCommonExtensions(psc);
694
695   if (psc->driCopySubBuffer)
696      psp->copySubBuffer = driCopySubBuffer;
697
698   psp->destroyScreen = driDestroyScreen;
699   psp->createContext = driCreateContext;
700   psp->createDrawable = driCreateDrawable;
701   psp->swapBuffers = driSwapBuffers;
702   psp->waitX = NULL;
703   psp->waitGL = NULL;
704
705   return psp;
706}
707
708/* Called from __glXFreeDisplayPrivate.
709 */
710static void
711driDestroyDisplay(__GLXDRIdisplay * dpy)
712{
713   Xfree(dpy);
714}
715
716/*
717 * Allocate, initialize and return a __DRIdisplayPrivate object.
718 * This is called from __glXInitialize() when we are given a new
719 * display pointer.
720 */
721_X_HIDDEN __GLXDRIdisplay *
722driCreateDisplay(Display * dpy)
723{
724   __GLXDRIdisplayPrivate *pdpyp;
725   int eventBase, errorBase;
726   int major, minor, patch;
727
728   if (!XF86DRIQueryExtension(dpy, &eventBase, &errorBase)) {
729      return NULL;
730   }
731
732   if (!XF86DRIQueryVersion(dpy, &major, &minor, &patch)) {
733      return NULL;
734   }
735
736   pdpyp = Xmalloc(sizeof *pdpyp);
737   if (!pdpyp) {
738      return NULL;
739   }
740
741   pdpyp->driMajor = major;
742   pdpyp->driMinor = minor;
743   pdpyp->driPatch = patch;
744
745   pdpyp->base.destroyDisplay = driDestroyDisplay;
746   pdpyp->base.createScreen = driCreateScreen;
747
748   return &pdpyp->base;
749}
750
751#endif /* GLX_DIRECT_RENDERING */
752