dri_glx.c revision 86d98fa4a2dfdae75e6ecd9a7e6e73d4183075a0
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   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   /* Initialize per screen dynamic client GLX extensions */
652   psc->ext_list_first_time = GL_TRUE;
653
654   if (!driGetDriverName(priv->dpy, screen, &driverName)) {
655      Xfree(psp);
656      return NULL;
657   }
658
659   psc->driver = driOpenDriver(driverName);
660   Xfree(driverName);
661   if (psc->driver == NULL) {
662      Xfree(psp);
663      return NULL;
664   }
665
666   extensions = dlsym(psc->driver, __DRI_DRIVER_EXTENSIONS);
667   if (extensions == NULL) {
668      ErrorMessageF("driver exports no extensions (%s)\n", dlerror());
669      Xfree(psp);
670      return NULL;
671   }
672
673   for (i = 0; extensions[i]; i++) {
674      if (strcmp(extensions[i]->name, __DRI_CORE) == 0)
675	 psc->core = (__DRIcoreExtension *) extensions[i];
676      if (strcmp(extensions[i]->name, __DRI_LEGACY) == 0)
677	 psc->legacy = (__DRIlegacyExtension *) extensions[i];
678   }
679
680   if (psc->core == NULL || psc->legacy == NULL) {
681      Xfree(psp);
682      return NULL;
683   }
684
685   pdp = (__GLXDRIdisplayPrivate *) priv->driDisplay;
686   psc->__driScreen = CallCreateNewScreen(psc->dpy, screen, psc, pdp);
687   if (psc->__driScreen == NULL) {
688      dlclose(psc->driver);
689      Xfree(psp);
690      return NULL;
691   }
692
693   driBindExtensions(psc);
694   driBindCommonExtensions(psc);
695
696   if (psc->driCopySubBuffer)
697      psp->copySubBuffer = driCopySubBuffer;
698
699   psp->destroyScreen = driDestroyScreen;
700   psp->createContext = driCreateContext;
701   psp->createDrawable = driCreateDrawable;
702   psp->swapBuffers = driSwapBuffers;
703   psp->waitX = NULL;
704   psp->waitGL = NULL;
705
706   return psp;
707}
708
709/* Called from __glXFreeDisplayPrivate.
710 */
711static void
712driDestroyDisplay(__GLXDRIdisplay * dpy)
713{
714   Xfree(dpy);
715}
716
717/*
718 * Allocate, initialize and return a __DRIdisplayPrivate object.
719 * This is called from __glXInitialize() when we are given a new
720 * display pointer.
721 */
722_X_HIDDEN __GLXDRIdisplay *
723driCreateDisplay(Display * dpy)
724{
725   __GLXDRIdisplayPrivate *pdpyp;
726   int eventBase, errorBase;
727   int major, minor, patch;
728
729   if (!XF86DRIQueryExtension(dpy, &eventBase, &errorBase)) {
730      return NULL;
731   }
732
733   if (!XF86DRIQueryVersion(dpy, &major, &minor, &patch)) {
734      return NULL;
735   }
736
737   pdpyp = Xmalloc(sizeof *pdpyp);
738   if (!pdpyp) {
739      return NULL;
740   }
741
742   pdpyp->driMajor = major;
743   pdpyp->driMinor = minor;
744   pdpyp->driPatch = patch;
745
746   pdpyp->base.destroyDisplay = driDestroyDisplay;
747   pdpyp->base.createScreen = driCreateScreen;
748
749   return &pdpyp->base;
750}
751
752#endif /* GLX_DIRECT_RENDERING */
753