2b43a74e66a1eaf4ec705913f083813b229f268f
[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 <unistd.h>
38 #include <X11/Xlibint.h>
39 #include <X11/extensions/Xext.h>
40 #include <X11/extensions/extutil.h>
41 #include "glheader.h"
42 #include "glxclient.h"
43 #include "xf86dri.h"
44 #include "sarea.h"
45 #include <stdio.h>
46 #include <dlfcn.h>
47 #include <sys/types.h>
48 #include <stdarg.h>
49 #include "glcontextmodes.h"
50 #include <sys/mman.h>
51 #include "xf86drm.h"
52
53
54 #ifndef RTLD_NOW
55 #define RTLD_NOW 0
56 #endif
57 #ifndef RTLD_GLOBAL
58 #define RTLD_GLOBAL 0
59 #endif
60
61 typedef struct __GLXDRIdisplayPrivateRec __GLXDRIdisplayPrivate;
62 struct __GLXDRIdisplayPrivateRec {
63 __GLXDRIdisplay base;
64
65 /*
66 ** XFree86-DRI version information
67 */
68 int driMajor;
69 int driMinor;
70 int driPatch;
71 };
72
73 #ifndef DEFAULT_DRIVER_DIR
74 /* this is normally defined in Mesa/configs/default with DRI_DRIVER_SEARCH_PATH */
75 #define DEFAULT_DRIVER_DIR "/usr/X11R6/lib/modules/dri"
76 #endif
77
78 static void InfoMessageF(const char *f, ...)
79 {
80 va_list args;
81 const char *env;
82
83 if ((env = getenv("LIBGL_DEBUG")) && strstr(env, "verbose")) {
84 fprintf(stderr, "libGL: ");
85 va_start(args, f);
86 vfprintf(stderr, f, args);
87 va_end(args);
88 }
89 }
90
91 /**
92 * Print error to stderr, unless LIBGL_DEBUG=="quiet".
93 */
94 static void ErrorMessageF(const char *f, ...)
95 {
96 va_list args;
97 const char *env;
98
99 if ((env = getenv("LIBGL_DEBUG")) && !strstr(env, "quiet")) {
100 fprintf(stderr, "libGL error: ");
101 va_start(args, f);
102 vfprintf(stderr, f, args);
103 va_end(args);
104 }
105 }
106
107
108 /**
109 * Versioned name of the expected \c __driCreateNewScreen function.
110 *
111 * The version of the last incompatible loader/driver inteface change is
112 * appended to the name of the \c __driCreateNewScreen function. This
113 * prevents loaders from trying to load drivers that are too old.
114 */
115 static const char createNewScreenName[] = __DRI_CREATE_NEW_SCREEN_STRING;
116
117
118 /**
119 * Try to \c dlopen the named driver.
120 *
121 * This function adds the "_dri.so" suffix to the driver name and searches the
122 * directories specified by the \c LIBGL_DRIVERS_PATH environment variable in
123 * order to find the driver.
124 *
125 * \param driverName - a name like "tdfx", "i810", "mga", etc.
126 *
127 * \returns
128 * A handle from \c dlopen, or \c NULL if driver file not found.
129 */
130 static void *OpenDriver(const char *driverName)
131 {
132 void *glhandle, *handle;
133 const char *libPaths, *p, *next;
134 char realDriverName[200];
135 int len;
136
137 /* Attempt to make sure libGL symbols will be visible to the driver */
138 glhandle = dlopen("libGL.so.1", RTLD_NOW | RTLD_GLOBAL);
139
140 libPaths = DEFAULT_DRIVER_DIR;
141 if (geteuid() == getuid()) {
142 /* don't allow setuid apps to use LIBGL_DRIVERS_PATH */
143 libPaths = getenv("LIBGL_DRIVERS_PATH");
144 if (!libPaths)
145 libPaths = getenv("LIBGL_DRIVERS_DIR"); /* deprecated */
146 }
147
148 handle = NULL;
149 for (p = libPaths; *p; p = next) {
150 next = strchr(p, ':');
151 if (next == NULL) {
152 len = strlen(p);
153 next = p + len;
154 } else {
155 len = next - p;
156 next++;
157 }
158
159 #ifdef GLX_USE_TLS
160 snprintf(realDriverName, sizeof realDriverName,
161 "%.*s/tls/%s_dri.so", len, p, driverName);
162 InfoMessageF("OpenDriver: trying %s\n", realDriverName);
163 handle = dlopen(realDriverName, RTLD_NOW | RTLD_GLOBAL);
164 #endif
165
166 if ( handle == NULL ) {
167 snprintf(realDriverName, sizeof realDriverName,
168 "%.*s/%s_dri.so", len, p, driverName);
169 InfoMessageF("OpenDriver: trying %s\n", realDriverName);
170 handle = dlopen(realDriverName, RTLD_NOW | RTLD_GLOBAL);
171 }
172
173 if ( handle != NULL )
174 break;
175 else
176 ErrorMessageF("dlopen %s failed (%s)\n", realDriverName, dlerror());
177 }
178
179 if (!handle)
180 ErrorMessageF("unable to load driver: %s_dri.so\n", driverName);
181
182 if (glhandle)
183 dlclose(glhandle);
184
185 return handle;
186 }
187
188
189 /*
190 * Given a display pointer and screen number, determine the name of
191 * the DRI driver for the screen. (I.e. "r128", "tdfx", etc).
192 * Return True for success, False for failure.
193 */
194 static Bool GetDriverName(Display *dpy, int scrNum, char **driverName)
195 {
196 int directCapable;
197 Bool b;
198 int driverMajor, driverMinor, driverPatch;
199
200 *driverName = NULL;
201
202 if (!XF86DRIQueryDirectRenderingCapable(dpy, scrNum, &directCapable)) {
203 ErrorMessageF("XF86DRIQueryDirectRenderingCapable failed\n");
204 return False;
205 }
206 if (!directCapable) {
207 ErrorMessageF("XF86DRIQueryDirectRenderingCapable returned false\n");
208 return False;
209 }
210
211 b = XF86DRIGetClientDriverName(dpy, scrNum, &driverMajor, &driverMinor,
212 &driverPatch, driverName);
213 if (!b) {
214 ErrorMessageF("Cannot determine driver name for screen %d\n", scrNum);
215 return False;
216 }
217
218 InfoMessageF("XF86DRIGetClientDriverName: %d.%d.%d %s (screen %d)\n",
219 driverMajor, driverMinor, driverPatch, *driverName, scrNum);
220
221 return True;
222 }
223
224
225 /*
226 * Given a display pointer and screen number, return a __DRIdriver handle.
227 * Return NULL if anything goes wrong.
228 */
229 static void *driGetDriver(Display *dpy, int scrNum)
230 {
231 char *driverName;
232 void *ret;
233
234 if (GetDriverName(dpy, scrNum, &driverName)) {
235 ret = OpenDriver(driverName);
236 if (driverName)
237 Xfree(driverName);
238 return ret;
239 }
240 return NULL;
241 }
242
243 /*
244 * Exported function for querying the DRI driver for a given screen.
245 *
246 * The returned char pointer points to a static array that will be
247 * overwritten by subsequent calls.
248 */
249 PUBLIC const char *glXGetScreenDriver (Display *dpy, int scrNum) {
250 static char ret[32];
251 char *driverName;
252 if (GetDriverName(dpy, scrNum, &driverName)) {
253 int len;
254 if (!driverName)
255 return NULL;
256 len = strlen (driverName);
257 if (len >= 31)
258 return NULL;
259 memcpy (ret, driverName, len+1);
260 Xfree(driverName);
261 return ret;
262 }
263 return NULL;
264 }
265
266
267 /*
268 * Exported function for obtaining a driver's option list (UTF-8 encoded XML).
269 *
270 * The returned char pointer points directly into the driver. Therefore
271 * it should be treated as a constant.
272 *
273 * If the driver was not found or does not support configuration NULL is
274 * returned.
275 *
276 * Note: The driver remains opened after this function returns.
277 */
278 PUBLIC const char *glXGetDriverConfig (const char *driverName) {
279 void *handle = OpenDriver (driverName);
280 if (handle)
281 return dlsym (handle, "__driConfigOptions");
282 else
283 return NULL;
284 }
285
286 static void
287 filter_modes( __GLcontextModes ** server_modes,
288 const __GLcontextModes * driver_modes )
289 {
290 __GLcontextModes * m;
291 __GLcontextModes ** prev_next;
292 const __GLcontextModes * check;
293
294 if (driver_modes == NULL) {
295 fprintf(stderr, "libGL warning: 3D driver returned no fbconfigs.\n");
296 return;
297 }
298
299 /* For each mode in server_modes, check to see if a matching mode exists
300 * in driver_modes. If not, then the mode is not available.
301 */
302
303 prev_next = server_modes;
304 for ( m = *prev_next ; m != NULL ; m = *prev_next ) {
305 GLboolean do_delete = GL_TRUE;
306
307 for ( check = driver_modes ; check != NULL ; check = check->next ) {
308 if ( _gl_context_modes_are_same( m, check ) ) {
309 do_delete = GL_FALSE;
310 break;
311 }
312 }
313
314 /* The 3D has to support all the modes that match the GLX visuals
315 * sent from the X server.
316 */
317 if ( do_delete && (m->visualID != 0) ) {
318 do_delete = GL_FALSE;
319
320 /* don't warn for this visual (Novell #247471 / X.Org #6689) */
321 if (m->visualRating != GLX_NON_CONFORMANT_CONFIG) {
322 fprintf(stderr, "libGL warning: 3D driver claims to not "
323 "support visual 0x%02x\n", m->visualID);
324 }
325 }
326
327 if ( do_delete ) {
328 *prev_next = m->next;
329
330 m->next = NULL;
331 _gl_context_modes_destroy( m );
332 }
333 else {
334 prev_next = & m->next;
335 }
336 }
337 }
338
339 #ifdef XDAMAGE_1_1_INTERFACE
340 static GLboolean has_damage_post(Display *dpy)
341 {
342 static GLboolean inited = GL_FALSE;
343 static GLboolean has_damage;
344
345 if (!inited) {
346 int major, minor;
347
348 if (XDamageQueryVersion(dpy, &major, &minor) &&
349 major == 1 && minor >= 1)
350 {
351 has_damage = GL_TRUE;
352 } else {
353 has_damage = GL_FALSE;
354 }
355 inited = GL_TRUE;
356 }
357
358 return has_damage;
359 }
360 #endif /* XDAMAGE_1_1_INTERFACE */
361
362 static void __glXReportDamage(__DRIdrawable *driDraw,
363 int x, int y,
364 drm_clip_rect_t *rects, int num_rects,
365 GLboolean front_buffer)
366 {
367 #ifdef XDAMAGE_1_1_INTERFACE
368 XRectangle *xrects;
369 XserverRegion region;
370 int i;
371 int x_off, y_off;
372 __GLXdrawable *glxDraw =
373 containerOf(driDraw, __GLXdrawable, driDrawable);
374 __GLXscreenConfigs *psc = glxDraw->psc;
375 Display *dpy = psc->dpy;
376 Drawable drawable;
377
378 if (!has_damage_post(dpy))
379 return;
380
381 if (front_buffer) {
382 x_off = x;
383 y_off = y;
384 drawable = RootWindow(dpy, psc->scr);
385 } else{
386 x_off = 0;
387 y_off = 0;
388 drawable = glxDraw->drawable;
389 }
390
391 xrects = malloc(sizeof(XRectangle) * num_rects);
392 if (xrects == NULL)
393 return;
394
395 for (i = 0; i < num_rects; i++) {
396 xrects[i].x = rects[i].x1 + x_off;
397 xrects[i].y = rects[i].y1 + y_off;
398 xrects[i].width = rects[i].x2 - rects[i].x1;
399 xrects[i].height = rects[i].y2 - rects[i].y1;
400 }
401 region = XFixesCreateRegion(dpy, xrects, num_rects);
402 free(xrects);
403 XDamageAdd(dpy, drawable, region);
404 XFixesDestroyRegion(dpy, region);
405 #endif
406 }
407
408 static GLboolean
409 __glXDRIGetDrawableInfo(__DRIdrawable *drawable,
410 unsigned int *index, unsigned int *stamp,
411 int *X, int *Y, int *W, int *H,
412 int *numClipRects, drm_clip_rect_t ** pClipRects,
413 int *backX, int *backY,
414 int *numBackClipRects, drm_clip_rect_t **pBackClipRects)
415 {
416 __GLXdrawable *glxDraw =
417 containerOf(drawable, __GLXdrawable, driDrawable);
418 __GLXscreenConfigs *psc = glxDraw->psc;
419 Display *dpy = psc->dpy;
420
421 return XF86DRIGetDrawableInfo(dpy, psc->scr, glxDraw->drawable,
422 index, stamp, X, Y, W, H,
423 numClipRects, pClipRects,
424 backX, backY,
425 numBackClipRects, pBackClipRects);
426 }
427
428
429 /**
430 * Table of functions exported by the loader to the driver.
431 */
432 static const __DRIcontextModesExtension contextModesExtension = {
433 { __DRI_CONTEXT_MODES, __DRI_CONTEXT_MODES_VERSION },
434 _gl_context_modes_create,
435 _gl_context_modes_destroy,
436 };
437
438 static const __DRIsystemTimeExtension systemTimeExtension = {
439 { __DRI_SYSTEM_TIME, __DRI_SYSTEM_TIME_VERSION },
440 __glXGetUST,
441 __driGetMscRateOML,
442 };
443
444 static const __DRIgetDrawableInfoExtension getDrawableInfoExtension = {
445 { __DRI_GET_DRAWABLE_INFO, __DRI_GET_DRAWABLE_INFO_VERSION },
446 __glXDRIGetDrawableInfo
447 };
448
449 static const __DRIdamageExtension damageExtension = {
450 { __DRI_DAMAGE, __DRI_DAMAGE_VERSION },
451 __glXReportDamage,
452 };
453
454 static const __DRIextension *loader_extensions[] = {
455 &contextModesExtension.base,
456 &systemTimeExtension.base,
457 &getDrawableInfoExtension.base,
458 &damageExtension.base,
459 NULL
460 };
461
462
463 /**
464 * Perform the required libGL-side initialization and call the client-side
465 * driver's \c __driCreateNewScreen function.
466 *
467 * \param dpy Display pointer.
468 * \param scrn Screen number on the display.
469 * \param psc DRI screen information.
470 * \param driDpy DRI display information.
471 * \param createNewScreen Pointer to the client-side driver's
472 * \c __driCreateNewScreen function.
473 * \returns A pointer to the \c __DRIscreenPrivate structure returned by
474 * the client-side driver on success, or \c NULL on failure.
475 *
476 * \todo This function needs to be modified to remove context-modes from the
477 * list stored in the \c __GLXscreenConfigsRec to match the list
478 * returned by the client-side driver.
479 */
480 static void *
481 CallCreateNewScreen(Display *dpy, int scrn, __GLXscreenConfigs *psc,
482 __GLXDRIdisplayPrivate * driDpy,
483 PFNCREATENEWSCREENFUNC createNewScreen)
484 {
485 void *psp = NULL;
486 #ifndef GLX_USE_APPLEGL
487 drm_handle_t hSAREA;
488 drmAddress pSAREA = MAP_FAILED;
489 char *BusID;
490 __DRIversion ddx_version;
491 __DRIversion dri_version;
492 __DRIversion drm_version;
493 __DRIframebuffer framebuffer;
494 int fd = -1;
495 int status;
496 const char * err_msg;
497 const char * err_extra;
498
499 dri_version.major = driDpy->driMajor;
500 dri_version.minor = driDpy->driMinor;
501 dri_version.patch = driDpy->driPatch;
502
503
504 err_msg = "XF86DRIOpenConnection";
505 err_extra = NULL;
506
507 framebuffer.base = MAP_FAILED;
508 framebuffer.dev_priv = NULL;
509
510 if (XF86DRIOpenConnection(dpy, scrn, &hSAREA, &BusID)) {
511 int newlyopened;
512 fd = drmOpenOnce(NULL,BusID, &newlyopened);
513 Xfree(BusID); /* No longer needed */
514
515 err_msg = "open DRM";
516 err_extra = strerror( -fd );
517
518 if (fd >= 0) {
519 drm_magic_t magic;
520
521 err_msg = "drmGetMagic";
522 err_extra = NULL;
523
524 if (!drmGetMagic(fd, &magic)) {
525 drmVersionPtr version = drmGetVersion(fd);
526 if (version) {
527 drm_version.major = version->version_major;
528 drm_version.minor = version->version_minor;
529 drm_version.patch = version->version_patchlevel;
530 drmFreeVersion(version);
531 }
532 else {
533 drm_version.major = -1;
534 drm_version.minor = -1;
535 drm_version.patch = -1;
536 }
537
538 err_msg = "XF86DRIAuthConnection";
539 if (!newlyopened || XF86DRIAuthConnection(dpy, scrn, magic)) {
540 char *driverName;
541
542 /*
543 * Get device name (like "tdfx") and the ddx version
544 * numbers. We'll check the version in each DRI driver's
545 * "createNewScreen" function.
546 */
547 err_msg = "XF86DRIGetClientDriverName";
548 if (XF86DRIGetClientDriverName(dpy, scrn,
549 &ddx_version.major,
550 &ddx_version.minor,
551 &ddx_version.patch,
552 &driverName)) {
553 drm_handle_t hFB;
554 int junk;
555
556 /* No longer needed. */
557 Xfree( driverName );
558
559
560 /*
561 * Get device-specific info. pDevPriv will point to a struct
562 * (such as DRIRADEONRec in xfree86/driver/ati/radeon_dri.h)
563 * that has information about the screen size, depth, pitch,
564 * ancilliary buffers, DRM mmap handles, etc.
565 */
566 err_msg = "XF86DRIGetDeviceInfo";
567 if (XF86DRIGetDeviceInfo(dpy, scrn,
568 &hFB,
569 &junk,
570 &framebuffer.size,
571 &framebuffer.stride,
572 &framebuffer.dev_priv_size,
573 &framebuffer.dev_priv)) {
574 framebuffer.width = DisplayWidth(dpy, scrn);
575 framebuffer.height = DisplayHeight(dpy, scrn);
576
577 /*
578 * Map the framebuffer region.
579 */
580 status = drmMap(fd, hFB, framebuffer.size,
581 (drmAddressPtr)&framebuffer.base);
582
583 err_msg = "drmMap of framebuffer";
584 err_extra = strerror( -status );
585
586 if ( status == 0 ) {
587 /*
588 * Map the SAREA region. Further mmap regions
589 * may be setup in each DRI driver's
590 * "createNewScreen" function.
591 */
592 status = drmMap(fd, hSAREA, SAREA_MAX,
593 &pSAREA);
594
595 err_msg = "drmMap of sarea";
596 err_extra = strerror( -status );
597
598 if ( status == 0 ) {
599 __GLcontextModes * driver_modes = NULL;
600
601 err_msg = "InitDriver";
602 err_extra = NULL;
603 psp = (*createNewScreen)(scrn,
604 &psc->driScreen,
605 & ddx_version,
606 & dri_version,
607 & drm_version,
608 & framebuffer,
609 pSAREA,
610 fd,
611 loader_extensions,
612 & driver_modes );
613
614 filter_modes(&psc->configs, driver_modes);
615 filter_modes(&psc->visuals, driver_modes);
616 _gl_context_modes_destroy(driver_modes);
617 }
618 }
619 }
620 }
621 }
622 }
623 }
624 }
625
626 if ( psp == NULL ) {
627 if ( pSAREA != MAP_FAILED ) {
628 (void)drmUnmap(pSAREA, SAREA_MAX);
629 }
630
631 if ( framebuffer.base != MAP_FAILED ) {
632 (void)drmUnmap((drmAddress)framebuffer.base, framebuffer.size);
633 }
634
635 if ( framebuffer.dev_priv != NULL ) {
636 Xfree(framebuffer.dev_priv);
637 }
638
639 if ( fd >= 0 ) {
640 (void)drmCloseOnce(fd);
641 }
642
643 (void)XF86DRICloseConnection(dpy, scrn);
644
645 if ( err_extra != NULL ) {
646 fprintf(stderr, "libGL error: %s failed (%s)\n", err_msg,
647 err_extra);
648 }
649 else {
650 fprintf(stderr, "libGL error: %s failed\n", err_msg );
651 }
652
653 fprintf(stderr, "libGL error: reverting to (slow) indirect rendering\n");
654 }
655 #endif /* !GLX_USE_APPLEGL */
656
657 return psp;
658 }
659
660
661 static void driCreateContext(__GLXscreenConfigs *psc,
662 const __GLcontextModes *mode,
663 GLXContext gc,
664 GLXContext shareList, int renderType)
665 {
666 drm_context_t hwContext;
667 __DRIcontext *shared;
668
669 if (psc && psc->driScreen.private) {
670 shared = (shareList != NULL) ? &shareList->driContext : NULL;
671
672 if (!XF86DRICreateContextWithConfig(psc->dpy, psc->scr,
673 mode->visualID,
674 &gc->hwContextID, &hwContext))
675 /* gah, handle this better */
676 return;
677
678 gc->driContext.private =
679 (*psc->driScreen.createNewContext)( &psc->driScreen,
680 mode, renderType,
681 shared,
682 hwContext,
683 &gc->driContext );
684 if (gc->driContext.private) {
685 gc->isDirect = GL_TRUE;
686 gc->screen = mode->screen;
687 gc->psc = psc;
688 gc->mode = mode;
689 }
690 else {
691 XF86DRIDestroyContext(psc->dpy, psc->scr, gc->hwContextID);
692 }
693 }
694 }
695
696 static void driDestroyScreen(__GLXscreenConfigs *psc)
697 {
698 /* Free the direct rendering per screen data */
699 if (psc->driScreen.private)
700 (*psc->driScreen.destroyScreen)(&psc->driScreen);
701 psc->driScreen.private = NULL;
702 if (psc->drawHash)
703 __glxHashDestroy(psc->drawHash);
704 if (psc->driver)
705 dlclose(psc->driver);
706 }
707
708 static void driCreateScreen(__GLXscreenConfigs *psc, int screen,
709 __GLXdisplayPrivate *priv)
710 {
711 PFNCREATENEWSCREENFUNC createNewScreen;
712 __GLXDRIdisplayPrivate *pdp;
713
714 if (priv->driDisplay == NULL)
715 return;
716
717 /* Create drawable hash */
718 psc->drawHash = __glxHashCreate();
719 if ( psc->drawHash == NULL )
720 return;
721
722 /* Initialize per screen dynamic client GLX extensions */
723 psc->ext_list_first_time = GL_TRUE;
724
725 psc->driver = driGetDriver(priv->dpy, screen);
726 createNewScreen = dlsym(psc->driver, createNewScreenName);
727 if (createNewScreenName == NULL)
728 return;
729
730 pdp = (__GLXDRIdisplayPrivate *) priv->driDisplay;
731 psc->driScreen.private =
732 CallCreateNewScreen(psc->dpy, screen, psc, pdp, createNewScreen);
733 if (psc->driScreen.private != NULL)
734 __glXScrEnableDRIExtension(psc);
735
736 psc->driDestroyScreen = driDestroyScreen;
737 psc->driCreateContext = driCreateContext;
738 }
739
740 /* Called from __glXFreeDisplayPrivate.
741 */
742 static void driDestroyDisplay(__GLXDRIdisplay *dpy)
743 {
744 Xfree(dpy);
745 }
746
747 /*
748 * Allocate, initialize and return a __DRIdisplayPrivate object.
749 * This is called from __glXInitialize() when we are given a new
750 * display pointer.
751 */
752 __GLXDRIdisplay *driCreateDisplay(Display *dpy)
753 {
754 __GLXDRIdisplayPrivate *pdpyp;
755 int eventBase, errorBase;
756 int major, minor, patch;
757
758 if (!XF86DRIQueryExtension(dpy, &eventBase, &errorBase)) {
759 return NULL;
760 }
761
762 if (!XF86DRIQueryVersion(dpy, &major, &minor, &patch)) {
763 return NULL;
764 }
765
766 pdpyp = Xmalloc(sizeof *pdpyp);
767 if (!pdpyp) {
768 return NULL;
769 }
770
771 pdpyp->driMajor = major;
772 pdpyp->driMinor = minor;
773 pdpyp->driPatch = patch;
774
775 pdpyp->base.destroyDisplay = driDestroyDisplay;
776 pdpyp->base.createScreen = driCreateScreen;
777
778 return (void *)pdpyp;
779 }
780
781 #endif /* GLX_DIRECT_RENDERING */