#include <unistd.h>
#include <X11/Xlibint.h>
#include <X11/extensions/Xext.h>
-#include "extutil.h"
+#include <X11/extensions/extutil.h>
#include "glxclient.h"
#include "xf86dri.h"
#include "sarea.h"
#define RTLD_GLOBAL 0
#endif
-#ifdef BUILT_IN_DRI_DRIVER
-
-extern void *__driCreateScreen(Display *dpy, int scrn, __DRIscreen *psc,
- int numConfigs, __GLXvisualConfig *config);
-
-
-#else /* BUILT_IN_DRI_DRIVER */
-
#ifndef DEFAULT_DRIVER_DIR
/* this is normally defined in the Imakefile */
}
-/*
- * We'll save a pointer to this function when we couldn't find a
- * direct rendering driver for a given screen.
- */
-static void *DummyCreateScreen(Display *dpy, int scrn, __DRIscreen *psc,
- int numConfigs, __GLXvisualConfig *config)
-{
- (void) dpy;
- (void) scrn;
- (void) psc;
- (void) numConfigs;
- (void) config;
- return NULL;
-}
-
-
-
-/*
- * Extract the ith directory path out of a colon-separated list of
- * paths.
- * Input:
- * index - index of path to extract (starting at zero)
- * paths - the colon-separated list of paths
- * dirLen - max length of result to store in <dir>
- * Output:
- * dir - the extracted directory path, dir[0] will be zero when
- * extraction fails.
+/**
+ * Extract the ith directory path out of a colon-separated list of paths. No
+ * more than \c dirLen characters, including the terminating \c NUL, will be
+ * written to \c dir.
+ *
+ * \param index Index of path to extract (starting at zero)
+ * \param paths The colon-separated list of paths
+ * \param dirLen Maximum length of result to store in \c dir
+ * \param dir Buffer to hold the extracted directory path
+ *
+ * \returns
+ * The number of characters that would have been written to \c dir had there
+ * been enough room. This does not include the terminating \c NUL. When
+ * extraction fails, zero will be returned.
+ *
+ * \todo
+ * It seems like this function could be rewritten to use \c strchr.
*/
-static void ExtractDir(int index, const char *paths, int dirLen, char *dir)
+static size_t
+ExtractDir(int index, const char *paths, int dirLen, char *dir)
{
int i, len;
const char *start, *end;
else if (*start == 0) {
/* end of string and couldn't find ith colon */
dir[0] = 0;
- return;
+ return 0;
}
else {
start++;
len = dirLen - 1;
strncpy(dir, start, len);
dir[len] = 0;
+
+ return( end - start );
}
-/*
- * Try to dlopen() the named driver. This function adds the
- * "_dri.so" suffix to the driver name and searches the
- * directories specified by the LIBGL_DRIVERS_PATH env var
- * in order to find the driver.
- * Input:
- * driverName - a name like "tdfx", "i810", "mga", etc.
- * Return:
- * handle from dlopen, or NULL if driver file not found.
+/**
+ * Versioned name of the expected \c __driCreateNewScreen function.
+ *
+ * The version of the last incompatible loader/driver inteface change is
+ * appended to the name of the \c __driCreateNewScreen function. This
+ * prevents loaders from trying to load drivers that are too old.
+ *
+ * \todo
+ * Create a macro or something so that this is automatically updated.
+ */
+static const char createNewScreenName[] = "__driCreateNewScreen_20050727";
+
+
+/**
+ * Try to \c dlopen the named driver.
+ *
+ * This function adds the "_dri.so" suffix to the driver name and searches the
+ * directories specified by the \c LIBGL_DRIVERS_PATH environment variable in
+ * order to find the driver.
+ *
+ * \param driverName - a name like "tdfx", "i810", "mga", etc.
+ *
+ * \returns
+ * A handle from \c dlopen, or \c NULL if driver file not found.
*/
static __DRIdriver *OpenDriver(const char *driverName)
{
char *libPaths = NULL;
+ char libDir[1000];
int i;
__DRIdriver *driver;
if (!libPaths)
libPaths = DEFAULT_DRIVER_DIR;
- for (i = 0; ; i++) {
- char libDir[1000], realDriverName[200];
- void *handle;
- ExtractDir(i, libPaths, 1000, libDir);
- if (!libDir[0])
- break; /* ran out of paths to search */
- snprintf(realDriverName, 200, "%s/%s_dri.so", libDir, driverName);
+ for ( i = 0 ; ExtractDir(i, libPaths, 1000, libDir) != 0 ; i++ ) {
+ char realDriverName[200];
+ void *handle = NULL;
+
+
+ /* If TLS support is enabled, try to open the TLS version of the driver
+ * binary first. If that fails, try the non-TLS version.
+ */
+#ifdef GLX_USE_TLS
+ snprintf(realDriverName, 200, "%s/tls/%s_dri.so", libDir, driverName);
InfoMessageF("OpenDriver: trying %s\n", realDriverName);
handle = dlopen(realDriverName, RTLD_NOW | RTLD_GLOBAL);
- if (handle) {
+#endif
+
+ if ( handle == NULL ) {
+ snprintf(realDriverName, 200, "%s/%s_dri.so", libDir, driverName);
+ InfoMessageF("OpenDriver: trying %s\n", realDriverName);
+ handle = dlopen(realDriverName, RTLD_NOW | RTLD_GLOBAL);
+ }
+
+ if ( handle != NULL ) {
/* allocate __DRIdriver struct */
driver = (__DRIdriver *) Xmalloc(sizeof(__DRIdriver));
if (!driver)
return NULL; /* out of memory! */
}
- driver->createScreenFunc = (CreateScreenFunc)
- dlsym(handle, "__driCreateScreen");
- driver->createNewScreenFunc = (CreateNewScreenFunc)
- dlsym(handle, "__driCreateNewScreen");
+ driver->createNewScreenFunc = (PFNCREATENEWSCREENFUNC)
+ dlsym(handle, createNewScreenName);
- if ( (driver->createScreenFunc == NULL)
- && (driver->createNewScreenFunc == NULL) ) {
+ if ( driver->createNewScreenFunc == NULL ) {
/* If the driver doesn't have this symbol then something's
* really, really wrong.
*/
- ErrorMessageF("Neither __driCreateScreen or __driCreateNewScreen "
- "are defined in %s_dri.so!\n", driverName);
+ ErrorMessageF("%s not defined in %s_dri.so!\n"
+ "Your driver may be too old for this libGL.\n",
+ createNewScreenName, driverName);
Xfree(driver);
dlclose(handle);
continue;
}
-#endif /* BUILT_IN_DRI_DRIVER */
-
-
/* This function isn't currently used.
*/
static void driDestroyDisplay(Display *dpy, void *private)
*/
pdisp->private = NULL;
pdisp->destroyDisplay = NULL;
- pdisp->createScreen = NULL;
if (!XF86DRIQueryExtension(dpy, &eventBase, &errorBase)) {
return NULL;
pdisp->destroyDisplay = driDestroyDisplay;
- /* allocate array of pointers to createScreen funcs */
- pdisp->createScreen = (CreateScreenFunc *) Xmalloc(numScreens * sizeof(void *));
- if (!pdisp->createScreen) {
- Xfree(pdpyp);
- return NULL;
- }
-
- /* allocate array of pointers to createScreen funcs */
- pdisp->createNewScreen = (CreateNewScreenFunc *) Xmalloc(numScreens * sizeof(void *));
+ /* allocate array of pointers to createNewScreen funcs */
+ pdisp->createNewScreen = (PFNCREATENEWSCREENFUNC *)
+ Xmalloc(numScreens * sizeof(void *));
if (!pdisp->createNewScreen) {
- Xfree(pdisp->createScreen);
Xfree(pdpyp);
return NULL;
}
pdpyp->libraryHandles = (void **) Xmalloc(numScreens * sizeof(void*));
if (!pdpyp->libraryHandles) {
Xfree(pdisp->createNewScreen);
- Xfree(pdisp->createScreen);
Xfree(pdpyp);
return NULL;
}
-#ifdef BUILT_IN_DRI_DRIVER
- /* we'll statically bind to the built-in __driCreateScreen function */
- for (scrn = 0; scrn < numScreens; scrn++) {
- pdisp->createScreen[scrn] = __driCreateScreen;
- pdisp->createNewScreen[scrn] = NULL;
- pdpyp->libraryHandles[scrn] = NULL;
- }
-
-#else
/* dynamically discover DRI drivers for all screens, saving each
* driver's "__driCreateScreen" function pointer. That's the bootstrap
* entrypoint for all DRI drivers.
for (scrn = 0; scrn < numScreens; scrn++) {
__DRIdriver *driver = driGetDriver(dpy, scrn);
if (driver) {
- pdisp->createScreen[scrn] = driver->createScreenFunc;
pdisp->createNewScreen[scrn] = driver->createNewScreenFunc;
pdpyp->libraryHandles[scrn] = driver->handle;
}
else {
- pdisp->createScreen[scrn] = DummyCreateScreen;
pdisp->createNewScreen[scrn] = NULL;
pdpyp->libraryHandles[scrn] = NULL;
}
}
-#endif
return (void *)pdpyp;
}