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 **************************************************************************/
30 * Kevin E. Martin <kevin@precisioninsight.com>
31 * Brian Paul <brian@precisioninsight.com>
35 #ifdef GLX_DIRECT_RENDERING
38 #include <X11/Xlibint.h>
39 #include <X11/extensions/Xext.h>
40 #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
;
67 /** If non-zero, prefer an "egl_foo_dri.so" driver over "foo_dri.so" */
68 static int PreferEGL
= 0;
72 * This may be called by libEGL.so to tell libGL to prefer "egl_" drivers
73 * over regular DRI drivers".
75 void __glXPreferEGL(int state
)
85 static void InfoMessageF(const char *f
, ...)
90 if ((env
= getenv("LIBGL_DEBUG")) && strstr(env
, "verbose")) {
91 fprintf(stderr
, "libGL: ");
93 vfprintf(stderr
, f
, args
);
99 * Print error to stderr, unless LIBGL_DEBUG=="quiet".
101 static void ErrorMessageF(const char *f
, ...)
106 if ((env
= getenv("LIBGL_DEBUG")) && !strstr(env
, "quiet")) {
107 fprintf(stderr
, "libGL error: ");
109 vfprintf(stderr
, f
, args
);
116 * Extract the ith directory path out of a colon-separated list of paths. No
117 * more than \c dirLen characters, including the terminating \c NUL, will be
120 * \param index Index of path to extract (starting at zero)
121 * \param paths The colon-separated list of paths
122 * \param dirLen Maximum length of result to store in \c dir
123 * \param dir Buffer to hold the extracted directory path
126 * The number of characters that would have been written to \c dir had there
127 * been enough room. This does not include the terminating \c NUL. When
128 * extraction fails, zero will be returned.
131 * It seems like this function could be rewritten to use \c strchr.
134 ExtractDir(int index
, const char *paths
, int dirLen
, char *dir
)
137 const char *start
, *end
;
147 else if (*start
== 0) {
148 /* end of string and couldn't find ith colon */
157 while (*start
== ':')
160 /* find next colon, or end of string */
162 while (*end
!= ':' && *end
!= 0) {
166 /* copy string between <start> and <end> into result string */
168 if (len
> dirLen
- 1)
170 strncpy(dir
, start
, len
);
173 return( end
- start
);
178 * Try to dlopen() a driver.
179 * \param libDir the directory to search
180 * \param driverName the name of the driver (such as "r300").
181 * \param tls if true, try to find TLS version of driver
182 * \param preferEGL if true, try to find EGL-specific driver
183 * \return handle from dlopen(), will be NULL if fails.
186 try_open(const char *libDir
, const char *driverName
,
187 GLboolean tls
, GLboolean preferEGL
)
189 const char *tlsDir
= tls
? "/tls/" : "";
190 const char *eglPrefix
= preferEGL
? "egl_" : "";
191 char fullPathName
[200];
194 snprintf(fullPathName
, 200, "%s%s/%s%s_dri.so",
195 libDir
, tlsDir
, eglPrefix
, driverName
);
196 InfoMessageF("OpenDriver: trying %s\n", fullPathName
);
197 handle
= dlopen(fullPathName
, RTLD_NOW
| RTLD_GLOBAL
);
205 * Versioned name of the expected \c __driCreateNewScreen function.
207 * The version of the last incompatible loader/driver inteface change is
208 * appended to the name of the \c __driCreateNewScreen function. This
209 * prevents loaders from trying to load drivers that are too old.
212 * Create a macro or something so that this is automatically updated.
214 static const char createNewScreenName
[] = "__driCreateNewScreen_20050727";
218 * Try to \c dlopen the named driver.
220 * This function adds the "_dri.so" suffix to the driver name and searches the
221 * directories specified by the \c LIBGL_DRIVERS_PATH environment variable in
222 * order to find the driver.
224 * \param driverName - a name like "tdfx", "i810", "mga", etc.
227 * A handle from \c dlopen, or \c NULL if driver file not found.
229 static __DRIdriver
*OpenDriver(const char *driverName
)
231 void *glhandle
= NULL
;
232 char *libPaths
= NULL
;
237 /* First, search Drivers list to see if we've already opened this driver */
238 for (driver
= Drivers
; driver
; driver
= driver
->next
) {
239 if (strcmp(driver
->name
, driverName
) == 0) {
245 /* Attempt to make sure libGL symbols will be visible to the driver */
246 glhandle
= dlopen("libGL.so.1", RTLD_NOW
| RTLD_GLOBAL
);
248 if (geteuid() == getuid()) {
249 /* don't allow setuid apps to use LIBGL_DRIVERS_PATH */
250 libPaths
= getenv("LIBGL_DRIVERS_PATH");
252 libPaths
= getenv("LIBGL_DRIVERS_DIR"); /* deprecated */
255 libPaths
= DEFAULT_DRIVER_DIR
;
257 for ( i
= 0 ; ExtractDir(i
, libPaths
, 1000, libDir
) != 0 ; i
++ ) {
261 handle
= try_open(libDir
, driverName
, GL_FALSE
, GL_TRUE
);
264 handle
= try_open(libDir
, driverName
, GL_TRUE
, GL_FALSE
);
267 handle
= try_open(libDir
, driverName
, GL_FALSE
, GL_FALSE
);
269 if ( handle
!= NULL
) {
270 /* allocate __DRIdriver struct */
271 driver
= (__DRIdriver
*) Xmalloc(sizeof(__DRIdriver
));
273 break; /* out of memory! */
274 /* init the struct */
275 driver
->name
= __glXstrdup(driverName
);
279 break; /* out of memory! */
282 driver
->createNewScreenFunc
= (PFNCREATENEWSCREENFUNC
)
283 dlsym(handle
, createNewScreenName
);
285 if ( driver
->createNewScreenFunc
== NULL
) {
286 /* If the driver doesn't have this symbol then something's
287 * really, really wrong.
289 ErrorMessageF("%s not defined in %s_dri.so!\n"
290 "Your driver may be too old for this libGL.\n",
291 createNewScreenName
, driverName
);
297 driver
->handle
= handle
;
298 /* put at head of linked list */
299 driver
->next
= Drivers
;
304 ErrorMessageF("Unable to find/open driver for %s (%s)\n",
305 driverName
, dlerror());
310 ErrorMessageF("unable to load driver: %s_dri.so\n", driverName
);
320 * Given a display pointer and screen number, determine the name of
321 * the DRI driver for the screen. (I.e. "r128", "tdfx", etc).
322 * Return True for success, False for failure.
324 static Bool
GetDriverName(Display
*dpy
, int scrNum
, char **driverName
)
328 int driverMajor
, driverMinor
, driverPatch
;
332 if (!XF86DRIQueryDirectRenderingCapable(dpy
, scrNum
, &directCapable
)) {
333 ErrorMessageF("XF86DRIQueryDirectRenderingCapable failed\n");
336 if (!directCapable
) {
337 ErrorMessageF("XF86DRIQueryDirectRenderingCapable returned false\n");
341 b
= XF86DRIGetClientDriverName(dpy
, scrNum
, &driverMajor
, &driverMinor
,
342 &driverPatch
, driverName
);
344 ErrorMessageF("Cannot determine driver name for screen %d\n", scrNum
);
348 InfoMessageF("XF86DRIGetClientDriverName: %d.%d.%d %s (screen %d)\n",
349 driverMajor
, driverMinor
, driverPatch
, *driverName
, scrNum
);
356 * Given a display pointer and screen number, return a __DRIdriver handle.
357 * Return NULL if anything goes wrong.
359 __DRIdriver
*driGetDriver(Display
*dpy
, int scrNum
)
362 if (GetDriverName(dpy
, scrNum
, &driverName
)) {
364 ret
= OpenDriver(driverName
);
374 * Exported function for querying the DRI driver for a given screen.
376 * The returned char pointer points to a static array that will be
377 * overwritten by subsequent calls.
379 PUBLIC
const char *glXGetScreenDriver (Display
*dpy
, int scrNum
) {
382 if (GetDriverName(dpy
, scrNum
, &driverName
)) {
386 len
= strlen (driverName
);
389 memcpy (ret
, driverName
, len
+1);
398 * Exported function for obtaining a driver's option list (UTF-8 encoded XML).
400 * The returned char pointer points directly into the driver. Therefore
401 * it should be treated as a constant.
403 * If the driver was not found or does not support configuration NULL is
406 * Note: The driver remains opened after this function returns.
408 PUBLIC
const char *glXGetDriverConfig (const char *driverName
) {
409 __DRIdriver
*driver
= OpenDriver (driverName
);
411 return dlsym (driver
->handle
, "__driConfigOptions");
417 /* Called from __glXFreeDisplayPrivate.
419 static void driDestroyDisplay(Display
*dpy
, void *private)
421 __DRIdisplayPrivate
*pdpyp
= (__DRIdisplayPrivate
*)private;
424 const int numScreens
= ScreenCount(dpy
);
426 for (i
= 0; i
< numScreens
; i
++) {
427 if (pdpyp
->libraryHandles
[i
]) {
428 __DRIdriver
*driver
, *prev
;
430 /* Remove driver from Drivers list */
431 for (prev
= NULL
, driver
= Drivers
; driver
;
432 prev
= driver
, driver
= driver
->next
) {
433 if (driver
->handle
== pdpyp
->libraryHandles
[i
]) {
435 prev
->next
= driver
->next
;
437 Drivers
= driver
->next
;
439 Xfree((void *) driver
->name
);
445 dlclose(pdpyp
->libraryHandles
[i
]);
448 Xfree(pdpyp
->libraryHandles
);
455 * Allocate, initialize and return a __DRIdisplayPrivate object.
456 * This is called from __glXInitialize() when we are given a new
459 void *driCreateDisplay(Display
*dpy
, __DRIdisplay
*pdisp
)
461 const int numScreens
= ScreenCount(dpy
);
462 __DRIdisplayPrivate
*pdpyp
;
463 int eventBase
, errorBase
;
464 int major
, minor
, patch
;
467 /* Initialize these fields to NULL in case we fail.
468 * If we don't do this we may later get segfaults trying to free random
469 * addresses when the display is closed.
471 pdisp
->private = NULL
;
472 pdisp
->destroyDisplay
= NULL
;
474 if (!XF86DRIQueryExtension(dpy
, &eventBase
, &errorBase
)) {
478 if (!XF86DRIQueryVersion(dpy
, &major
, &minor
, &patch
)) {
482 pdpyp
= (__DRIdisplayPrivate
*)Xmalloc(sizeof(__DRIdisplayPrivate
));
487 pdpyp
->driMajor
= major
;
488 pdpyp
->driMinor
= minor
;
489 pdpyp
->driPatch
= patch
;
491 pdisp
->destroyDisplay
= driDestroyDisplay
;
493 /* allocate array of pointers to createNewScreen funcs */
494 pdisp
->createNewScreen
= (PFNCREATENEWSCREENFUNC
*)
495 Xmalloc(numScreens
* sizeof(void *));
496 if (!pdisp
->createNewScreen
) {
501 /* allocate array of library handles */
502 pdpyp
->libraryHandles
= (void **) Xmalloc(numScreens
* sizeof(void*));
503 if (!pdpyp
->libraryHandles
) {
504 Xfree(pdisp
->createNewScreen
);
509 /* dynamically discover DRI drivers for all screens, saving each
510 * driver's "__driCreateScreen" function pointer. That's the bootstrap
511 * entrypoint for all DRI drivers.
513 for (scrn
= 0; scrn
< numScreens
; scrn
++) {
514 __DRIdriver
*driver
= driGetDriver(dpy
, scrn
);
516 pdisp
->createNewScreen
[scrn
] = driver
->createNewScreenFunc
;
517 pdpyp
->libraryHandles
[scrn
] = driver
->handle
;
520 pdisp
->createNewScreen
[scrn
] = NULL
;
521 pdpyp
->libraryHandles
[scrn
] = NULL
;
525 return (void *)pdpyp
;
528 #endif /* GLX_DIRECT_RENDERING */