egl: Rework driver loading.
Driver loading is now splitted into two stages. In the first stage, an _EGLModule is created for each driver: user driver, default drivers, and all files in the search directories that start with "egl_". Modules are not loaded at this stage. In the second stage, each module is loaded to initialize a display. The process stops at the first module that can initialize the display. If eglGetProcAddress is called before eglInitialize, the same code path will be taken to find the first module that supports EGL_DEFAULT_DISPLAY. Because we do not want to initialize the display, drv->Probe is used instead in this case.
This commit is contained in:
parent
cf588ab3f1
commit
f2aa361f3b
|
@ -264,46 +264,24 @@ EGLBoolean EGLAPIENTRY
|
||||||
eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
|
eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
|
||||||
{
|
{
|
||||||
_EGLDisplay *disp = _eglLockDisplay(dpy);
|
_EGLDisplay *disp = _eglLockDisplay(dpy);
|
||||||
EGLint major_int = 0, minor_int = 0;
|
|
||||||
|
|
||||||
if (!disp)
|
if (!disp)
|
||||||
RETURN_EGL_ERROR(NULL, EGL_BAD_DISPLAY, EGL_FALSE);
|
RETURN_EGL_ERROR(NULL, EGL_BAD_DISPLAY, EGL_FALSE);
|
||||||
|
|
||||||
if (!disp->Initialized) {
|
if (!disp->Initialized) {
|
||||||
_EGLDriver *drv = disp->Driver;
|
if (!_eglMatchDriver(disp, EGL_FALSE))
|
||||||
|
RETURN_EGL_ERROR(disp, EGL_NOT_INITIALIZED, EGL_FALSE);
|
||||||
if (!drv) {
|
|
||||||
_eglPreloadDrivers();
|
|
||||||
drv = _eglMatchDriver(disp);
|
|
||||||
/* Initialize the particular display now */
|
|
||||||
if (drv && !drv->API.Initialize(drv, disp, &major_int, &minor_int))
|
|
||||||
RETURN_EGL_ERROR(disp, EGL_NOT_INITIALIZED, EGL_FALSE);
|
|
||||||
}
|
|
||||||
if (!drv)
|
|
||||||
/* Load and initialize the first default driver that works */
|
|
||||||
drv = _eglLoadDefaultDriver(disp, &major_int, &minor_int);
|
|
||||||
if (!drv)
|
|
||||||
RETURN_EGL_ERROR(disp, EGL_NOT_INITIALIZED, EGL_FALSE);
|
|
||||||
|
|
||||||
disp->APImajor = major_int;
|
|
||||||
disp->APIminor = minor_int;
|
|
||||||
_eglsnprintf(disp->Version, sizeof(disp->Version),
|
|
||||||
"%d.%d (%s)", major_int, minor_int, drv->Name);
|
|
||||||
|
|
||||||
|
_eglsnprintf(disp->Version, sizeof(disp->Version), "%d.%d (%s)",
|
||||||
|
disp->APImajor, disp->APIminor, disp->Driver->Name);
|
||||||
/* limit to APIs supported by core */
|
/* limit to APIs supported by core */
|
||||||
disp->ClientAPIsMask &= _EGL_API_ALL_BITS;
|
disp->ClientAPIsMask &= _EGL_API_ALL_BITS;
|
||||||
|
|
||||||
disp->Driver = drv;
|
|
||||||
disp->Initialized = EGL_TRUE;
|
|
||||||
} else {
|
|
||||||
major_int = disp->APImajor;
|
|
||||||
minor_int = disp->APIminor;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Update applications version of major and minor if not NULL */
|
/* Update applications version of major and minor if not NULL */
|
||||||
if ((major != NULL) && (minor != NULL)) {
|
if ((major != NULL) && (minor != NULL)) {
|
||||||
*major = major_int;
|
*major = disp->APImajor;
|
||||||
*minor = minor_int;
|
*minor = disp->APIminor;
|
||||||
}
|
}
|
||||||
|
|
||||||
RETURN_EGL_SUCCESS(disp, EGL_TRUE);
|
RETURN_EGL_SUCCESS(disp, EGL_TRUE);
|
||||||
|
@ -870,18 +848,8 @@ eglGetProcAddress(const char *procname)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ret)
|
if (!ret)
|
||||||
RETURN_EGL_SUCCESS(NULL, ret);
|
ret = _eglGetDriverProc(procname);
|
||||||
|
|
||||||
_eglPreloadDrivers();
|
|
||||||
|
|
||||||
/* now loop over drivers to query their procs */
|
|
||||||
for (i = 0; i < _eglGlobal.NumDrivers; i++) {
|
|
||||||
_EGLDriver *drv = _eglGlobal.Drivers[i];
|
|
||||||
ret = drv->API.GetProcAddress(drv, procname);
|
|
||||||
if (ret)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
RETURN_EGL_SUCCESS(NULL, ret);
|
RETURN_EGL_SUCCESS(NULL, ret);
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,6 +83,22 @@ _eglAppendArray(_EGLArray *array, void *elem)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Erase an element from an array.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
_eglEraseArray(_EGLArray *array, EGLint i, void (*free_cb)(void *))
|
||||||
|
{
|
||||||
|
if (free_cb)
|
||||||
|
free_cb(array->Elements[i]);
|
||||||
|
if (i < array->Size - 1) {
|
||||||
|
memmove(&array->Elements[i], &array->Elements[i + 1],
|
||||||
|
(array->Size - i - 1) * sizeof(array->Elements[0]));
|
||||||
|
}
|
||||||
|
array->Size--;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find in an array for the given element.
|
* Find in an array for the given element.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -29,6 +29,10 @@ extern void
|
||||||
_eglAppendArray(_EGLArray *array, void *elem);
|
_eglAppendArray(_EGLArray *array, void *elem);
|
||||||
|
|
||||||
|
|
||||||
|
extern void
|
||||||
|
_eglEraseArray(_EGLArray *array, EGLint i, void (*free_cb)(void *));
|
||||||
|
|
||||||
|
|
||||||
void *
|
void *
|
||||||
_eglFindArray(_EGLArray *array, void *elem);
|
_eglFindArray(_EGLArray *array, void *elem);
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include "eglstring.h"
|
#include "eglstring.h"
|
||||||
#include "eglsurface.h"
|
#include "eglsurface.h"
|
||||||
#include "eglimage.h"
|
#include "eglimage.h"
|
||||||
|
#include "eglmutex.h"
|
||||||
|
|
||||||
#if defined(_EGL_OS_UNIX)
|
#if defined(_EGL_OS_UNIX)
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
|
@ -31,17 +32,22 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct _egl_module {
|
||||||
|
char *Path;
|
||||||
|
void *Handle;
|
||||||
|
_EGLDriver *Driver;
|
||||||
|
} _EGLModule;
|
||||||
|
|
||||||
|
static _EGL_DECLARE_MUTEX(_eglModuleMutex);
|
||||||
|
static _EGLArray *_eglModules;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrappers for dlopen/dlclose()
|
* Wrappers for dlopen/dlclose()
|
||||||
*/
|
*/
|
||||||
#if defined(_EGL_OS_WINDOWS)
|
#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;
|
typedef HMODULE lib_handle;
|
||||||
|
|
||||||
static HMODULE
|
static HMODULE
|
||||||
|
@ -67,12 +73,6 @@ library_suffix(void)
|
||||||
#elif defined(_EGL_OS_UNIX)
|
#elif defined(_EGL_OS_UNIX)
|
||||||
|
|
||||||
|
|
||||||
static const char *DefaultDriverNames[] = {
|
|
||||||
"egl_gallium",
|
|
||||||
"egl_dri2",
|
|
||||||
"egl_glx"
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef void * lib_handle;
|
typedef void * lib_handle;
|
||||||
|
|
||||||
static void *
|
static void *
|
||||||
|
@ -157,88 +157,110 @@ _eglOpenLibrary(const char *driverPath, lib_handle *handle)
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load the named driver.
|
* Load a module and create the driver object.
|
||||||
*/
|
*/
|
||||||
static _EGLDriver *
|
static EGLBoolean
|
||||||
_eglLoadDriver(const char *path, const char *args)
|
_eglLoadModule(_EGLModule *mod)
|
||||||
{
|
{
|
||||||
_EGLMain_t mainFunc;
|
_EGLMain_t mainFunc;
|
||||||
lib_handle lib;
|
lib_handle lib;
|
||||||
_EGLDriver *drv = NULL;
|
_EGLDriver *drv;
|
||||||
|
|
||||||
mainFunc = _eglOpenLibrary(path, &lib);
|
mainFunc = _eglOpenLibrary(mod->Path, &lib);
|
||||||
if (!mainFunc)
|
if (!mainFunc)
|
||||||
return NULL;
|
return EGL_FALSE;
|
||||||
|
|
||||||
drv = mainFunc(args);
|
drv = mainFunc(NULL);
|
||||||
if (!drv) {
|
if (!drv) {
|
||||||
if (lib)
|
if (lib)
|
||||||
close_library(lib);
|
close_library(lib);
|
||||||
return NULL;
|
return EGL_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!drv->Name) {
|
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->Name = "UNNAMED";
|
||||||
}
|
}
|
||||||
|
|
||||||
drv->Path = _eglstrdup(path);
|
mod->Handle = (void *) lib;
|
||||||
drv->Args = (args) ? _eglstrdup(args) : NULL;
|
mod->Driver = drv;
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
drv->LibHandle = lib;
|
return EGL_TRUE;
|
||||||
|
|
||||||
return drv;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Match a display to a preloaded driver.
|
* Unload a module.
|
||||||
*
|
|
||||||
* The matching is done by finding the driver with the highest score.
|
|
||||||
*/
|
*/
|
||||||
_EGLDriver *
|
static void
|
||||||
_eglMatchDriver(_EGLDisplay *dpy)
|
_eglUnloadModule(_EGLModule *mod)
|
||||||
{
|
{
|
||||||
_EGLDriver *best_drv = NULL;
|
/* destroy the driver */
|
||||||
EGLint best_score = -1, i;
|
if (mod->Driver && mod->Driver->Unload)
|
||||||
|
mod->Driver->Unload(mod->Driver);
|
||||||
|
if (mod->Handle)
|
||||||
|
close_library(mod->Handle);
|
||||||
|
|
||||||
/*
|
mod->Driver = NULL;
|
||||||
* this function is called after preloading and the drivers never change
|
mod->Handle = NULL;
|
||||||
* 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
best_drv = drv;
|
|
||||||
best_score = score;
|
|
||||||
/* perfect match */
|
|
||||||
if (score >= 100)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return best_drv;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a module to the module array.
|
||||||
|
*/
|
||||||
|
static _EGLModule *
|
||||||
|
_eglAddModule(const char *path)
|
||||||
|
{
|
||||||
|
_EGLModule *mod;
|
||||||
|
EGLint i;
|
||||||
|
|
||||||
|
if (!_eglModules) {
|
||||||
|
_eglModules = _eglCreateArray("Module", 8);
|
||||||
|
if (!_eglModules)
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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 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
|
* A loader function for use with _eglPreloadForEach. The loader data is the
|
||||||
* filename of the driver. This function stops on the first valid driver.
|
* filename of the driver. This function stops on the first valid driver.
|
||||||
|
@ -246,7 +268,6 @@ _eglMatchDriver(_EGLDisplay *dpy)
|
||||||
static EGLBoolean
|
static EGLBoolean
|
||||||
_eglLoaderFile(const char *dir, size_t len, void *loader_data)
|
_eglLoaderFile(const char *dir, size_t len, void *loader_data)
|
||||||
{
|
{
|
||||||
_EGLDriver *drv;
|
|
||||||
char path[1024];
|
char path[1024];
|
||||||
const char *filename = (const char *) loader_data;
|
const char *filename = (const char *) loader_data;
|
||||||
size_t flen = strlen(filename);
|
size_t flen = strlen(filename);
|
||||||
|
@ -262,9 +283,7 @@ _eglLoaderFile(const char *dir, size_t len, void *loader_data)
|
||||||
len += flen;
|
len += flen;
|
||||||
path[len] = '\0';
|
path[len] = '\0';
|
||||||
|
|
||||||
if (library_suffix() == NULL || strstr(path, library_suffix()))
|
if (library_suffix()) {
|
||||||
drv = _eglLoadDriver(path, NULL);
|
|
||||||
else {
|
|
||||||
const char *suffix = library_suffix();
|
const char *suffix = library_suffix();
|
||||||
size_t slen = strlen(suffix);
|
size_t slen = strlen(suffix);
|
||||||
const char *p;
|
const char *p;
|
||||||
|
@ -272,36 +291,100 @@ _eglLoaderFile(const char *dir, size_t len, void *loader_data)
|
||||||
|
|
||||||
p = filename + flen - slen;
|
p = filename + flen - slen;
|
||||||
need_suffix = (p < filename || strcmp(p, suffix) != 0);
|
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);
|
strcpy(path + len, suffix);
|
||||||
drv = _eglLoadDriver(path, NULL);
|
|
||||||
} else {
|
|
||||||
drv = NULL;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!drv)
|
|
||||||
return EGL_TRUE;
|
|
||||||
|
|
||||||
/* remember the driver and stop */
|
#if defined(_EGL_OS_UNIX)
|
||||||
_eglGlobal.Drivers[_eglGlobal.NumDrivers++] = drv;
|
/* check if the file exists */
|
||||||
return EGL_FALSE;
|
if (access(path, F_OK))
|
||||||
|
return EGL_TRUE;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
_eglAddModule(path);
|
||||||
|
|
||||||
|
return EGL_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Run the preload function on each driver directory and return the number of
|
* A loader function for use with _eglPreloadForEach. The loader data is the
|
||||||
* drivers loaded.
|
* 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 callback function on each driver directory.
|
||||||
*
|
*
|
||||||
* The process may end prematurely if the callback function returns false.
|
* The process may end prematurely if the callback function returns false.
|
||||||
*/
|
*/
|
||||||
static EGLint
|
static void
|
||||||
_eglPreloadForEach(const char *search_path,
|
_eglPreloadForEach(const char *search_path,
|
||||||
EGLBoolean (*loader)(const char *, size_t, void *),
|
EGLBoolean (*loader)(const char *, size_t, void *),
|
||||||
void *loader_data)
|
void *loader_data)
|
||||||
{
|
{
|
||||||
const char *cur, *next;
|
const char *cur, *next;
|
||||||
size_t len;
|
size_t len;
|
||||||
EGLint num_drivers = _eglGlobal.NumDrivers;
|
|
||||||
|
|
||||||
cur = search_path;
|
cur = search_path;
|
||||||
while (cur) {
|
while (cur) {
|
||||||
|
@ -313,8 +396,6 @@ _eglPreloadForEach(const char *search_path,
|
||||||
|
|
||||||
cur = (next) ? next + 1 : NULL;
|
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
|
static void
|
||||||
_eglPreloadUserDriver(void)
|
_eglAddUserDriver(void)
|
||||||
{
|
{
|
||||||
const char *search_path = _eglGetSearchPath();
|
const char *search_path = _eglGetSearchPath();
|
||||||
char *env;
|
char *env;
|
||||||
|
@ -380,107 +461,206 @@ _eglPreloadUserDriver(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /* _EGL_OS_UNIX */
|
#endif /* _EGL_OS_UNIX */
|
||||||
if (!env)
|
if (env)
|
||||||
return EGL_FALSE;
|
_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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Preload drivers.
|
* Add default drivers to the module array.
|
||||||
*
|
|
||||||
* This function loads the driver modules and creates the corresponding
|
|
||||||
* _EGLDriver objects.
|
|
||||||
*/
|
*/
|
||||||
EGLBoolean
|
static void
|
||||||
_eglPreloadDrivers(void)
|
_eglAddDefaultDrivers(void)
|
||||||
{
|
{
|
||||||
EGLBoolean loaded;
|
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
|
||||||
|
|
||||||
/* protect the preloading process */
|
for (i = 0; i < ARRAY_SIZE(DefaultDriverNames); i++) {
|
||||||
_eglLockMutex(_eglGlobal.Mutex);
|
void *name = (void *) DefaultDriverNames[i];
|
||||||
|
_eglPreloadForEach(search_path, _eglLoaderFile, name);
|
||||||
/* already preloaded */
|
|
||||||
if (_eglGlobal.NumDrivers) {
|
|
||||||
_eglUnlockMutex(_eglGlobal.Mutex);
|
|
||||||
return EGL_TRUE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
loaded = _eglPreloadUserDriver();
|
|
||||||
|
|
||||||
_eglUnlockMutex(_eglGlobal.Mutex);
|
|
||||||
|
|
||||||
return loaded;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unload preloaded drivers.
|
* 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Match a display to a driver. The display is initialized unless use_probe is
|
||||||
|
* true.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
_EGLDriver *
|
||||||
|
_eglMatchDriver(_EGLDisplay *dpy, EGLBoolean use_probe)
|
||||||
|
{
|
||||||
|
_EGLModule *mod;
|
||||||
|
_EGLDriver *best_drv = NULL;
|
||||||
|
EGLint best_score = 0;
|
||||||
|
EGLint major, minor, i;
|
||||||
|
|
||||||
|
_eglLockMutex(&_eglModuleMutex);
|
||||||
|
|
||||||
|
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++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
__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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
return proc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unload all drivers.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
_eglUnloadDrivers(void)
|
_eglUnloadDrivers(void)
|
||||||
{
|
{
|
||||||
#if defined(_EGL_OS_UNIX)
|
|
||||||
EGLint i;
|
|
||||||
|
|
||||||
/* this is called at atexit time */
|
/* this is called at atexit time */
|
||||||
for (i = 0; i < _eglGlobal.NumDrivers; i++) {
|
if (_eglModules) {
|
||||||
_EGLDriver *drv = _eglGlobal.Drivers[i];
|
#if defined(_EGL_OS_UNIX)
|
||||||
lib_handle handle = drv->LibHandle;
|
_eglDestroyArray(_eglModules, _eglFreeModule);
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
_eglGlobal.NumDrivers = 0;
|
|
||||||
#elif defined(_EGL_OS_WINDOWS)
|
#elif defined(_EGL_OS_WINDOWS)
|
||||||
/* XXX Windows unloads DLLs before atexit */
|
/* XXX Windows unloads DLLs before atexit */
|
||||||
|
_eglDestroyArray(_eglModules, NULL);
|
||||||
#endif
|
#endif
|
||||||
}
|
_eglModules = NULL;
|
||||||
|
|
||||||
_EGLDriver *
|
|
||||||
_eglLoadDefaultDriver(EGLDisplay dpy, EGLint *major, EGLint *minor)
|
|
||||||
{
|
|
||||||
_EGLDriver *drv = NULL;
|
|
||||||
EGLBoolean ok;
|
|
||||||
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];
|
|
||||||
|
|
||||||
_eglUnlockMutex(_eglGlobal.Mutex);
|
|
||||||
ok = drv->API.Initialize(drv, dpy, major, minor);
|
|
||||||
_eglLockMutex(_eglGlobal.Mutex);
|
|
||||||
if (ok)
|
|
||||||
break;
|
|
||||||
|
|
||||||
_eglUnloadDrivers();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_eglUnlockMutex(_eglGlobal.Mutex);
|
|
||||||
|
|
||||||
return _eglGlobal.NumDrivers > 0 ? drv : NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -41,10 +41,6 @@ typedef _EGLDriver *(*_EGLMain_t)(const char *args);
|
||||||
*/
|
*/
|
||||||
struct _egl_driver
|
struct _egl_driver
|
||||||
{
|
{
|
||||||
void *LibHandle; /**< dlopen handle */
|
|
||||||
const char *Path; /**< path to this driver */
|
|
||||||
const char *Args; /**< args to load this driver */
|
|
||||||
|
|
||||||
const char *Name; /**< name of this driver */
|
const char *Name; /**< name of this driver */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -73,21 +69,17 @@ _eglMain(const char *args);
|
||||||
|
|
||||||
|
|
||||||
extern _EGLDriver *
|
extern _EGLDriver *
|
||||||
_eglMatchDriver(_EGLDisplay *dpy);
|
_eglMatchDriver(_EGLDisplay *dpy, EGLBoolean probe_only);
|
||||||
|
|
||||||
|
|
||||||
extern EGLBoolean
|
extern __eglMustCastToProperFunctionPointerType
|
||||||
_eglPreloadDrivers(void);
|
_eglGetDriverProc(const char *procname);
|
||||||
|
|
||||||
|
|
||||||
extern void
|
extern void
|
||||||
_eglUnloadDrivers(void);
|
_eglUnloadDrivers(void);
|
||||||
|
|
||||||
|
|
||||||
extern _EGLDriver *
|
|
||||||
_eglLoadDefaultDriver(EGLDisplay dpy, EGLint *major, EGLint *minor);
|
|
||||||
|
|
||||||
|
|
||||||
PUBLIC void
|
PUBLIC void
|
||||||
_eglInitDriverFallbacks(_EGLDriver *drv);
|
_eglInitDriverFallbacks(_EGLDriver *drv);
|
||||||
|
|
||||||
|
|
|
@ -12,8 +12,6 @@ struct _egl_global _eglGlobal =
|
||||||
&_eglGlobalMutex, /* Mutex */
|
&_eglGlobalMutex, /* Mutex */
|
||||||
NULL, /* DisplayList */
|
NULL, /* DisplayList */
|
||||||
1, /* FreeScreenHandle */
|
1, /* FreeScreenHandle */
|
||||||
0, /* NumDrivers */
|
|
||||||
{ NULL }, /* Drivers */
|
|
||||||
2, /* NumAtExitCalls */
|
2, /* NumAtExitCalls */
|
||||||
{
|
{
|
||||||
/* default AtExitCalls, called in reverse order */
|
/* default AtExitCalls, called in reverse order */
|
||||||
|
|
|
@ -18,10 +18,6 @@ struct _egl_global
|
||||||
|
|
||||||
EGLScreenMESA FreeScreenHandle;
|
EGLScreenMESA FreeScreenHandle;
|
||||||
|
|
||||||
/* these never change after preloading */
|
|
||||||
EGLint NumDrivers;
|
|
||||||
_EGLDriver *Drivers[10];
|
|
||||||
|
|
||||||
EGLint NumAtExitCalls;
|
EGLint NumAtExitCalls;
|
||||||
void (*AtExitCalls[10])(void);
|
void (*AtExitCalls[10])(void);
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue