|
|
@@ -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_gallium" |
|
|
|
}; |
|
|
|
|
|
|
|
typedef HMODULE lib_handle; |
|
|
|
|
|
|
|
static HMODULE |
|
|
@@ -67,12 +73,6 @@ library_suffix(void) |
|
|
|
#elif defined(_EGL_OS_UNIX) |
|
|
|
|
|
|
|
|
|
|
|
static const char *DefaultDriverNames[] = { |
|
|
|
"egl_gallium", |
|
|
|
"egl_dri2", |
|
|
|
"egl_glx" |
|
|
|
}; |
|
|
|
|
|
|
|
typedef void * lib_handle; |
|
|
|
|
|
|
|
static void * |
|
|
@@ -157,87 +157,109 @@ _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); |
|
|
|
} |
|
|
|
|
|
|
|
#include <errno.h> |
|
|
|
|
|
|
|
/** |
|
|
|
* A loader function for use with _eglPreloadForEach. The loader data is the |
|
|
@@ -246,7 +268,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); |
|
|
@@ -262,9 +283,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; |
|
|
@@ -272,36 +291,100 @@ _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 |
|
|
|
|
|
|
|
_eglAddModule(path); |
|
|
|
|
|
|
|
return EGL_TRUE; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* remember the driver and stop */ |
|
|
|
_eglGlobal.Drivers[_eglGlobal.NumDrivers++] = drv; |
|
|
|
/** |
|
|
|
* A loader function for use with _eglPreloadForEach. The loader data is the |
|
|
|
* pattern (prefix) of the files to look for. |
|
|
|
*/ |
|
|
|
static EGLBoolean |
|
|
|
_eglLoaderPattern(const char *dir, size_t len, void *loader_data) |
|
|
|
{ |
|
|
|
#if defined(_EGL_OS_UNIX) |
|
|
|
const char *prefix, *suffix; |
|
|
|
size_t prefix_len, suffix_len; |
|
|
|
DIR *dirp; |
|
|
|
struct dirent *dirent; |
|
|
|
char path[1024]; |
|
|
|
|
|
|
|
if (len + 2 > sizeof(path)) |
|
|
|
return EGL_TRUE; |
|
|
|
if (len) { |
|
|
|
memcpy(path, dir, len); |
|
|
|
path[len++] = '/'; |
|
|
|
} |
|
|
|
path[len] = '\0'; |
|
|
|
|
|
|
|
dirp = opendir(path); |
|
|
|
if (!dirp) |
|
|
|
return EGL_TRUE; |
|
|
|
|
|
|
|
prefix = (const char *) loader_data; |
|
|
|
prefix_len = strlen(prefix); |
|
|
|
suffix = library_suffix(); |
|
|
|
suffix_len = (suffix) ? strlen(suffix) : 0; |
|
|
|
|
|
|
|
while ((dirent = readdir(dirp))) { |
|
|
|
size_t dirent_len = strlen(dirent->d_name); |
|
|
|
const char *p; |
|
|
|
|
|
|
|
/* match the prefix */ |
|
|
|
if (strncmp(dirent->d_name, prefix, prefix_len) != 0) |
|
|
|
continue; |
|
|
|
/* match the suffix */ |
|
|
|
if (suffix) { |
|
|
|
p = dirent->d_name + dirent_len - suffix_len; |
|
|
|
if (p < dirent->d_name || strcmp(p, suffix) != 0) |
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
|
/* make a full path and add it to the module array */ |
|
|
|
if (len + dirent_len + 1 <= sizeof(path)) { |
|
|
|
strcpy(path + len, dirent->d_name); |
|
|
|
_eglAddModule(path); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
closedir(dirp); |
|
|
|
|
|
|
|
return EGL_TRUE; |
|
|
|
#else /* _EGL_OS_UNIX */ |
|
|
|
/* stop immediately */ |
|
|
|
return EGL_FALSE; |
|
|
|
#endif |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
* 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) { |
|
|
@@ -313,8 +396,6 @@ _eglPreloadForEach(const char *search_path, |
|
|
|
|
|
|
|
cur = (next) ? next + 1 : NULL; |
|
|
|
} |
|
|
|
|
|
|
|
return (_eglGlobal.NumDrivers - num_drivers); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@@ -359,12 +440,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; |
|
|
@@ -380,107 +461,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; |
|
|
|
|
|
|
|
/** |
|
|
|
* 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); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return EGL_TRUE; |
|
|
|
|
|
|
|
/** |
|
|
|
* Add drivers to the module array. Drivers will be loaded as they are matched |
|
|
|
* to displays. |
|
|
|
*/ |
|
|
|
static EGLBoolean |
|
|
|
_eglAddDrivers(void) |
|
|
|
{ |
|
|
|
if (_eglModules) |
|
|
|
return EGL_TRUE; |
|
|
|
|
|
|
|
/* the order here decides the priorities of the drivers */ |
|
|
|
_eglAddUserDriver(); |
|
|
|
_eglAddDefaultDrivers(); |
|
|
|
_eglPreloadForEach(_eglGetSearchPath(), _eglLoaderPattern, (void *) "egl_"); |
|
|
|
|
|
|
|
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; |
|
|
|
} |
|
|
|
|
|
|
|
loaded = _eglPreloadUserDriver(); |
|
|
|
/* match the loaded modules */ |
|
|
|
for (i = 0; i < _eglModules->Size; i++) { |
|
|
|
mod = (_EGLModule *) _eglModules->Elements[i]; |
|
|
|
if (!mod->Driver) |
|
|
|
break; |
|
|
|
|
|
|
|
_eglUnlockMutex(_eglGlobal.Mutex); |
|
|
|
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; |
|
|
|
} |
|
|
|
|
|
|
|
return loaded; |
|
|
|
} |
|
|
|
/* load more modules */ |
|
|
|
if (!best_drv) { |
|
|
|
EGLint first_unloaded = i; |
|
|
|
|
|
|
|
/** |
|
|
|
* Unload preloaded drivers. |
|
|
|
*/ |
|
|
|
void |
|
|
|
_eglUnloadDrivers(void) |
|
|
|
{ |
|
|
|
#if defined(_EGL_OS_UNIX) |
|
|
|
EGLint i; |
|
|
|
while (i < _eglModules->Size) { |
|
|
|
mod = (_EGLModule *) _eglModules->Elements[i]; |
|
|
|
assert(!mod->Driver); |
|
|
|
|
|
|
|
/* 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; |
|
|
|
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++; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
_eglGlobal.NumDrivers = 0; |
|
|
|
#elif defined(_EGL_OS_WINDOWS) |
|
|
|
/* XXX Windows unloads DLLs before atexit */ |
|
|
|
#endif |
|
|
|
_eglUnlockMutex(&_eglModuleMutex); |
|
|
|
|
|
|
|
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 best_drv; |
|
|
|
} |
|
|
|
|
|
|
|
_EGLDriver * |
|
|
|
_eglLoadDefaultDriver(EGLDisplay dpy, EGLint *major, EGLint *minor) |
|
|
|
|
|
|
|
__eglMustCastToProperFunctionPointerType |
|
|
|
_eglGetDriverProc(const char *procname) |
|
|
|
{ |
|
|
|
_EGLDriver *drv = NULL; |
|
|
|
EGLBoolean ok; |
|
|
|
int i; |
|
|
|
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; |
|
|
|
} |
|
|
|
|
|
|
|
_eglLockMutex(_eglGlobal.Mutex); |
|
|
|
for (i = 0; i < _eglModules->Size; i++) { |
|
|
|
_EGLModule *mod = (_EGLModule *) _eglModules->Elements[i]; |
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(DefaultDriverNames); i++) { |
|
|
|
_eglPreloadForEach(_eglGetSearchPath(), |
|
|
|
_eglLoaderFile, (void *) DefaultDriverNames[i]); |
|
|
|
if (_eglGlobal.NumDrivers == 0) |
|
|
|
continue; |
|
|
|
drv = _eglGlobal.Drivers[0]; |
|
|
|
|
|
|
|
_eglUnlockMutex(_eglGlobal.Mutex); |
|
|
|
ok = drv->API.Initialize(drv, dpy, major, minor); |
|
|
|
_eglLockMutex(_eglGlobal.Mutex); |
|
|
|
if (ok) |
|
|
|
if (!mod->Driver) |
|
|
|
break; |
|
|
|
proc = mod->Driver->API.GetProcAddress(mod->Driver, procname); |
|
|
|
if (proc) |
|
|
|
break; |
|
|
|
|
|
|
|
_eglUnloadDrivers(); |
|
|
|
} |
|
|
|
|
|
|
|
_eglUnlockMutex(_eglGlobal.Mutex); |
|
|
|
return proc; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
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; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|