diff options
Diffstat (limited to 'src/egl/loader/loader.c')
-rw-r--r-- | src/egl/loader/loader.c | 244 |
1 files changed, 244 insertions, 0 deletions
diff --git a/src/egl/loader/loader.c b/src/egl/loader/loader.c new file mode 100644 index 0000000000..864746ffd8 --- /dev/null +++ b/src/egl/loader/loader.c @@ -0,0 +1,244 @@ +/* + * Mesa 3-D graphics library + * Version: 7.12 + * + * Copyright (C) 2012 LunarG, Inc. + * + * 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, sublicense, + * 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 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. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <assert.h> +#include <limits.h> +#include "loader.h" + +#if defined(_EGL_OS_WINDOWS) + +typedef HMODULE lib_handle; + +static HMODULE +open_library(const char *filename) +{ + return LoadLibrary(filename); +} + +static __eglMustCastToProperFunctionPointerType +lookup_library(HMODULE lib, const char *sym) +{ + return (__eglMustCastToProperFunctionPointerType) + GetProcAddress(lib, sym); +} + +static void +close_library(HMODULE lib) +{ + FreeLibrary(lib); +} + +static const char * +library_reason(void) +{ + return "unknown error"; +} + +static const char * +library_suffix(void) +{ + return ".dll"; +} + +#elif defined(_EGL_OS_UNIX) + +#include <dlfcn.h> + +typedef void *lib_handle; + +static void * +open_library(const char *filename) +{ + return dlopen(filename, RTLD_LAZY); +} + +static __eglMustCastToProperFunctionPointerType +lookup_library(void *lib, const char *sym) +{ + return (__eglMustCastToProperFunctionPointerType) + dlsym(lib, sym); +} + +static void +close_library(void *lib) +{ + dlclose(lib); +} + +static const char * +library_reason(void) +{ + return dlerror(); +} + +static const char * +library_suffix(void) +{ + return ".so"; +} + +#endif /* _EGL_OS_UNIX */ + +static lib_handle loader_impl; + +void +loader_log(const char *format, ...) +{ + static int loader_debug = -1; + va_list args; + + if (loader_debug < 0) { + const char *env = getenv("EGL_DEBUG"); + loader_debug = (env) ? !!atoi(env) : 0; + } + if (!loader_debug) + return; + + printf("libEGL_loader: "); + va_start(args, format); + vprintf(format, args); + va_end(args); + printf("\n"); +} + +static lib_handle +loader_load_library(const char *path, const char * const *procs, + __eglMustCastToProperFunctionPointerType *entries) +{ + lib_handle impl; + int i; + + impl = open_library(path); + if (!impl) { + loader_log("failed to load %s: %s", path, library_reason()); + return NULL; + } + + for (i = 0; procs[i]; i++) { + __eglMustCastToProperFunctionPointerType ent; + + ent = lookup_library(impl, procs[i]); + + if (!ent) { + loader_log("failed to load %s: %s missing", path, procs[i]); + close_library(impl); + return NULL; + } + + entries[i] = ent; + } + + return impl; +} + +static lib_handle +loader_load_impl(const char *name, const char * const *procs, + __eglMustCastToProperFunctionPointerType *entries) +{ + const char *suffix = library_suffix(); + EGLBoolean is_file = EGL_FALSE; + char path[PATH_MAX]; + + if (suffix) { + size_t len = strlen(name); + size_t slen = strlen(suffix); + + /* assume it is a filename when the suffix matches */ + is_file = (len > slen && !strcmp(name + len - slen, suffix)); + } + else { + suffix = ""; + } + + /* make it a filename */ + if (!is_file) { + int ret; + + ret = snprintf(path, sizeof(path), "libEGL_%s%s.1", name, suffix); + if (ret >= sizeof(path)) + return NULL; + + name = path; + } + + return loader_load_library(name, procs, entries); +} + +static lib_handle +loader_try_impls(EGLNativeDisplayType display_id, const char **candidates, + const char * const *procs, + __eglMustCastToProperFunctionPointerType *entries) +{ + lib_handle impl = NULL; + const char **p; + + for (p = candidates; *p; p++) { + impl = loader_load_impl(*p, procs, entries); + if (impl) { + loader_log("use %s", *p); + break; + } + } + + return impl; +} + +EGLBoolean loader_load_for_display(EGLNativeDisplayType display_id, + const char * const *procs, __eglMustCastToProperFunctionPointerType *entries) +{ + const char *candidates[8]; + int count = 0; + + if (loader_impl) { + close_library(loader_impl); + loader_impl = NULL; + } + + candidates[count] = getenv("EGL_DRIVER"); + if (candidates[count]) { + loader_log("EGL_DRIVER = %s", candidates[count]); + + /* skip "egl_" prefix */ + if (!strncmp(candidates[count], "egl_", 4)) + candidates[count] += 4; + count++; + } + else { + candidates[count++] = "dri2"; + candidates[count++] = "gallium"; + candidates[count++] = "glx"; + } + + assert(count < sizeof(candidates)); + candidates[count] = NULL; + + loader_impl = loader_try_impls(display_id, candidates, procs, entries); + + return (loader_impl != NULL); +} |