summaryrefslogtreecommitdiff
path: root/src/egl/loader/loader.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/egl/loader/loader.c')
-rw-r--r--src/egl/loader/loader.c244
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);
+}