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