1 /**************************************************************************
3 Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
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:
14 The above copyright notice and this permission notice (including the
15 next paragraph) shall be included in all copies or substantial portions
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.
26 **************************************************************************/
27 /* $XFree86: xc/lib/GL/dri/dri_glx.c,v 1.14 2003/07/16 00:54:00 dawes Exp $ */
31 * Kevin E. Martin <kevin@precisioninsight.com>
32 * Brian Paul <brian@precisioninsight.com>
36 #ifdef GLX_DIRECT_RENDERING
39 #include <X11/Xlibint.h>
40 #include <X11/extensions/Xext.h>
41 #include <X11/extensions/extutil.h>
42 #include "glxclient.h"
48 #include <sys/types.h>
59 #ifndef DEFAULT_DRIVER_DIR
60 /* this is normally defined in Mesa/configs/default with DRI_DRIVER_SEARCH_PATH */
61 #define DEFAULT_DRIVER_DIR "/usr/X11R6/lib/modules/dri"
64 static __DRIdriver
*Drivers
= NULL
;
71 static void InfoMessageF(const char *f
, ...)
76 if ((env
= getenv("LIBGL_DEBUG")) && strstr(env
, "verbose")) {
77 fprintf(stderr
, "libGL: ");
79 vfprintf(stderr
, f
, args
);
84 static void ErrorMessageF(const char *f
, ...)
88 if (getenv("LIBGL_DEBUG")) {
89 fprintf(stderr
, "libGL error: ");
91 vfprintf(stderr
, f
, args
);
98 * Extract the ith directory path out of a colon-separated list of paths. No
99 * more than \c dirLen characters, including the terminating \c NUL, will be
102 * \param index Index of path to extract (starting at zero)
103 * \param paths The colon-separated list of paths
104 * \param dirLen Maximum length of result to store in \c dir
105 * \param dir Buffer to hold the extracted directory path
108 * The number of characters that would have been written to \c dir had there
109 * been enough room. This does not include the terminating \c NUL. When
110 * extraction fails, zero will be returned.
113 * It seems like this function could be rewritten to use \c strchr.
116 ExtractDir(int index
, const char *paths
, int dirLen
, char *dir
)
119 const char *start
, *end
;
129 else if (*start
== 0) {
130 /* end of string and couldn't find ith colon */
139 while (*start
== ':')
142 /* find next colon, or end of string */
144 while (*end
!= ':' && *end
!= 0) {
148 /* copy string between <start> and <end> into result string */
150 if (len
> dirLen
- 1)
152 strncpy(dir
, start
, len
);
155 return( end
- start
);
160 * Versioned name of the expected \c __driCreateNewScreen function.
162 * The version of the last incompatible loader/driver inteface change is
163 * appended to the name of the \c __driCreateNewScreen function. This
164 * prevents loaders from trying to load drivers that are too old.
167 * Create a macro or something so that this is automatically updated.
169 static const char createNewScreenName
[] = "__driCreateNewScreen_20050727";
173 * Try to \c dlopen the named driver.
175 * This function adds the "_dri.so" suffix to the driver name and searches the
176 * directories specified by the \c LIBGL_DRIVERS_PATH environment variable in
177 * order to find the driver.
179 * \param driverName - a name like "tdfx", "i810", "mga", etc.
182 * A handle from \c dlopen, or \c NULL if driver file not found.
184 static __DRIdriver
*OpenDriver(const char *driverName
)
186 void *glhandle
= NULL
;
187 char *libPaths
= NULL
;
192 /* First, search Drivers list to see if we've already opened this driver */
193 for (driver
= Drivers
; driver
; driver
= driver
->next
) {
194 if (strcmp(driver
->name
, driverName
) == 0) {
200 /* Attempt to make sure libGL symbols will be visible to the driver */
201 glhandle
= dlopen("libGL.so.1", RTLD_NOW
| RTLD_GLOBAL
);
203 if (geteuid() == getuid()) {
204 /* don't allow setuid apps to use LIBGL_DRIVERS_PATH */
205 libPaths
= getenv("LIBGL_DRIVERS_PATH");
207 libPaths
= getenv("LIBGL_DRIVERS_DIR"); /* deprecated */
210 libPaths
= DEFAULT_DRIVER_DIR
;
212 for ( i
= 0 ; ExtractDir(i
, libPaths
, 1000, libDir
) != 0 ; i
++ ) {
213 char realDriverName
[200];
217 /* If TLS support is enabled, try to open the TLS version of the driver
218 * binary first. If that fails, try the non-TLS version.
221 snprintf(realDriverName
, 200, "%s/tls/%s_dri.so", libDir
, driverName
);
222 InfoMessageF("OpenDriver: trying %s\n", realDriverName
);
223 handle
= dlopen(realDriverName
, RTLD_NOW
| RTLD_GLOBAL
);
226 if ( handle
== NULL
) {
227 snprintf(realDriverName
, 200, "%s/%s_dri.so", libDir
, driverName
);
228 InfoMessageF("OpenDriver: trying %s\n", realDriverName
);
229 handle
= dlopen(realDriverName
, RTLD_NOW
| RTLD_GLOBAL
);
232 if ( handle
!= NULL
) {
233 /* allocate __DRIdriver struct */
234 driver
= (__DRIdriver
*) Xmalloc(sizeof(__DRIdriver
));
236 break; /* out of memory! */
237 /* init the struct */
238 driver
->name
= __glXstrdup(driverName
);
242 break; /* out of memory! */
245 driver
->createNewScreenFunc
= (PFNCREATENEWSCREENFUNC
)
246 dlsym(handle
, createNewScreenName
);
248 if ( driver
->createNewScreenFunc
== NULL
) {
249 /* If the driver doesn't have this symbol then something's
250 * really, really wrong.
252 ErrorMessageF("%s not defined in %s_dri.so!\n"
253 "Your driver may be too old for this libGL.\n",
254 createNewScreenName
, driverName
);
260 driver
->handle
= handle
;
261 /* put at head of linked list */
262 driver
->next
= Drivers
;
267 ErrorMessageF("dlopen %s failed (%s)\n", realDriverName
, dlerror());
272 ErrorMessageF("unable to load driver: %s_dri.so\n", driverName
);
282 * Given a display pointer and screen number, determine the name of
283 * the DRI driver for the screen. (I.e. "r128", "tdfx", etc).
284 * Return True for success, False for failure.
286 static Bool
GetDriverName(Display
*dpy
, int scrNum
, char **driverName
)
290 int driverMajor
, driverMinor
, driverPatch
;
294 if (!XF86DRIQueryDirectRenderingCapable(dpy
, scrNum
, &directCapable
)) {
295 ErrorMessageF("XF86DRIQueryDirectRenderingCapable failed\n");
298 if (!directCapable
) {
299 ErrorMessageF("XF86DRIQueryDirectRenderingCapable returned false\n");
303 b
= XF86DRIGetClientDriverName(dpy
, scrNum
, &driverMajor
, &driverMinor
,
304 &driverPatch
, driverName
);
306 ErrorMessageF("Cannot determine driver name for screen %d\n", scrNum
);
310 InfoMessageF("XF86DRIGetClientDriverName: %d.%d.%d %s (screen %d)\n",
311 driverMajor
, driverMinor
, driverPatch
, *driverName
, scrNum
);
318 * Given a display pointer and screen number, return a __DRIdriver handle.
319 * Return NULL if anything goes wrong.
321 __DRIdriver
*driGetDriver(Display
*dpy
, int scrNum
)
324 if (GetDriverName(dpy
, scrNum
, &driverName
)) {
326 ret
= OpenDriver(driverName
);
336 * Exported function for querying the DRI driver for a given screen.
338 * The returned char pointer points to a static array that will be
339 * overwritten by subsequent calls.
341 const char *glXGetScreenDriver (Display
*dpy
, int scrNum
) {
344 if (GetDriverName(dpy
, scrNum
, &driverName
)) {
348 len
= strlen (driverName
);
351 memcpy (ret
, driverName
, len
+1);
360 * Exported function for obtaining a driver's option list (UTF-8 encoded XML).
362 * The returned char pointer points directly into the driver. Therefore
363 * it should be treated as a constant.
365 * If the driver was not found or does not support configuration NULL is
368 * Note: The driver remains opened after this function returns.
370 const char *glXGetDriverConfig (const char *driverName
) {
371 __DRIdriver
*driver
= OpenDriver (driverName
);
373 return dlsym (driver
->handle
, "__driConfigOptions");
379 /* Called from __glXFreeDisplayPrivate.
381 static void driDestroyDisplay(Display
*dpy
, void *private)
383 __DRIdisplayPrivate
*pdpyp
= (__DRIdisplayPrivate
*)private;
386 const int numScreens
= ScreenCount(dpy
);
388 for (i
= 0; i
< numScreens
; i
++) {
389 if (pdpyp
->libraryHandles
[i
]) {
390 __DRIdriver
*driver
, *prev
;
392 /* Remove driver from Drivers list */
393 for (prev
= NULL
, driver
= Drivers
; driver
;
394 prev
= driver
, driver
= driver
->next
) {
395 if (driver
->handle
== pdpyp
->libraryHandles
[i
]) {
397 prev
->next
= driver
->next
;
399 Drivers
= driver
->next
;
407 dlclose(pdpyp
->libraryHandles
[i
]);
410 Xfree(pdpyp
->libraryHandles
);
417 * Allocate, initialize and return a __DRIdisplayPrivate object.
418 * This is called from __glXInitialize() when we are given a new
421 void *driCreateDisplay(Display
*dpy
, __DRIdisplay
*pdisp
)
423 const int numScreens
= ScreenCount(dpy
);
424 __DRIdisplayPrivate
*pdpyp
;
425 int eventBase
, errorBase
;
426 int major
, minor
, patch
;
429 /* Initialize these fields to NULL in case we fail.
430 * If we don't do this we may later get segfaults trying to free random
431 * addresses when the display is closed.
433 pdisp
->private = NULL
;
434 pdisp
->destroyDisplay
= NULL
;
436 if (!XF86DRIQueryExtension(dpy
, &eventBase
, &errorBase
)) {
440 if (!XF86DRIQueryVersion(dpy
, &major
, &minor
, &patch
)) {
444 pdpyp
= (__DRIdisplayPrivate
*)Xmalloc(sizeof(__DRIdisplayPrivate
));
449 pdpyp
->driMajor
= major
;
450 pdpyp
->driMinor
= minor
;
451 pdpyp
->driPatch
= patch
;
453 pdisp
->destroyDisplay
= driDestroyDisplay
;
455 /* allocate array of pointers to createNewScreen funcs */
456 pdisp
->createNewScreen
= (PFNCREATENEWSCREENFUNC
*)
457 Xmalloc(numScreens
* sizeof(void *));
458 if (!pdisp
->createNewScreen
) {
463 /* allocate array of library handles */
464 pdpyp
->libraryHandles
= (void **) Xmalloc(numScreens
* sizeof(void*));
465 if (!pdpyp
->libraryHandles
) {
466 Xfree(pdisp
->createNewScreen
);
471 /* dynamically discover DRI drivers for all screens, saving each
472 * driver's "__driCreateScreen" function pointer. That's the bootstrap
473 * entrypoint for all DRI drivers.
475 for (scrn
= 0; scrn
< numScreens
; scrn
++) {
476 __DRIdriver
*driver
= driGetDriver(dpy
, scrn
);
478 pdisp
->createNewScreen
[scrn
] = driver
->createNewScreenFunc
;
479 pdpyp
->libraryHandles
[scrn
] = driver
->handle
;
482 pdisp
->createNewScreen
[scrn
] = NULL
;
483 pdpyp
->libraryHandles
[scrn
] = NULL
;
487 return (void *)pdpyp
;
490 #endif /* GLX_DIRECT_RENDERING */