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>
42 #include "glxclient.h"
48 #include <sys/types.h>
58 #ifdef BUILT_IN_DRI_DRIVER
60 extern void *__driCreateScreen(Display
*dpy
, int scrn
, __DRIscreen
*psc
,
61 int numConfigs
, __GLXvisualConfig
*config
);
64 #else /* BUILT_IN_DRI_DRIVER */
67 #ifndef DEFAULT_DRIVER_DIR
68 /* this is normally defined in the Imakefile */
69 #define DEFAULT_DRIVER_DIR "/usr/X11R6/lib/modules/dri"
72 static __DRIdriver
*Drivers
= NULL
;
79 static void InfoMessageF(const char *f
, ...)
84 if ((env
= getenv("LIBGL_DEBUG")) && strstr(env
, "verbose")) {
85 fprintf(stderr
, "libGL: ");
87 vfprintf(stderr
, f
, args
);
92 static void ErrorMessageF(const char *f
, ...)
96 if (getenv("LIBGL_DEBUG")) {
97 fprintf(stderr
, "libGL error: ");
99 vfprintf(stderr
, f
, args
);
106 * We'll save a pointer to this function when we couldn't find a
107 * direct rendering driver for a given screen.
109 static void *DummyCreateScreen(Display
*dpy
, int scrn
, __DRIscreen
*psc
,
110 int numConfigs
, __GLXvisualConfig
*config
)
123 * Extract the ith directory path out of a colon-separated list of paths. No
124 * more than \c dirLen characters, including the terminating \c NUL, will be
127 * \param index Index of path to extract (starting at zero)
128 * \param paths The colon-separated list of paths
129 * \param dirLen Maximum length of result to store in \c dir
130 * \param dir Buffer to hold the extracted directory path
133 * The number of characters that would have been written to \c dir had there
134 * been enough room. This does not include the terminating \c NUL. When
135 * extraction fails, zero will be returned.
138 * It seems like this function could be rewritten to use \c strchr.
141 ExtractDir(int index
, const char *paths
, int dirLen
, char *dir
)
144 const char *start
, *end
;
154 else if (*start
== 0) {
155 /* end of string and couldn't find ith colon */
164 while (*start
== ':')
167 /* find next colon, or end of string */
169 while (*end
!= ':' && *end
!= 0) {
173 /* copy string between <start> and <end> into result string */
175 if (len
> dirLen
- 1)
177 strncpy(dir
, start
, len
);
180 return( end
- start
);
185 * Try to \c dlopen the named driver.
187 * This function adds the "_dri.so" suffix to the driver name and searches the
188 * directories specified by the \c LIBGL_DRIVERS_PATH environment variable in
189 * order to find the driver.
191 * \param driverName - a name like "tdfx", "i810", "mga", etc.
194 * A handle from \c dlopen, or \c NULL if driver file not found.
196 static __DRIdriver
*OpenDriver(const char *driverName
)
198 char *libPaths
= NULL
;
203 /* First, search Drivers list to see if we've already opened this driver */
204 for (driver
= Drivers
; driver
; driver
= driver
->next
) {
205 if (strcmp(driver
->name
, driverName
) == 0) {
211 if (geteuid() == getuid()) {
212 /* don't allow setuid apps to use LIBGL_DRIVERS_PATH */
213 libPaths
= getenv("LIBGL_DRIVERS_PATH");
215 libPaths
= getenv("LIBGL_DRIVERS_DIR"); /* deprecated */
218 libPaths
= DEFAULT_DRIVER_DIR
;
220 for ( i
= 0 ; ExtractDir(i
, libPaths
, 1000, libDir
) != 0 ; i
++ ) {
221 char realDriverName
[200];
225 if ( handle
== NULL
) {
226 snprintf(realDriverName
, 200, "%s/%s_dri.so", libDir
, driverName
);
227 InfoMessageF("OpenDriver: trying %s\n", realDriverName
);
228 handle
= dlopen(realDriverName
, RTLD_NOW
| RTLD_GLOBAL
);
231 if ( handle
!= NULL
) {
232 /* allocate __DRIdriver struct */
233 driver
= (__DRIdriver
*) Xmalloc(sizeof(__DRIdriver
));
235 return NULL
; /* out of memory! */
236 /* init the struct */
237 driver
->name
= __glXstrdup(driverName
);
240 return NULL
; /* out of memory! */
243 driver
->createScreenFunc
= (CreateScreenFunc
)
244 dlsym(handle
, "__driCreateScreen");
245 driver
->createNewScreenFunc
= (CreateNewScreenFunc
)
246 dlsym(handle
, "__driCreateNewScreen");
248 if ( (driver
->createScreenFunc
== NULL
)
249 && (driver
->createNewScreenFunc
== NULL
) ) {
250 /* If the driver doesn't have this symbol then something's
251 * really, really wrong.
253 ErrorMessageF("Neither __driCreateScreen or __driCreateNewScreen "
254 "are defined in %s_dri.so!\n", driverName
);
259 driver
->handle
= handle
;
260 /* put at head of linked list */
261 driver
->next
= Drivers
;
266 ErrorMessageF("dlopen %s failed (%s)\n", realDriverName
, dlerror());
270 ErrorMessageF("unable to find driver: %s_dri.so\n", driverName
);
276 * Given a display pointer and screen number, determine the name of
277 * the DRI driver for the screen. (I.e. "r128", "tdfx", etc).
278 * Return True for success, False for failure.
280 static Bool
GetDriverName(Display
*dpy
, int scrNum
, char **driverName
)
284 int driverMajor
, driverMinor
, driverPatch
;
288 if (!XF86DRIQueryDirectRenderingCapable(dpy
, scrNum
, &directCapable
)) {
289 ErrorMessageF("XF86DRIQueryDirectRenderingCapable failed\n");
292 if (!directCapable
) {
293 ErrorMessageF("XF86DRIQueryDirectRenderingCapable returned false\n");
297 b
= XF86DRIGetClientDriverName(dpy
, scrNum
, &driverMajor
, &driverMinor
,
298 &driverPatch
, driverName
);
300 ErrorMessageF("Cannot determine driver name for screen %d\n", scrNum
);
304 InfoMessageF("XF86DRIGetClientDriverName: %d.%d.%d %s (screen %d)\n",
305 driverMajor
, driverMinor
, driverPatch
, *driverName
, scrNum
);
312 * Given a display pointer and screen number, return a __DRIdriver handle.
313 * Return NULL if anything goes wrong.
315 __DRIdriver
*driGetDriver(Display
*dpy
, int scrNum
)
318 if (GetDriverName(dpy
, scrNum
, &driverName
)) {
320 ret
= OpenDriver(driverName
);
330 * Exported function for querying the DRI driver for a given screen.
332 * The returned char pointer points to a static array that will be
333 * overwritten by subsequent calls.
335 const char *glXGetScreenDriver (Display
*dpy
, int scrNum
) {
338 if (GetDriverName(dpy
, scrNum
, &driverName
)) {
342 len
= strlen (driverName
);
345 memcpy (ret
, driverName
, len
+1);
354 * Exported function for obtaining a driver's option list (UTF-8 encoded XML).
356 * The returned char pointer points directly into the driver. Therefore
357 * it should be treated as a constant.
359 * If the driver was not found or does not support configuration NULL is
362 * Note: The driver remains opened after this function returns.
364 const char *glXGetDriverConfig (const char *driverName
) {
365 __DRIdriver
*driver
= OpenDriver (driverName
);
367 return dlsym (driver
->handle
, "__driConfigOptions");
373 #endif /* BUILT_IN_DRI_DRIVER */
376 /* This function isn't currently used.
378 static void driDestroyDisplay(Display
*dpy
, void *private)
380 __DRIdisplayPrivate
*pdpyp
= (__DRIdisplayPrivate
*)private;
383 const int numScreens
= ScreenCount(dpy
);
385 for (i
= 0; i
< numScreens
; i
++) {
386 if (pdpyp
->libraryHandles
[i
])
387 dlclose(pdpyp
->libraryHandles
[i
]);
389 Xfree(pdpyp
->libraryHandles
);
396 * Allocate, initialize and return a __DRIdisplayPrivate object.
397 * This is called from __glXInitialize() when we are given a new
400 void *driCreateDisplay(Display
*dpy
, __DRIdisplay
*pdisp
)
402 const int numScreens
= ScreenCount(dpy
);
403 __DRIdisplayPrivate
*pdpyp
;
404 int eventBase
, errorBase
;
405 int major
, minor
, patch
;
408 /* Initialize these fields to NULL in case we fail.
409 * If we don't do this we may later get segfaults trying to free random
410 * addresses when the display is closed.
412 pdisp
->private = NULL
;
413 pdisp
->destroyDisplay
= NULL
;
414 pdisp
->createScreen
= NULL
;
416 if (!XF86DRIQueryExtension(dpy
, &eventBase
, &errorBase
)) {
420 if (!XF86DRIQueryVersion(dpy
, &major
, &minor
, &patch
)) {
424 pdpyp
= (__DRIdisplayPrivate
*)Xmalloc(sizeof(__DRIdisplayPrivate
));
429 pdpyp
->driMajor
= major
;
430 pdpyp
->driMinor
= minor
;
431 pdpyp
->driPatch
= patch
;
433 pdisp
->destroyDisplay
= driDestroyDisplay
;
435 /* allocate array of pointers to createScreen funcs */
436 pdisp
->createScreen
= (CreateScreenFunc
*) Xmalloc(numScreens
* sizeof(void *));
437 if (!pdisp
->createScreen
) {
442 /* allocate array of pointers to createScreen funcs */
443 pdisp
->createNewScreen
= (CreateNewScreenFunc
*) Xmalloc(numScreens
* sizeof(void *));
444 if (!pdisp
->createNewScreen
) {
445 Xfree(pdisp
->createScreen
);
450 /* allocate array of library handles */
451 pdpyp
->libraryHandles
= (void **) Xmalloc(numScreens
* sizeof(void*));
452 if (!pdpyp
->libraryHandles
) {
453 Xfree(pdisp
->createNewScreen
);
454 Xfree(pdisp
->createScreen
);
459 #ifdef BUILT_IN_DRI_DRIVER
460 /* we'll statically bind to the built-in __driCreateScreen function */
461 for (scrn
= 0; scrn
< numScreens
; scrn
++) {
462 pdisp
->createScreen
[scrn
] = __driCreateScreen
;
463 pdisp
->createNewScreen
[scrn
] = NULL
;
464 pdpyp
->libraryHandles
[scrn
] = NULL
;
468 /* dynamically discover DRI drivers for all screens, saving each
469 * driver's "__driCreateScreen" function pointer. That's the bootstrap
470 * entrypoint for all DRI drivers.
472 for (scrn
= 0; scrn
< numScreens
; scrn
++) {
473 __DRIdriver
*driver
= driGetDriver(dpy
, scrn
);
475 pdisp
->createScreen
[scrn
] = driver
->createScreenFunc
;
476 pdisp
->createNewScreen
[scrn
] = driver
->createNewScreenFunc
;
477 pdpyp
->libraryHandles
[scrn
] = driver
->handle
;
480 pdisp
->createScreen
[scrn
] = DummyCreateScreen
;
481 pdisp
->createNewScreen
[scrn
] = NULL
;
482 pdpyp
->libraryHandles
[scrn
] = NULL
;
487 return (void *)pdpyp
;
490 #endif /* GLX_DIRECT_RENDERING */