X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fegl%2Fmain%2Fegldriver.c;h=218b3daef25bf476c601d074183178cb835c647d;hb=b8b3517a49555b5127776272848d8689327db960;hp=2913ce2ece987de3f55462313e6540e41d1ba5ca;hpb=021a68b7e83259faedacea8b3a18e754bed6277a;p=mesa.git diff --git a/src/egl/main/egldriver.c b/src/egl/main/egldriver.c index 2913ce2ece9..218b3daef25 100644 --- a/src/egl/main/egldriver.c +++ b/src/egl/main/egldriver.c @@ -1,3 +1,33 @@ +/************************************************************************** + * + * Copyright 2008 VMware, Inc. + * Copyright 2009-2010 Chia-I Wu + * Copyright 2010-2011 LunarG, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + /** * Functions for choosing and opening/loading device drivers. */ @@ -7,672 +37,88 @@ #include #include #include -#include "eglconfig.h" -#include "eglcontext.h" +#include "c11/threads.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 "eglimage.h" - -#if defined(_EGL_PLATFORM_POSIX) -#include -#include -#include -#include -#endif - - -/** - * Wrappers for dlopen/dlclose() - */ -#if defined(_EGL_PLATFORM_WINDOWS) - - -/* XXX Need to decide how to do dynamic name lookup on Windows */ -static const char DefaultDriverName[] = "TBD"; - -typedef HMODULE lib_handle; - -static HMODULE -open_library(const char *filename) -{ - return LoadLibrary(filename); -} - -static void -close_library(HMODULE lib) -{ - FreeLibrary(lib); -} - - -static const char * -library_suffix(void) -{ - return ".dll"; -} +#include "util/debug.h" -#elif defined(_EGL_PLATFORM_POSIX) +static mtx_t _eglModuleMutex = _MTX_INITIALIZER_NP; +static _EGLDriver *_eglDriver; - -static const char DefaultDriverName[] = "egl_glx"; - -typedef void * lib_handle; - -static void * -open_library(const char *filename) +static _EGLDriver * +_eglGetDriver(void) { - return dlopen(filename, RTLD_LAZY); -} + mtx_lock(&_eglModuleMutex); -static void -close_library(void *lib) -{ - dlclose(lib); -} + if (!_eglDriver) + _eglDriver = _eglBuiltInDriver(); + mtx_unlock(&_eglModuleMutex); -static const char * -library_suffix(void) -{ - return ".so"; + return _eglDriver; } - -#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(). - */ -static _EGLMain_t -_eglOpenLibrary(const char *driverPath, lib_handle *handle) -{ - lib_handle lib; - _EGLMain_t mainFunc = NULL; - const char *error = "unknown error"; - - assert(driverPath); - - _eglLog(_EGL_DEBUG, "dlopen(%s)", driverPath); - lib = open_library(driverPath); - -#if defined(_EGL_PLATFORM_WINDOWS) - /* XXX untested */ - if (lib) - mainFunc = (_EGLMain_t) GetProcAddress(lib, "_eglMain"); -#elif defined(_EGL_PLATFORM_POSIX) - if (lib) { - 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(); - } -#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; - } - - if (!mainFunc) { - _eglLog(_EGL_WARNING, "_eglMain not found in %s (%s)", - driverPath, error); - if (lib) - close_library(lib); - return NULL; - } - - *handle = lib; - return mainFunc; -} - - -/** - * Load the named driver. - */ static _EGLDriver * -_eglLoadDriver(const char *path, const char *args) +_eglMatchAndInitialize(_EGLDisplay *dpy) { - _EGLMain_t mainFunc; - lib_handle lib; - _EGLDriver *drv = NULL; - - mainFunc = _eglOpenLibrary(path, &lib); - if (!mainFunc) - return NULL; - - drv = mainFunc(args); - if (!drv) { - if (lib) - close_library(lib); - return NULL; - } - - if (!drv->Name) { - _eglLog(_EGL_WARNING, "Driver loaded from %s has no name", 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; - } - - drv->LibHandle = lib; + if (_eglGetDriver()) + if (_eglDriver->API.Initialize(_eglDriver, dpy)) + return _eglDriver; - return drv; + return NULL; } - /** - * Match a display to a preloaded driver. - * - * The matching is done by finding the driver with the highest score. + * Match a display to a driver. The matching is done by finding the first + * driver that can initialize the display. */ _EGLDriver * _eglMatchDriver(_EGLDisplay *dpy) { - _EGLDriver *best_drv = NULL; - EGLint best_score = -1, i; + _EGLDriver *best_drv; - /* - * 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; + assert(!dpy->Initialized); - 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); - } + /* set options */ + dpy->Options.ForceSoftware = + env_var_as_boolean("LIBGL_ALWAYS_SOFTWARE", false); - best_drv = drv; - best_score = score; - /* perfect match */ - if (score >= 100) - break; - } + best_drv = _eglMatchAndInitialize(dpy); + if (!best_drv && !dpy->Options.ForceSoftware) { + dpy->Options.ForceSoftware = EGL_TRUE; + best_drv = _eglMatchAndInitialize(dpy); } - return best_drv; -} - - -/** - * 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 -_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); - - /* 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'; - - if (library_suffix() == NULL || strstr(path, library_suffix())) - drv = _eglLoadDriver(path, NULL); - else { - 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 && len + slen + 1 <= sizeof(path)) { - strcpy(path + len, suffix); - drv = _eglLoadDriver(path, NULL); - } else { - drv = NULL; - } + if (best_drv) { + _eglLog(_EGL_DEBUG, "the best driver is %s", + best_drv->Name); + dpy->Driver = best_drv; + dpy->Initialized = EGL_TRUE; } - if (!drv) - return EGL_TRUE; - - /* remember the driver and stop */ - _eglGlobal.Drivers[_eglGlobal.NumDrivers++] = drv; - return EGL_FALSE; -} - - -/** - * 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_PLATFORM_POSIX) - 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))) { - _EGLDriver *drv; - 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 load the driver */ - if (len + dirent_len + 1 <= sizeof(path)) { - strcpy(path + len, dirent->d_name); - drv = _eglLoadDriver(path, NULL); - if (drv) - _eglGlobal.Drivers[_eglGlobal.NumDrivers++] = drv; - } - } - - closedir(dirp); - - return EGL_TRUE; -#else /* _EGL_PLATFORM_POSIX */ - /* stop immediately */ - return EGL_FALSE; -#endif -} - - -/** - * Run the preload function on each driver directory and return the number of - * drivers loaded. - * - * The process may end prematurely if the callback function returns false. - */ -static EGLint -_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) { - next = strchr(cur, ':'); - len = (next) ? next - cur : strlen(cur); - if (!loader(cur, len, loader_data)) - break; - - cur = (next) ? next + 1 : NULL; - } - - return (_eglGlobal.NumDrivers - num_drivers); -} - - -/** - * Return a list of colon-separated driver directories. - */ -static const char * -_eglGetSearchPath(void) -{ - static const char *search_path; - -#if defined(_EGL_PLATFORM_POSIX) || defined(_EGL_PLATFORM_WINDOWS) - if (!search_path) { - static char buffer[1024]; - const char *p; - int ret; - - p = getenv("EGL_DRIVERS_PATH"); -#if defined(_EGL_PLATFORM_POSIX) - if (p && (geteuid() != getuid() || getegid() != getgid())) { - _eglLog(_EGL_DEBUG, - "ignore EGL_DRIVERS_PATH for setuid/setgid binaries"); - p = NULL; - } -#endif /* _EGL_PLATFORM_POSIX */ - - if (p) { - ret = snprintf(buffer, sizeof(buffer), - "%s:%s", p, _EGL_DRIVER_SEARCH_DIR); - if (ret > 0 && ret < sizeof(buffer)) - search_path = buffer; - } - } - if (!search_path) - search_path = _EGL_DRIVER_SEARCH_DIR; -#else - search_path = ""; -#endif - - return search_path; -} - - -/** - * Preload a user driver. - * - * A user driver can be specified by EGL_DRIVER. - */ -static EGLBoolean -_eglPreloadUserDriver(void) -{ - const char *search_path = _eglGetSearchPath(); - char *env; - - env = getenv("EGL_DRIVER"); -#if defined(_EGL_PLATFORM_POSIX) - 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_PLATFORM_POSIX */ - if (!env) - return EGL_FALSE; - - 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 display drivers. - * - * Display drivers are a set of drivers that support a certain display system. - * The display system may be specified by EGL_DISPLAY. - * - * FIXME This makes libEGL a memory hog if an user driver is not specified and - * there are many display drivers. - */ -static EGLBoolean -_eglPreloadDisplayDrivers(void) -{ - const char *dpy; - char prefix[32]; - int ret; - - dpy = getenv("EGL_DISPLAY"); - if (!dpy || !dpy[0]) - dpy = _EGL_DEFAULT_DISPLAY; - if (!dpy || !dpy[0]) - return EGL_FALSE; - - ret = snprintf(prefix, sizeof(prefix), "egl_%s_", dpy); - if (ret < 0 || ret >= sizeof(prefix)) - return EGL_FALSE; - - return (_eglPreloadForEach(_eglGetSearchPath(), - _eglLoaderPattern, (void *) prefix) > 0); -} - - -/** - * Preload the default driver. - */ -static EGLBoolean -_eglPreloadDefaultDriver(void) -{ - return (_eglPreloadForEach(_eglGetSearchPath(), - _eglLoaderFile, (void *) DefaultDriverName) > 0); + return best_drv; } - -/** - * Preload drivers. - * - * This function loads the driver modules and creates the corresponding - * _EGLDriver objects. - */ -EGLBoolean -_eglPreloadDrivers(void) +__eglMustCastToProperFunctionPointerType +_eglGetDriverProc(const char *procname) { - EGLBoolean loaded; - - /* protect the preloading process */ - _eglLockMutex(_eglGlobal.Mutex); - - /* already preloaded */ - if (_eglGlobal.NumDrivers) { - _eglUnlockMutex(_eglGlobal.Mutex); - return EGL_TRUE; - } + if (_eglGetDriver()) + return _eglDriver->API.GetProcAddress(_eglDriver, procname); - loaded = (_eglPreloadUserDriver() || - _eglPreloadDisplayDrivers() || - _eglPreloadDefaultDriver()); - - _eglUnlockMutex(_eglGlobal.Mutex); - - return loaded; + return NULL; } - /** - * Unload preloaded drivers. + * Unload all drivers. */ void _eglUnloadDrivers(void) { - EGLint i; - /* 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; - } - - _eglGlobal.NumDrivers = 0; -} - - -/** - * Plug all the available fallback routines into the given driver's - * dispatch table. - */ -void -_eglInitDriverFallbacks(_EGLDriver *drv) -{ - /* 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 */ - -#ifdef EGL_KHR_image_base - drv->API.CreateImageKHR = _eglCreateImageKHR; - drv->API.DestroyImageKHR = _eglDestroyImageKHR; -#endif /* EGL_KHR_image_base */ -} - - -/** - * 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); -} - - -/** - * 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; + free(_eglDriver); + _eglDriver = NULL; }