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