summaryrefslogtreecommitdiff
path: root/src/egl/main/egldriver.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/egl/main/egldriver.c')
-rw-r--r--src/egl/main/egldriver.c496
1 files changed, 269 insertions, 227 deletions
diff --git a/src/egl/main/egldriver.c b/src/egl/main/egldriver.c
index f56214472e..1e3d7d24aa 100644
--- a/src/egl/main/egldriver.c
+++ b/src/egl/main/egldriver.c
@@ -22,6 +22,7 @@
#include "eglstring.h"
#include "eglsurface.h"
#include "eglimage.h"
+#include "eglmutex.h"
#if defined(_EGL_OS_UNIX)
#include <dlfcn.h>
@@ -31,17 +32,22 @@
#endif
+typedef struct _egl_module {
+ char *Path;
+ void *Handle;
+ _EGLDriver *Driver;
+} _EGLModule;
+
+static _EGL_DECLARE_MUTEX(_eglModuleMutex);
+static _EGLArray *_eglModules;
+
+
/**
* Wrappers for dlopen/dlclose()
*/
#if defined(_EGL_OS_WINDOWS)
-/* XXX Need to decide how to do dynamic name lookup on Windows */
-static const char *DefaultDriverNames[] = {
- "egl_gdi_swrast"
-};
-
typedef HMODULE lib_handle;
static HMODULE
@@ -67,11 +73,6 @@ library_suffix(void)
#elif defined(_EGL_OS_UNIX)
-static const char *DefaultDriverNames[] = {
- "egl_dri2",
- "egl_glx"
-};
-
typedef void * lib_handle;
static void *
@@ -97,13 +98,6 @@ library_suffix(void)
#endif
-#define NUM_PROBE_CACHE_SLOTS 8
-static struct {
- EGLint keys[NUM_PROBE_CACHE_SLOTS];
- const void *values[NUM_PROBE_CACHE_SLOTS];
-} _eglProbeCache;
-
-
/**
* Open the named driver and find its bootstrap function: _eglMain().
*/
@@ -163,85 +157,106 @@ _eglOpenLibrary(const char *driverPath, lib_handle *handle)
/**
- * Load the named driver.
+ * Load a module and create the driver object.
*/
-static _EGLDriver *
-_eglLoadDriver(const char *path, const char *args)
+static EGLBoolean
+_eglLoadModule(_EGLModule *mod)
{
_EGLMain_t mainFunc;
lib_handle lib;
- _EGLDriver *drv = NULL;
+ _EGLDriver *drv;
- mainFunc = _eglOpenLibrary(path, &lib);
+ mainFunc = _eglOpenLibrary(mod->Path, &lib);
if (!mainFunc)
- return NULL;
+ return EGL_FALSE;
- drv = mainFunc(args);
+ drv = mainFunc(NULL);
if (!drv) {
if (lib)
close_library(lib);
- return NULL;
+ return EGL_FALSE;
}
if (!drv->Name) {
- _eglLog(_EGL_WARNING, "Driver loaded from %s has no name", path);
+ _eglLog(_EGL_WARNING, "Driver loaded from %s has no name", mod->Path);
drv->Name = "UNNAMED";
}
- drv->Path = _eglstrdup(path);
- drv->Args = (args) ? _eglstrdup(args) : NULL;
- if (!drv->Path || (args && !drv->Args)) {
- if (drv->Path)
- free((char *) drv->Path);
- if (drv->Args)
- free((char *) drv->Args);
- drv->Unload(drv);
- if (lib)
- close_library(lib);
- return NULL;
- }
+ mod->Handle = (void *) lib;
+ mod->Driver = drv;
+
+ return EGL_TRUE;
+}
- drv->LibHandle = lib;
- return drv;
+/**
+ * Unload a module.
+ */
+static void
+_eglUnloadModule(_EGLModule *mod)
+{
+ /* destroy the driver */
+ if (mod->Driver && mod->Driver->Unload)
+ mod->Driver->Unload(mod->Driver);
+ if (mod->Handle)
+ close_library(mod->Handle);
+
+ mod->Driver = NULL;
+ mod->Handle = NULL;
}
/**
- * Match a display to a preloaded driver.
- *
- * The matching is done by finding the driver with the highest score.
+ * Add a module to the module array.
*/
-_EGLDriver *
-_eglMatchDriver(_EGLDisplay *dpy)
+static _EGLModule *
+_eglAddModule(const char *path)
{
- _EGLDriver *best_drv = NULL;
- EGLint best_score = -1, i;
+ _EGLModule *mod;
+ EGLint i;
- /*
- * this function is called after preloading and the drivers never change
- * after preloading.
- */
- for (i = 0; i < _eglGlobal.NumDrivers; i++) {
- _EGLDriver *drv = _eglGlobal.Drivers[i];
- EGLint score;
-
- score = (drv->Probe) ? drv->Probe(drv, dpy) : 0;
- if (score > best_score) {
- if (best_drv) {
- _eglLog(_EGL_DEBUG, "driver %s has higher score than %s",
- drv->Name, best_drv->Name);
- }
+ if (!_eglModules) {
+ _eglModules = _eglCreateArray("Module", 8);
+ if (!_eglModules)
+ return NULL;
+ }
- best_drv = drv;
- best_score = score;
- /* perfect match */
- if (score >= 100)
- break;
+ /* find duplicates */
+ for (i = 0; i < _eglModules->Size; i++) {
+ mod = _eglModules->Elements[i];
+ if (strcmp(mod->Path, path) == 0)
+ return mod;
+ }
+
+ /* allocate a new one */
+ mod = calloc(1, sizeof(*mod));
+ if (mod) {
+ mod->Path = _eglstrdup(path);
+ if (!mod->Path) {
+ free(mod);
+ mod = NULL;
}
}
+ if (mod) {
+ _eglAppendArray(_eglModules, (void *) mod);
+ _eglLog(_EGL_DEBUG, "added %s to module array", mod->Path);
+ }
- return best_drv;
+ return mod;
+}
+
+
+/**
+ * Free a module.
+ */
+static void
+_eglFreeModule(void *module)
+{
+ _EGLModule *mod = (_EGLModule *) module;
+
+ _eglUnloadModule(mod);
+ free(mod->Path);
+ free(mod);
}
@@ -252,7 +267,6 @@ _eglMatchDriver(_EGLDisplay *dpy)
static EGLBoolean
_eglLoaderFile(const char *dir, size_t len, void *loader_data)
{
- _EGLDriver *drv;
char path[1024];
const char *filename = (const char *) loader_data;
size_t flen = strlen(filename);
@@ -268,9 +282,7 @@ _eglLoaderFile(const char *dir, size_t len, void *loader_data)
len += flen;
path[len] = '\0';
- if (library_suffix() == NULL || strstr(path, library_suffix()))
- drv = _eglLoadDriver(path, NULL);
- else {
+ if (library_suffix()) {
const char *suffix = library_suffix();
size_t slen = strlen(suffix);
const char *p;
@@ -278,19 +290,23 @@ _eglLoaderFile(const char *dir, size_t len, void *loader_data)
p = filename + flen - slen;
need_suffix = (p < filename || strcmp(p, suffix) != 0);
- if (need_suffix && len + slen + 1 <= sizeof(path)) {
+ if (need_suffix) {
+ /* overflow */
+ if (len + slen + 1 > sizeof(path))
+ return EGL_TRUE;
strcpy(path + len, suffix);
- drv = _eglLoadDriver(path, NULL);
- } else {
- drv = NULL;
}
}
- if (!drv)
+
+#if defined(_EGL_OS_UNIX)
+ /* check if the file exists */
+ if (access(path, F_OK))
return EGL_TRUE;
+#endif
- /* remember the driver and stop */
- _eglGlobal.Drivers[_eglGlobal.NumDrivers++] = drv;
- return EGL_FALSE;
+ _eglAddModule(path);
+
+ return EGL_TRUE;
}
@@ -326,7 +342,6 @@ _eglLoaderPattern(const char *dir, size_t len, void *loader_data)
suffix_len = (suffix) ? strlen(suffix) : 0;
while ((dirent = readdir(dirp))) {
- _EGLDriver *drv;
size_t dirent_len = strlen(dirent->d_name);
const char *p;
@@ -340,12 +355,10 @@ _eglLoaderPattern(const char *dir, size_t len, void *loader_data)
continue;
}
- /* make a full path and load the driver */
+ /* make a full path and add it to the module array */
if (len + dirent_len + 1 <= sizeof(path)) {
strcpy(path + len, dirent->d_name);
- drv = _eglLoadDriver(path, NULL);
- if (drv)
- _eglGlobal.Drivers[_eglGlobal.NumDrivers++] = drv;
+ _eglAddModule(path);
}
}
@@ -360,19 +373,17 @@ _eglLoaderPattern(const char *dir, size_t len, void *loader_data)
/**
- * Run the preload function on each driver directory and return the number of
- * drivers loaded.
+ * Run the callback function on each driver directory.
*
* The process may end prematurely if the callback function returns false.
*/
-static EGLint
+static void
_eglPreloadForEach(const char *search_path,
EGLBoolean (*loader)(const char *, size_t, void *),
void *loader_data)
{
const char *cur, *next;
size_t len;
- EGLint num_drivers = _eglGlobal.NumDrivers;
cur = search_path;
while (cur) {
@@ -384,8 +395,6 @@ _eglPreloadForEach(const char *search_path,
cur = (next) ? next + 1 : NULL;
}
-
- return (_eglGlobal.NumDrivers - num_drivers);
}
@@ -430,12 +439,12 @@ _eglGetSearchPath(void)
/**
- * Preload a user driver.
+ * Add the user driver to the module array.
*
- * A user driver can be specified by EGL_DRIVER.
+ * The user driver is specified by EGL_DRIVER.
*/
-static EGLBoolean
-_eglPreloadUserDriver(void)
+static void
+_eglAddUserDriver(void)
{
const char *search_path = _eglGetSearchPath();
char *env;
@@ -451,132 +460,206 @@ _eglPreloadUserDriver(void)
}
}
#endif /* _EGL_OS_UNIX */
- if (!env)
- return EGL_FALSE;
+ if (env)
+ _eglPreloadForEach(search_path, _eglLoaderFile, (void *) env);
+}
- if (!_eglPreloadForEach(search_path, _eglLoaderFile, (void *) env)) {
- _eglLog(_EGL_WARNING, "EGL_DRIVER is set to an invalid driver");
- return EGL_FALSE;
- }
- return EGL_TRUE;
+/**
+ * Add default drivers to the module array.
+ */
+static void
+_eglAddDefaultDrivers(void)
+{
+ const char *search_path = _eglGetSearchPath();
+ EGLint i;
+#if defined(_EGL_OS_WINDOWS)
+ const char *DefaultDriverNames[] = {
+ "egl_gallium"
+ };
+#elif defined(_EGL_OS_UNIX)
+ const char *DefaultDriverNames[] = {
+ "egl_gallium",
+ "egl_dri2",
+ "egl_glx"
+ };
+#endif
+
+ for (i = 0; i < ARRAY_SIZE(DefaultDriverNames); i++) {
+ void *name = (void *) DefaultDriverNames[i];
+ _eglPreloadForEach(search_path, _eglLoaderFile, name);
+ }
}
/**
- * Preload platform drivers.
- *
- * Platform drivers are a set of drivers that support a certain window system.
- * The window system may be specified by EGL_PLATFORM.
- *
- * FIXME This makes libEGL a memory hog if an user driver is not specified and
- * there are many platform drivers.
+ * Add drivers to the module array. Drivers will be loaded as they are matched
+ * to displays.
*/
static EGLBoolean
-_eglPreloadPlatformDrivers(void)
+_eglAddDrivers(void)
{
- const char *dpy;
- char prefix[32];
- int ret;
-
- dpy = getenv("EGL_PLATFORM");
- /* try deprecated env variable */
- if (!dpy || !dpy[0])
- dpy = getenv("EGL_DISPLAY");
- if (!dpy || !dpy[0])
- dpy = _EGL_DEFAULT_PLATFORM;
- if (!dpy || !dpy[0])
- return EGL_FALSE;
+ if (_eglModules)
+ return EGL_TRUE;
- ret = _eglsnprintf(prefix, sizeof(prefix), "egl_%s_", dpy);
- if (ret < 0 || ret >= sizeof(prefix))
- return EGL_FALSE;
+ /* the order here decides the priorities of the drivers */
+ _eglAddUserDriver();
+ _eglAddDefaultDrivers();
+ _eglPreloadForEach(_eglGetSearchPath(), _eglLoaderPattern, (void *) "egl_");
- return (_eglPreloadForEach(_eglGetSearchPath(),
- _eglLoaderPattern, (void *) prefix) > 0);
+ return (_eglModules != NULL);
}
/**
- * Preload drivers.
+ * Match a display to a driver. The display is initialized unless use_probe is
+ * true.
*
- * This function loads the driver modules and creates the corresponding
- * _EGLDriver objects.
+ * The matching is done by finding the first driver that can initialize the
+ * display, or when use_probe is true, the driver with highest score.
*/
-EGLBoolean
-_eglPreloadDrivers(void)
+_EGLDriver *
+_eglMatchDriver(_EGLDisplay *dpy, EGLBoolean use_probe)
{
- EGLBoolean loaded;
+ _EGLModule *mod;
+ _EGLDriver *best_drv = NULL;
+ EGLint best_score = 0;
+ EGLint major, minor, i;
- /* protect the preloading process */
- _eglLockMutex(_eglGlobal.Mutex);
+ _eglLockMutex(&_eglModuleMutex);
- /* already preloaded */
- if (_eglGlobal.NumDrivers) {
- _eglUnlockMutex(_eglGlobal.Mutex);
- return EGL_TRUE;
+ if (!_eglAddDrivers()) {
+ _eglUnlockMutex(&_eglModuleMutex);
+ return EGL_FALSE;
+ }
+
+ /* match the loaded modules */
+ for (i = 0; i < _eglModules->Size; i++) {
+ mod = (_EGLModule *) _eglModules->Elements[i];
+ if (!mod->Driver)
+ break;
+
+ if (use_probe) {
+ EGLint score = (mod->Driver->Probe) ?
+ mod->Driver->Probe(mod->Driver, dpy) : 1;
+ if (score > best_score) {
+ best_drv = mod->Driver;
+ best_score = score;
+ }
+ }
+ else {
+ if (mod->Driver->API.Initialize(mod->Driver, dpy, &major, &minor)) {
+ best_drv = mod->Driver;
+ best_score = 100;
+ }
+ }
+ /* perfect match */
+ if (best_score >= 100)
+ break;
+ }
+
+ /* load more modules */
+ if (!best_drv) {
+ EGLint first_unloaded = i;
+
+ while (i < _eglModules->Size) {
+ mod = (_EGLModule *) _eglModules->Elements[i];
+ assert(!mod->Driver);
+
+ if (!_eglLoadModule(mod)) {
+ /* remove invalid modules */
+ _eglEraseArray(_eglModules, i, _eglFreeModule);
+ continue;
+ }
+
+ if (use_probe) {
+ best_score = (mod->Driver->Probe) ?
+ mod->Driver->Probe(mod->Driver, dpy) : 1;
+ }
+ else {
+ if (mod->Driver->API.Initialize(mod->Driver, dpy, &major, &minor))
+ best_score = 100;
+ }
+
+ if (best_score > 0) {
+ best_drv = mod->Driver;
+ /* loaded modules come before unloaded ones */
+ if (first_unloaded != i) {
+ void *tmp = _eglModules->Elements[i];
+ _eglModules->Elements[i] =
+ _eglModules->Elements[first_unloaded];
+ _eglModules->Elements[first_unloaded] = tmp;
+ }
+ break;
+ }
+ else {
+ _eglUnloadModule(mod);
+ i++;
+ }
+ }
}
- loaded = (_eglPreloadUserDriver() ||
- _eglPreloadPlatformDrivers());
+ _eglUnlockMutex(&_eglModuleMutex);
- _eglUnlockMutex(_eglGlobal.Mutex);
+ if (best_drv) {
+ _eglLog(_EGL_DEBUG, "the best driver is %s (score %d)",
+ best_drv->Name, best_score);
+ if (!use_probe) {
+ dpy->Driver = best_drv;
+ dpy->Initialized = EGL_TRUE;
+ dpy->APImajor = major;
+ dpy->APIminor = minor;
+ }
+ }
- return loaded;
+ return best_drv;
}
-/**
- * Unload preloaded drivers.
- */
-void
-_eglUnloadDrivers(void)
+
+__eglMustCastToProperFunctionPointerType
+_eglGetDriverProc(const char *procname)
{
EGLint i;
+ _EGLProc proc = NULL;
+
+ if (!_eglModules) {
+ /* load the driver for the default display */
+ EGLDisplay egldpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ _EGLDisplay *dpy = _eglLookupDisplay(egldpy);
+ if (!dpy || !_eglMatchDriver(dpy, EGL_TRUE))
+ return NULL;
+ }
- /* this is called at atexit time */
- for (i = 0; i < _eglGlobal.NumDrivers; i++) {
- _EGLDriver *drv = _eglGlobal.Drivers[i];
- lib_handle handle = drv->LibHandle;
-
- if (drv->Path)
- free((char *) drv->Path);
- if (drv->Args)
- free((char *) drv->Args);
-
- /* destroy driver */
- if (drv->Unload)
- drv->Unload(drv);
-
- if (handle)
- close_library(handle);
- _eglGlobal.Drivers[i] = NULL;
+ for (i = 0; i < _eglModules->Size; i++) {
+ _EGLModule *mod = (_EGLModule *) _eglModules->Elements[i];
+
+ if (!mod->Driver)
+ break;
+ proc = mod->Driver->API.GetProcAddress(mod->Driver, procname);
+ if (proc)
+ break;
}
- _eglGlobal.NumDrivers = 0;
+ return proc;
}
-_EGLDriver *
-_eglLoadDefaultDriver(EGLDisplay dpy, EGLint *major, EGLint *minor)
-{
- _EGLDriver *drv = NULL;
- int i;
-
- _eglLockMutex(_eglGlobal.Mutex);
- for (i = 0; i < ARRAY_SIZE(DefaultDriverNames); i++) {
- _eglPreloadForEach(_eglGetSearchPath(),
- _eglLoaderFile, (void *) DefaultDriverNames[i]);
- if (_eglGlobal.NumDrivers == 0)
- continue;
- drv = _eglGlobal.Drivers[0];
- if (drv->API.Initialize(drv, dpy, major, minor))
- break;
- _eglUnloadDrivers();
- }
-
- _eglUnlockMutex(_eglGlobal.Mutex);
-
- return _eglGlobal.NumDrivers > 0 ? drv : NULL;
+/**
+ * Unload all drivers.
+ */
+void
+_eglUnloadDrivers(void)
+{
+ /* this is called at atexit time */
+ if (_eglModules) {
+#if defined(_EGL_OS_UNIX)
+ _eglDestroyArray(_eglModules, _eglFreeModule);
+#elif defined(_EGL_OS_WINDOWS)
+ /* XXX Windows unloads DLLs before atexit */
+ _eglDestroyArray(_eglModules, NULL);
+#endif
+ _eglModules = NULL;
+ }
}
@@ -656,44 +739,3 @@ _eglSearchPathForEach(EGLBoolean (*callback)(const char *, size_t, void *),
const char *search_path = _eglGetSearchPath();
_eglPreloadForEach(search_path, callback, callback_data);
}
-
-
-/**
- * Set the probe cache at the given key.
- *
- * A key, instead of a _EGLDriver, is used to allow the probe cache to be share
- * by multiple drivers.
- */
-void
-_eglSetProbeCache(EGLint key, const void *val)
-{
- EGLint idx;
-
- for (idx = 0; idx < NUM_PROBE_CACHE_SLOTS; idx++) {
- if (!_eglProbeCache.keys[idx] || _eglProbeCache.keys[idx] == key)
- break;
- }
- assert(key > 0);
- assert(idx < NUM_PROBE_CACHE_SLOTS);
-
- _eglProbeCache.keys[idx] = key;
- _eglProbeCache.values[idx] = val;
-}
-
-
-/**
- * Return the probe cache at the given key.
- */
-const void *
-_eglGetProbeCache(EGLint key)
-{
- EGLint idx;
-
- for (idx = 0; idx < NUM_PROBE_CACHE_SLOTS; idx++) {
- if (!_eglProbeCache.keys[idx] || _eglProbeCache.keys[idx] == key)
- break;
- }
-
- return (idx < NUM_PROBE_CACHE_SLOTS && _eglProbeCache.keys[idx] == key) ?
- _eglProbeCache.values[idx] : NULL;
-}