diff options
author | Chia-I Wu <olv@lunarg.com> | 2011-12-22 16:20:04 +0800 |
---|---|---|
committer | Chia-I Wu <olv@lunarg.com> | 2011-12-28 15:46:33 +0800 |
commit | f554bc27ec50fc2d6e790db15eb5235ae70a9d2d (patch) | |
tree | ea3f1aae43098fb66aebf7be62e253d1bd4a3c71 | |
parent | 6dd1dcc91d0ed291a5a8a37f9d3e90755d0b90e3 (diff) |
egl/loader: add libEGL_loadernew-egl
-rw-r--r-- | src/egl/loader/Makefile | 55 | ||||
-rw-r--r-- | src/egl/loader/loader.c | 244 | ||||
-rw-r--r-- | src/egl/loader/loader.h | 36 | ||||
-rw-r--r-- | src/egl/main/eglapi.py | 160 |
4 files changed, 495 insertions, 0 deletions
diff --git a/src/egl/loader/Makefile b/src/egl/loader/Makefile new file mode 100644 index 0000000000..f9c56560d6 --- /dev/null +++ b/src/egl/loader/Makefile @@ -0,0 +1,55 @@ +# src/egl/loader/Makefile + +TOP = ../../.. +include $(TOP)/configs/current + +EGL_MAJOR := 1 +EGL_MINOR := 0 + +INCLUDE_DIRS := \ + -I$(TOP)/include \ + -I$(TOP)/src/egl/core + +LOCAL_CFLAGS := \ + $(INCLUDE_DIRS) \ + -D_EGL_OS_UNIX + +SOURCES := \ + egl.c \ + loader.c + +OBJECTS := $(SOURCES:.c=.o) + +.c.o: + $(CC) -c $(LOCAL_CFLAGS) $(CFLAGS) $< -o $@ + +default: depend library + +# EGL Library +library: $(TOP)/$(LIB_DIR)/$(EGL_LIB_NAME) + +$(TOP)/$(LIB_DIR)/$(EGL_LIB_NAME): $(OBJECTS) + $(MKLIB) -o $(EGL_LIB) -linker '$(CC)' -ldflags '$(LDFLAGS)' \ + -major $(EGL_MAJOR) -minor $(EGL_MINOR) \ + -install $(TOP)/$(LIB_DIR) $(MKLIB_OPTIONS) \ + -L$(TOP)/$(LIB_DIR) $(EGL_LIB_DEPS) \ + $(OBJECTS) + +egl.c: $(TOP)/src/egl/main/egl.py + $(PYTHON2) $(PYTHON_FLAGS) $< loader > $@ + +install: library + +clean: + -rm -f *.o + -rm -f depend depend.bak + +depend: $(SOURCES) + @ echo "running $(MKDEP)" + @ rm -f depend + @ touch depend + $(MKDEP) $(MKDEP_OPTIONS) $(DEFINES) $(INCLUDE_DIRS) \ + $(SOURCES) > /dev/null 2>/dev/null + +-include depend +# DO NOT DELETE 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); +} diff --git a/src/egl/loader/loader.h b/src/egl/loader/loader.h new file mode 100644 index 0000000000..9c9556ecc1 --- /dev/null +++ b/src/egl/loader/loader.h @@ -0,0 +1,36 @@ +/* + * 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. + */ + +#ifndef _LOADER_H +#define _LOADER_H + +#include <EGL/egl.h> + +void loader_log(const char *format, ...); + +EGLBoolean loader_load_for_display(EGLNativeDisplayType display_id, + const char * const * procs, __eglMustCastToProperFunctionPointerType *entries); + +#endif /* _LOADER_H */ diff --git a/src/egl/main/eglapi.py b/src/egl/main/eglapi.py index 7af5673657..95ab352662 100644 --- a/src/egl/main/eglapi.py +++ b/src/egl/main/eglapi.py @@ -522,6 +522,165 @@ class EGLDriverTableCodeGen(EGLCodeGen): print print '#endif /* EGLAPI_INCLUDED */' +class EGLLoaderCodeGen(EGLCodeGen): + """eglloader.c generator.""" + + def __init__(self): + api = egl_1_4 + + self.api_functions = api + + loader_functions = [] + for func in api: + loader_name = '_eglLoader' + func.name[3:] + loader_func = Function(func.ret, loader_name, func.args) + loader_functions.append(loader_func) + + self.loader_functions = loader_functions + + def gen_header(self): + print '/* DO NOT EDIT - This file is automatically generated. */' + print + print '#include <EGL/egl.h>' + print '#include "eglmutex.h"' + print '#include "loader.h"' + + def gen_static_vars(self): + # declare loader's version of EGL + print + for func in self.loader_functions: + print 'static %s;' % func.c_proto(True) + + # generate dispatch table struct + print + print 'struct _eglLoaderDispatchTable {' + for func in self.api_functions: + print ' %s (EGLAPIENTRYP %s)(%s);' \ + % (func.ret, func.name, func.join_args()) + print '};' + + initializer = [] + for func in self.loader_functions: + initializer.append(' ' + func.name) + + # generate dispatch table + print + print 'static struct _eglLoaderDispatchTable _eglLoaderDispatch[2] = {' + print ' {' + print ',\n'.join(initializer) + print ' },' + print ' { NULL }' + print '};' + print + print '/* 0: use loader\'s, 1: use implementation\'s */' + print 'static int _eglLoaderDispatchIndex = 0;' + print + print 'static const char * const _eglLoaderNames[] = {' + for func in self.api_functions: + print ' "%s",' % func.name + print ' NULL' + print '};' + + # generate loader error state + # + # These are really minor, but + # + # - loader_error should be thread-local + # - loader_error should be propogated into the implementation somehow + # when the dispatch table is initialized + print + print 'static EGLint _eglLoaderError = EGL_SUCCESS;' + + def gen_helpers(self): + # gen error setting function + print + print 'static void _eglLoaderSetError(EGLint err)' + print '{' + print ' _eglLoaderError = err;' + print '}' + + # generate dispatch table init function + print + print '/* initialize and switch dispatch table */' + print 'static EGLBoolean' + print '_eglLoaderInitDispatch(EGLNativeDisplayType display_id)' + print '{' + print ' static _EGLMutex mutex = _EGL_MUTEX_INITIALIZER;' + print ' static EGLBoolean initialized = EGL_FALSE;' + print ' EGLBoolean update = EGL_FALSE;' + print + print ' _eglLockMutex(&mutex);' + print ' if (!initialized) {' + print ' update = loader_load_for_display(display_id, _eglLoaderNames,' + print ' (__eglMustCastToProperFunctionPointerType *) &_eglLoaderDispatch[1]);' + print ' initialized = EGL_TRUE;' + print ' }' + print ' _eglUnlockMutex(&mutex);' + print + print ' if (update)' + print ' _eglLoaderDispatchIndex = 1;' + print + print ' return (_eglLoaderDispatchIndex == 1);' + print '}' + + def gen_loader(self): + trigger_init = ( + 'eglBindAPI', + 'eglGetDisplay', + 'eglGetProcAddress', + 'eglQueryAPI', + ) + + for i in xrange(len(self.api_functions)): + func = self.api_functions[i] + loader_func = self.loader_functions[i] + + print + print 'static %s' % loader_func.c_proto() + print '{' + if func.name in trigger_init: + display_id = 'EGL_DEFAULT_DISPLAY' + if func.args and func.args[0][0] == 'EGLNativeDisplayType': + display_id = func.args[0][1] + + # initialize the dispatch table and dispatch + print ' if (!_eglLoaderInitDispatch(%s))' % display_id + print ' return %s;' % func.return_failure() + print ' return _eglLoaderDispatch[1].%s;' % func.c_call() + elif func.args and func.args[0][0] == 'EGLDisplay': + # record EGL_BAD_DISPLAY and return failure + print ' _eglLoaderSetError(EGL_BAD_DISPLAY);' + print ' return %s;' % func.return_failure() + else: + # record EGL_SUCCESS and return success + if func.name == 'eglGetError': + print ' EGLint err = _eglLoaderError;' + ret = 'err' + elif func.ret == 'EGLBoolean': + ret = 'EGL_TRUE' + else: + # the value of failure is also the value of success + ret = func.return_failure() + + print ' _eglLoaderSetError(EGL_SUCCESS);' + print ' return %s;' % ret + print '}' + + def gen_api(self): + for func in self.api_functions: + print + print func.c_proto() + print '{' + print ' return _eglLoaderDispatch[_eglLoaderDispatchIndex].%s;' \ + % func.c_call() + print '}' + + def gen_body(self): + self.gen_static_vars() + self.gen_helpers() + self.gen_loader() + self.gen_api() + if __name__ == '__main__': import sys @@ -529,6 +688,7 @@ if __name__ == '__main__': 'api': EGLAPICodeGen, 'apidispatch': EGLAPIDispatchCodeGen, 'drivertable': EGLDriverTableCodeGen, + 'loader': EGLLoaderCodeGen, } if len(sys.argv) != 2 or sys.argv[1] not in codegens: |