Merge branch 'mesa_7_7_branch'
[mesa.git] / src / glx / x11 / dri_glx.c
1 /**************************************************************************
2
3 Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
4 All Rights Reserved.
5
6 Permission is hereby granted, free of charge, to any person obtaining a
7 copy of this software and associated documentation files (the
8 "Software"), to deal in the Software without restriction, including
9 without limitation the rights to use, copy, modify, merge, publish,
10 distribute, sub license, and/or sell copies of the Software, and to
11 permit persons to whom the Software is furnished to do so, subject to
12 the following conditions:
13
14 The above copyright notice and this permission notice (including the
15 next paragraph) shall be included in all copies or substantial portions
16 of the Software.
17
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
22 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 SOFTWARE 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 "glcontextmodes.h"
42 #include "xf86dri.h"
43 #include "dri2.h"
44 #include "sarea.h"
45 #include <dlfcn.h>
46 #include <sys/types.h>
47 #include <sys/mman.h>
48 #include "xf86drm.h"
49 #include "dri_common.h"
50
51 typedef struct __GLXDRIdisplayPrivateRec __GLXDRIdisplayPrivate;
52 typedef struct __GLXDRIcontextPrivateRec __GLXDRIcontextPrivate;
53
54 struct __GLXDRIdisplayPrivateRec
55 {
56 __GLXDRIdisplay base;
57
58 /*
59 ** XFree86-DRI version information
60 */
61 int driMajor;
62 int driMinor;
63 int driPatch;
64 };
65
66 struct __GLXDRIcontextPrivateRec
67 {
68 __GLXDRIcontext base;
69 __DRIcontext *driContext;
70 XID hwContextID;
71 __GLXscreenConfigs *psc;
72 };
73
74 /*
75 * Given a display pointer and screen number, determine the name of
76 * the DRI driver for the screen. (I.e. "r128", "tdfx", etc).
77 * Return True for success, False for failure.
78 */
79 static Bool
80 driGetDriverName(Display * dpy, int scrNum, char **driverName)
81 {
82 int directCapable;
83 Bool b;
84 int event, error;
85 int driverMajor, driverMinor, driverPatch;
86
87 *driverName = NULL;
88
89 if (XF86DRIQueryExtension(dpy, &event, &error)) { /* DRI1 */
90 if (!XF86DRIQueryDirectRenderingCapable(dpy, scrNum, &directCapable)) {
91 ErrorMessageF("XF86DRIQueryDirectRenderingCapable failed\n");
92 return False;
93 }
94 if (!directCapable) {
95 ErrorMessageF("XF86DRIQueryDirectRenderingCapable returned false\n");
96 return False;
97 }
98
99 b = XF86DRIGetClientDriverName(dpy, scrNum, &driverMajor, &driverMinor,
100 &driverPatch, driverName);
101 if (!b) {
102 ErrorMessageF("Cannot determine driver name for screen %d\n",
103 scrNum);
104 return False;
105 }
106
107 InfoMessageF("XF86DRIGetClientDriverName: %d.%d.%d %s (screen %d)\n",
108 driverMajor, driverMinor, driverPatch, *driverName,
109 scrNum);
110
111 return True;
112 }
113 else if (DRI2QueryExtension(dpy, &event, &error)) { /* DRI2 */
114 char *dev;
115 Bool ret = DRI2Connect(dpy, RootWindow(dpy, scrNum), driverName, &dev);
116
117 if (ret)
118 Xfree(dev);
119
120 return ret;
121 }
122
123 return False;
124 }
125
126 /*
127 * Exported function for querying the DRI driver for a given screen.
128 *
129 * The returned char pointer points to a static array that will be
130 * overwritten by subsequent calls.
131 */
132 PUBLIC const char *
133 glXGetScreenDriver(Display * dpy, int scrNum)
134 {
135 static char ret[32];
136 char *driverName;
137 if (driGetDriverName(dpy, scrNum, &driverName)) {
138 int len;
139 if (!driverName)
140 return NULL;
141 len = strlen(driverName);
142 if (len >= 31)
143 return NULL;
144 memcpy(ret, driverName, len + 1);
145 Xfree(driverName);
146 return ret;
147 }
148 return NULL;
149 }
150
151 /*
152 * Exported function for obtaining a driver's option list (UTF-8 encoded XML).
153 *
154 * The returned char pointer points directly into the driver. Therefore
155 * it should be treated as a constant.
156 *
157 * If the driver was not found or does not support configuration NULL is
158 * returned.
159 *
160 * Note: The driver remains opened after this function returns.
161 */
162 PUBLIC const char *
163 glXGetDriverConfig(const char *driverName)
164 {
165 void *handle = driOpenDriver(driverName);
166 if (handle)
167 return dlsym(handle, "__driConfigOptions");
168 else
169 return NULL;
170 }
171
172 #ifdef XDAMAGE_1_1_INTERFACE
173
174 static GLboolean
175 has_damage_post(Display * dpy)
176 {
177 static GLboolean inited = GL_FALSE;
178 static GLboolean has_damage;
179
180 if (!inited) {
181 int major, minor;
182
183 if (XDamageQueryVersion(dpy, &major, &minor) &&
184 major == 1 && minor >= 1) {
185 has_damage = GL_TRUE;
186 }
187 else {
188 has_damage = GL_FALSE;
189 }
190 inited = GL_TRUE;
191 }
192
193 return has_damage;
194 }
195
196 static void
197 __glXReportDamage(__DRIdrawable * driDraw,
198 int x, int y,
199 drm_clip_rect_t * rects, int num_rects,
200 GLboolean front_buffer, void *loaderPrivate)
201 {
202 XRectangle *xrects;
203 XserverRegion region;
204 int i;
205 int x_off, y_off;
206 __GLXDRIdrawable *glxDraw = loaderPrivate;
207 __GLXscreenConfigs *psc = glxDraw->psc;
208 Display *dpy = psc->dpy;
209 Drawable drawable;
210
211 if (!has_damage_post(dpy))
212 return;
213
214 if (front_buffer) {
215 x_off = x;
216 y_off = y;
217 drawable = RootWindow(dpy, psc->scr);
218 }
219 else {
220 x_off = 0;
221 y_off = 0;
222 drawable = glxDraw->xDrawable;
223 }
224
225 xrects = malloc(sizeof(XRectangle) * num_rects);
226 if (xrects == NULL)
227 return;
228
229 for (i = 0; i < num_rects; i++) {
230 xrects[i].x = rects[i].x1 + x_off;
231 xrects[i].y = rects[i].y1 + y_off;
232 xrects[i].width = rects[i].x2 - rects[i].x1;
233 xrects[i].height = rects[i].y2 - rects[i].y1;
234 }
235 region = XFixesCreateRegion(dpy, xrects, num_rects);
236 free(xrects);
237 XDamageAdd(dpy, drawable, region);
238 XFixesDestroyRegion(dpy, region);
239 }
240
241 static const __DRIdamageExtension damageExtension = {
242 {__DRI_DAMAGE, __DRI_DAMAGE_VERSION},
243 __glXReportDamage,
244 };
245
246 #endif
247
248 static GLboolean
249 __glXDRIGetDrawableInfo(__DRIdrawable * drawable,
250 unsigned int *index, unsigned int *stamp,
251 int *X, int *Y, int *W, int *H,
252 int *numClipRects, drm_clip_rect_t ** pClipRects,
253 int *backX, int *backY,
254 int *numBackClipRects,
255 drm_clip_rect_t ** pBackClipRects,
256 void *loaderPrivate)
257 {
258 __GLXDRIdrawable *glxDraw = loaderPrivate;
259 __GLXscreenConfigs *psc = glxDraw->psc;
260 Display *dpy = psc->dpy;
261
262 return XF86DRIGetDrawableInfo(dpy, psc->scr, glxDraw->drawable,
263 index, stamp, X, Y, W, H,
264 numClipRects, pClipRects,
265 backX, backY,
266 numBackClipRects, pBackClipRects);
267 }
268
269 static const __DRIgetDrawableInfoExtension getDrawableInfoExtension = {
270 {__DRI_GET_DRAWABLE_INFO, __DRI_GET_DRAWABLE_INFO_VERSION},
271 __glXDRIGetDrawableInfo
272 };
273
274 static const __DRIextension *loader_extensions[] = {
275 &systemTimeExtension.base,
276 &getDrawableInfoExtension.base,
277 #ifdef XDAMAGE_1_1_INTERFACE
278 &damageExtension.base,
279 #endif
280 NULL
281 };
282
283 /**
284 * Perform the required libGL-side initialization and call the client-side
285 * driver's \c __driCreateNewScreen function.
286 *
287 * \param dpy Display pointer.
288 * \param scrn Screen number on the display.
289 * \param psc DRI screen information.
290 * \param driDpy DRI display information.
291 * \param createNewScreen Pointer to the client-side driver's
292 * \c __driCreateNewScreen function.
293 * \returns A pointer to the \c __DRIscreen structure returned by
294 * the client-side driver on success, or \c NULL on failure.
295 */
296 static void *
297 CallCreateNewScreen(Display * dpy, int scrn, __GLXscreenConfigs * psc,
298 __GLXDRIdisplayPrivate * driDpy)
299 {
300 void *psp = NULL;
301 drm_handle_t hSAREA;
302 drmAddress pSAREA = MAP_FAILED;
303 char *BusID;
304 __DRIversion ddx_version;
305 __DRIversion dri_version;
306 __DRIversion drm_version;
307 __DRIframebuffer framebuffer;
308 int fd = -1;
309 int status;
310
311 drm_magic_t magic;
312 drmVersionPtr version;
313 int newlyopened;
314 char *driverName;
315 drm_handle_t hFB;
316 int junk;
317 const __DRIconfig **driver_configs;
318 __GLcontextModes *visual;
319
320 /* DRI protocol version. */
321 dri_version.major = driDpy->driMajor;
322 dri_version.minor = driDpy->driMinor;
323 dri_version.patch = driDpy->driPatch;
324
325 framebuffer.base = MAP_FAILED;
326 framebuffer.dev_priv = NULL;
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
476 static void
477 driDestroyContext(__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
488 static Bool
489 driBindContext(__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
499 static void
500 driUnbindContext(__GLXDRIcontext * context)
501 {
502 __GLXDRIcontextPrivate *pcp = (__GLXDRIcontextPrivate *) context;
503 const __DRIcoreExtension *core = pcp->psc->core;
504
505 (*core->unbindContext) (pcp->driContext);
506 }
507
508 static __GLXDRIcontext *
509 driCreateContext(__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
555 static void
556 driDestroyDrawable(__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
565 static __GLXDRIdrawable *
566 driCreateDrawable(__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
610 static int64_t
611 driSwapBuffers(__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
618 static void
619 driCopySubBuffer(__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
626 static void
627 driDestroyScreen(__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
637 static __GLXDRIscreen *
638 driCreateScreen(__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 */
711 static void
712 driDestroyDisplay(__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 *
723 driCreateDisplay(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 */