X-Git-Url: https://git.libre-soc.org/?p=mesa.git;a=blobdiff_plain;f=src%2Fegl%2Fmain%2Fegldriver.c;h=b7c3de3e38e2c7ffe14c0fc5df90fa9357d48857;hp=97550ea27c397c0cff693ea9eb5c7c057f277925;hb=a8b6b6555c7d6a02a3d095c72ebbdc218bc45cd3;hpb=cecc33cd4f2b3ae1fa590a450eeaefc9b761fb30 diff --git a/src/egl/main/egldriver.c b/src/egl/main/egldriver.c index 97550ea27c3..b7c3de3e38e 100644 --- a/src/egl/main/egldriver.c +++ b/src/egl/main/egldriver.c @@ -7,34 +7,53 @@ #include #include #include -#include "eglconfig.h" -#include "eglcontext.h" + +#include "eglstring.h" #include "egldefines.h" #include "egldisplay.h" #include "egldriver.h" -#include "eglglobals.h" #include "egllog.h" -#include "eglmisc.h" -#include "eglmode.h" -#include "eglscreen.h" -#include "eglstring.h" -#include "eglsurface.h" +#include "eglmutex.h" -#if defined(_EGL_PLATFORM_POSIX) +#if defined(_EGL_OS_UNIX) #include #include #include +#include #endif +typedef struct _egl_module { + char *Path; + _EGLMain_t BuiltIn; + void *Handle; + _EGLDriver *Driver; +} _EGLModule; + +static _EGL_DECLARE_MUTEX(_eglModuleMutex); +static _EGLArray *_eglModules; + +const struct { + const char *name; + _EGLMain_t main; +} _eglBuiltInDrivers[] = { +#ifdef _EGL_BUILT_IN_DRIVER_GALLIUM + { "egl_gallium", _eglBuiltInDriverGALLIUM }, +#endif +#ifdef _EGL_BUILT_IN_DRIVER_DRI2 + { "egl_dri2", _eglBuiltInDriverDRI2 }, +#endif +#ifdef _EGL_BUILT_IN_DRIVER_GLX + { "egl_glx", _eglBuiltInDriverGLX }, +#endif + { NULL, NULL } +}; + /** * Wrappers for dlopen/dlclose() */ -#if defined(_EGL_PLATFORM_WINDOWS) - +#if defined(_EGL_OS_WINDOWS) -/* XXX Need to decide how to do dynamic name lookup on Windows */ -static const char DefaultDriverName[] = "TBD"; typedef HMODULE lib_handle; @@ -54,15 +73,13 @@ close_library(HMODULE lib) static const char * library_suffix(void) { - return "dll"; + return ".dll"; } -#elif defined(_EGL_PLATFORM_POSIX) +#elif defined(_EGL_OS_UNIX) -static const char DefaultDriverName[] = "egl_glx"; - typedef void * lib_handle; static void * @@ -81,45 +98,13 @@ close_library(void *lib) static const char * library_suffix(void) { - return "so"; -} - - -#else /* _EGL_PLATFORM_NO_OS */ - -static const char DefaultDriverName[] = "builtin"; - -typedef void *lib_handle; - -static INLINE void * -open_library(const char *filename) -{ - return (void *) filename; -} - -static INLINE void -close_library(void *lib) -{ -} - - -static const char * -library_suffix(void) -{ - return NULL; + return ".so"; } #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(). */ @@ -135,33 +120,30 @@ _eglOpenLibrary(const char *driverPath, lib_handle *handle) _eglLog(_EGL_DEBUG, "dlopen(%s)", driverPath); lib = open_library(driverPath); -#if defined(_EGL_PLATFORM_WINDOWS) +#if defined(_EGL_OS_WINDOWS) /* XXX untested */ if (lib) mainFunc = (_EGLMain_t) GetProcAddress(lib, "_eglMain"); -#elif defined(_EGL_PLATFORM_POSIX) +#elif defined(_EGL_OS_UNIX) if (lib) { - mainFunc = (_EGLMain_t) dlsym(lib, "_eglMain"); + union { + _EGLMain_t func; + void *ptr; + } tmp = { NULL }; + /* direct cast gives a warning when compiled with -pedantic */ + tmp.ptr = dlsym(lib, "_eglMain"); + mainFunc = tmp.func; if (!mainFunc) error = dlerror(); } else { error = dlerror(); } -#else /* _EGL_PLATFORM_NO_OS */ - /* must be the default driver name */ - if (strcmp(driverPath, DefaultDriverName) == 0) - mainFunc = (_EGLMain_t) _eglMain; - else - error = "not builtin driver"; #endif if (!lib) { _eglLog(_EGL_WARNING, "Could not open driver %s (%s)", driverPath, error); - if (!getenv("EGL_DRIVER")) - _eglLog(_EGL_WARNING, - "The driver can be overridden by setting EGL_DRIVER"); return NULL; } @@ -179,389 +161,518 @@ _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); - if (!mainFunc) - return NULL; + if (mod->Driver) + return EGL_TRUE; + + if (mod->BuiltIn) { + lib = (lib_handle) NULL; + mainFunc = mod->BuiltIn; + } + else { + mainFunc = _eglOpenLibrary(mod->Path, &lib); + if (!mainFunc) + 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) +{ +#if defined(_EGL_OS_UNIX) + /* destroy the driver */ + if (mod->Driver && mod->Driver->Unload) + mod->Driver->Unload(mod->Driver); + + /* + * XXX At this point (atexit), the module might be the last reference to + * libEGL. Closing the module might unmap libEGL and give problems. + */ +#if 0 + if (mod->Handle) + close_library(mod->Handle); +#endif +#elif defined(_EGL_OS_WINDOWS) + /* XXX Windows unloads DLLs before atexit */ +#endif + + 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. */ -static _EGLDriver * -_eglMatchDriver(_EGLDisplay *dpy) +static _EGLModule * +_eglAddModule(const char *path) { - _EGLDriver *best_drv = NULL; - EGLint best_score = -1, i; + _EGLModule *mod; + EGLint i; - for (i = 0; i < _eglGlobal.NumDrivers; i++) { - _EGLDriver *drv = _eglGlobal.Drivers[i]; - EGLint score; + if (!_eglModules) { + _eglModules = _eglCreateArray("Module", 8); + if (!_eglModules) + return NULL; + } - 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); - } + /* find duplicates */ + for (i = 0; i < _eglModules->Size; i++) { + mod = _eglModules->Elements[i]; + if (strcmp(mod->Path, path) == 0) + return mod; + } - best_drv = drv; - best_score = score; - /* perfect match */ - if (score >= 100) - break; + /* 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; } /** - * Open a preloaded driver. + * Free a module. */ -_EGLDriver * -_eglOpenDriver(_EGLDisplay *dpy) +static void +_eglFreeModule(void *module) { - _EGLDriver *drv = _eglMatchDriver(dpy); - return drv; -} - + _EGLModule *mod = (_EGLModule *) module; -/** - * Close a preloaded driver. - */ -EGLBoolean -_eglCloseDriver(_EGLDriver *drv, _EGLDisplay *dpy) -{ - return EGL_TRUE; + _eglUnloadModule(mod); + free(mod->Path); + free(mod); } /** - * Preload a user driver. - * - * A user driver can be specified by EGL_DRIVER. + * A loader function for use with _eglPreloadForEach. The loader data is the + * filename of the driver. This function stops on the first valid driver. */ static EGLBoolean -_eglPreloadUserDriver(void) +_eglLoaderFile(const char *dir, size_t len, void *loader_data) { -#if defined(_EGL_PLATFORM_POSIX) || defined(_EGL_PLATFORM_WINDOWS) - _EGLDriver *drv; - char *env, *path; - const char *suffix, *p; + char path[1024]; + const char *filename = (const char *) loader_data; + size_t flen = strlen(filename); - env = getenv("EGL_DRIVER"); - if (!env) - return EGL_FALSE; + /* make a full path */ + if (len + flen + 2 > sizeof(path)) + return EGL_TRUE; + if (len) { + memcpy(path, dir, len); + path[len++] = '/'; + } + memcpy(path + len, filename, flen); + len += flen; + path[len] = '\0'; - path = env; - suffix = library_suffix(); - - /* append suffix if there isn't */ - p = strrchr(path, '.'); - if (!p && suffix) { - size_t len = strlen(path); - char *tmp = malloc(len + strlen(suffix) + 2); - if (tmp) { - memcpy(tmp, path, len); - tmp[len++] = '.'; - tmp[len] = '\0'; - strcat(tmp + len, suffix); - - path = tmp; + if (library_suffix()) { + const char *suffix = library_suffix(); + size_t slen = strlen(suffix); + const char *p; + EGLBoolean need_suffix; + + p = filename + flen - slen; + need_suffix = (p < filename || strcmp(p, suffix) != 0); + if (need_suffix) { + /* overflow */ + if (len + slen + 1 > sizeof(path)) + return EGL_TRUE; + strcpy(path + len, suffix); } } - drv = _eglLoadDriver(path, NULL); - if (path != env) - free(path); - if (!drv) - return EGL_FALSE; +#if defined(_EGL_OS_UNIX) + /* check if the file exists */ + if (access(path, F_OK)) + return EGL_TRUE; +#endif - _eglGlobal.Drivers[_eglGlobal.NumDrivers++] = drv; + _eglAddModule(path); return EGL_TRUE; -#else /* _EGL_PLATFORM_POSIX || _EGL_PLATFORM_WINDOWS */ - return EGL_FALSE; -#endif } /** - * Preload display drivers. - * - * Display drivers are a set of drivers that support a certain display system. - * The display system may be specified by EGL_DISPLAY. + * Run the callback function on each driver directory. * - * FIXME This makes libEGL a memory hog if an user driver is not specified and - * there are many display drivers. + * The process may end prematurely if the callback function returns false. */ -static EGLBoolean -_eglPreloadDisplayDrivers(void) +static void +_eglPreloadForEach(const char *search_path, + EGLBoolean (*loader)(const char *, size_t, void *), + void *loader_data) { -#if defined(_EGL_PLATFORM_POSIX) - const char *dpy, *suffix; - char path[1024], prefix[32]; - DIR *dirp; - struct dirent *dirent; - - dpy = getenv("EGL_DISPLAY"); - if (!dpy || !dpy[0]) - dpy = _EGL_DEFAULT_DISPLAY; - if (!dpy || !dpy[0]) - return EGL_FALSE; - - snprintf(prefix, sizeof(prefix), "egl_%s_", dpy); - suffix = library_suffix(); + const char *cur, *next; + size_t len; - dirp = opendir(_EGL_DRIVER_SEARCH_DIR); - if (!dirp) - return EGL_FALSE; - - while ((dirent = readdir(dirp))) { - _EGLDriver *drv; - const char *p; + cur = search_path; + while (cur) { + next = strchr(cur, ':'); + len = (next) ? next - cur : strlen(cur); - /* match the prefix */ - if (strncmp(dirent->d_name, prefix, strlen(prefix)) != 0) - continue; - - /* match the suffix */ - p = strrchr(dirent->d_name, '.'); - if ((p && !suffix) || (!p && suffix)) - continue; - else if (p && suffix && strcmp(p + 1, suffix) != 0) - continue; - - snprintf(path, sizeof(path), - _EGL_DRIVER_SEARCH_DIR"/%s", dirent->d_name); + if (!loader(cur, len, loader_data)) + break; - drv = _eglLoadDriver(path, NULL); - if (drv) - _eglGlobal.Drivers[_eglGlobal.NumDrivers++] = drv; + cur = (next) ? next + 1 : NULL; } - - closedir(dirp); - - return (_eglGlobal.NumDrivers > 0); -#else /* _EGL_PLATFORM_POSIX */ - return EGL_FALSE; -#endif } /** - * Preload the default driver. + * Return a list of colon-separated driver directories. */ -static EGLBoolean -_eglPreloadDefaultDriver(void) +static const char * +_eglGetSearchPath(void) { - _EGLDriver *drv; - char path[1024]; - const char *suffix = library_suffix(); + static char search_path[1024]; + +#if defined(_EGL_OS_UNIX) || defined(_EGL_OS_WINDOWS) + if (search_path[0] == '\0') { + char *buf = search_path; + size_t len = sizeof(search_path); + EGLBoolean use_env; + char dir_sep; + int ret; + +#if defined(_EGL_OS_UNIX) + use_env = (geteuid() == getuid() && getegid() == getgid()); + dir_sep = '/'; +#else + use_env = EGL_TRUE; + dir_sep = '\\'; +#endif - if (suffix) - snprintf(path, sizeof(path), "%s.%s", DefaultDriverName, suffix); - else - snprintf(path, sizeof(path), DefaultDriverName); + if (use_env) { + char *p; - drv = _eglLoadDriver(path, NULL); - if (!drv) - return EGL_FALSE; + /* extract the dirname from EGL_DRIVER */ + p = getenv("EGL_DRIVER"); + if (p && strchr(p, dir_sep)) { + ret = _eglsnprintf(buf, len, "%s", p); + if (ret > 0 && ret < len) { + p = strrchr(buf, dir_sep); + *p++ = ':'; - _eglGlobal.Drivers[_eglGlobal.NumDrivers++] = drv; + len -= p - buf; + buf = p; + } + } - return EGL_TRUE; + /* append EGL_DRIVERS_PATH */ + p = getenv("EGL_DRIVERS_PATH"); + if (p) { + ret = _eglsnprintf(buf, len, "%s:", p); + if (ret > 0 && ret < len) { + buf += ret; + len -= ret; + } + } + } + else { + _eglLog(_EGL_DEBUG, + "ignore EGL_DRIVERS_PATH for setuid/setgid binaries"); + } + + ret = _eglsnprintf(buf, len, "%s", _EGL_DRIVER_SEARCH_DIR); + if (ret < 0 || ret >= len) + search_path[0] = '\0'; + + _eglLog(_EGL_DEBUG, "EGL search path is %s", search_path); + } +#endif /* defined(_EGL_OS_UNIX) || defined(_EGL_OS_WINDOWS) */ + + return search_path; } /** - * Preload drivers. + * Add the user driver to the module array. * - * This function loads the driver modules and creates the corresponding - * _EGLDriver objects. + * The user driver is specified by EGL_DRIVER. */ -EGLBoolean -_eglPreloadDrivers(void) +static void +_eglAddUserDriver(void) { - EGLBoolean loaded; + const char *search_path = _eglGetSearchPath(); + char *env; - /* already preloaded */ - if (_eglGlobal.NumDrivers) - return EGL_TRUE; + env = getenv("EGL_DRIVER"); +#if defined(_EGL_OS_UNIX) + if (env && strchr(env, '/')) { + search_path = ""; + if ((geteuid() != getuid() || getegid() != getgid())) { + _eglLog(_EGL_DEBUG, + "ignore EGL_DRIVER for setuid/setgid binaries"); + env = NULL; + } + } +#endif /* _EGL_OS_UNIX */ + if (env) { + _EGLModule *mod; + EGLint i; + + /* env can be a path */ + _eglPreloadForEach(search_path, _eglLoaderFile, (void *) env); + /* or the name of a built-in driver */ + for (i = 0; _eglBuiltInDrivers[i].name; i++) { + if (!strcmp(_eglBuiltInDrivers[i].name, env)) { + mod = _eglAddModule(env); + if (mod) + mod->BuiltIn = _eglBuiltInDrivers[i].main; + } + } + } +} - loaded = (_eglPreloadUserDriver() || - _eglPreloadDisplayDrivers() || - _eglPreloadDefaultDriver()); - return loaded; +/** + * Add egl_gallium to the module array. + */ +static void +_eglAddGalliumDriver(void) +{ +#ifndef _EGL_BUILT_IN_DRIVER_GALLIUM + void *external = (void *) "egl_gallium"; + _eglPreloadForEach(_eglGetSearchPath(), _eglLoaderFile, external); +#endif } /** - * Unload preloaded drivers. + * Add built-in drivers to the module array. */ -void -_eglUnloadDrivers(void) +static void +_eglAddBuiltInDrivers(void) { + _EGLModule *mod; EGLint i; - 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; - } - _eglGlobal.NumDrivers = 0; + for (i = 0; _eglBuiltInDrivers[i].name; i++) { + mod = _eglAddModule(_eglBuiltInDrivers[i].name); + if (mod) + mod->BuiltIn = _eglBuiltInDrivers[i].main; + } } /** - * Plug all the available fallback routines into the given driver's - * dispatch table. + * Add drivers to the module array. Drivers will be loaded as they are matched + * to displays. */ -void -_eglInitDriverFallbacks(_EGLDriver *drv) +static EGLBoolean +_eglAddDrivers(void) { - /* If a pointer is set to NULL, then the device driver _really_ has - * to implement it. - */ - drv->API.Initialize = NULL; - drv->API.Terminate = NULL; - - drv->API.GetConfigs = _eglGetConfigs; - drv->API.ChooseConfig = _eglChooseConfig; - drv->API.GetConfigAttrib = _eglGetConfigAttrib; - - drv->API.CreateContext = _eglCreateContext; - drv->API.DestroyContext = _eglDestroyContext; - drv->API.MakeCurrent = _eglMakeCurrent; - drv->API.QueryContext = _eglQueryContext; - - drv->API.CreateWindowSurface = _eglCreateWindowSurface; - drv->API.CreatePixmapSurface = _eglCreatePixmapSurface; - drv->API.CreatePbufferSurface = _eglCreatePbufferSurface; - drv->API.DestroySurface = _eglDestroySurface; - drv->API.QuerySurface = _eglQuerySurface; - drv->API.SurfaceAttrib = _eglSurfaceAttrib; - drv->API.BindTexImage = _eglBindTexImage; - drv->API.ReleaseTexImage = _eglReleaseTexImage; - drv->API.SwapInterval = _eglSwapInterval; - drv->API.SwapBuffers = _eglSwapBuffers; - drv->API.CopyBuffers = _eglCopyBuffers; - - drv->API.QueryString = _eglQueryString; - drv->API.WaitClient = _eglWaitClient; - drv->API.WaitNative = _eglWaitNative; - -#ifdef EGL_MESA_screen_surface - drv->API.ChooseModeMESA = _eglChooseModeMESA; - drv->API.GetModesMESA = _eglGetModesMESA; - drv->API.GetModeAttribMESA = _eglGetModeAttribMESA; - drv->API.GetScreensMESA = _eglGetScreensMESA; - drv->API.CreateScreenSurfaceMESA = _eglCreateScreenSurfaceMESA; - drv->API.ShowScreenSurfaceMESA = _eglShowScreenSurfaceMESA; - drv->API.ScreenPositionMESA = _eglScreenPositionMESA; - drv->API.QueryScreenMESA = _eglQueryScreenMESA; - drv->API.QueryScreenSurfaceMESA = _eglQueryScreenSurfaceMESA; - drv->API.QueryScreenModeMESA = _eglQueryScreenModeMESA; - drv->API.QueryModeStringMESA = _eglQueryModeStringMESA; -#endif /* EGL_MESA_screen_surface */ - -#ifdef EGL_VERSION_1_2 - drv->API.CreatePbufferFromClientBuffer = _eglCreatePbufferFromClientBuffer; -#endif /* EGL_VERSION_1_2 */ + if (_eglModules) + return EGL_TRUE; + + /* the order here decides the priorities of the drivers */ + _eglAddUserDriver(); + _eglAddGalliumDriver(); + _eglAddBuiltInDrivers(); + + return (_eglModules != NULL); } /** - * Set the probe cache at the given key. + * Match a display to a driver. The display is initialized unless use_probe is + * true. * - * A key, instead of a _EGLDriver, is used to allow the probe cache to be share - * by multiple drivers. + * 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. */ -void -_eglSetProbeCache(EGLint key, const void *val) +_EGLDriver * +_eglMatchDriver(_EGLDisplay *dpy, EGLBoolean use_probe) { - EGLint idx; + _EGLModule *mod; + _EGLDriver *best_drv = NULL; + EGLint best_score = 0; + EGLint major, minor, i; - for (idx = 0; idx < NUM_PROBE_CACHE_SLOTS; idx++) { - if (!_eglProbeCache.keys[idx] || _eglProbeCache.keys[idx] == key) + _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; } - assert(key > 0); - assert(idx < NUM_PROBE_CACHE_SLOTS); - _eglProbeCache.keys[idx] = key; - _eglProbeCache.values[idx] = val; + return proc; } /** - * Return the probe cache at the given key. + * Unload all drivers. */ -const void * -_eglGetProbeCache(EGLint key) +void +_eglUnloadDrivers(void) { - EGLint idx; - - for (idx = 0; idx < NUM_PROBE_CACHE_SLOTS; idx++) { - if (!_eglProbeCache.keys[idx] || _eglProbeCache.keys[idx] == key) - break; + /* this is called at atexit time */ + if (_eglModules) { + _eglDestroyArray(_eglModules, _eglFreeModule); + _eglModules = NULL; } +} - return (idx < NUM_PROBE_CACHE_SLOTS && _eglProbeCache.keys[idx] == key) ? - _eglProbeCache.values[idx] : NULL; + +/** + * Invoke a callback function on each EGL search path. + * + * The first argument of the callback function is the name of the search path. + * The second argument is the length of the name. + */ +void +_eglSearchPathForEach(EGLBoolean (*callback)(const char *, size_t, void *), + void *callback_data) +{ + const char *search_path = _eglGetSearchPath(); + _eglPreloadForEach(search_path, callback, callback_data); }