From 0270c80008e3c6b9f2f5dfba03631f72c7920796 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Mon, 2 Dec 2013 16:25:02 -0800 Subject: Add support for EGL. This totally replaces the getprocaddress and dlsym code, which was basically just stubs up until now. The is_glx/is_egl() is also dropped -- they weren't doing anything, and the only false answer they could give is if the dlopen were to fail. --- src/Makefile.am | 24 +++++++ src/dispatch_common.c | 185 +++++++++++++++++++++++++++++++++++++++++--------- src/dispatch_common.h | 27 +++----- src/gen_dispatch.py | 68 +++++++++++-------- 4 files changed, 224 insertions(+), 80 deletions(-) (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index 720498a..897fa16 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -31,6 +31,7 @@ lib_LTLIBRARIES = libepoxy.la epoxyinclude_DATA = \ $(GL_INCLUDES) \ $(GLX_INCLUDES) \ + $(EGL_INCLUDES) \ $() GL_INCLUDES = \ @@ -43,6 +44,11 @@ GLX_INCLUDES = \ $(GENERATED_GLX_INCLUDES) \ $() +EGL_INCLUDES = \ + ../include/epoxy/egl.h \ + $(GENERATED_EGL_INCLUDES) \ + $() + GENERATED_GL_INCLUDES = \ $(builddir)/../include/epoxy/gl_generated.h \ $(builddir)/../include/epoxy/gl_generated_vtable_defines.h \ @@ -53,6 +59,11 @@ GENERATED_GLX_INCLUDES = \ $(builddir)/../include/epoxy/glx_generated_vtable_defines.h \ $() +GENERATED_EGL_INCLUDES = \ + $(tuilddir)/../include/epoxy/egl_generated.h \ + $(builddir)/../include/epoxy/egl_generated_vtable_defines.h \ + $() + GENERATED_GL_SOURCE = gl_generated_dispatch.c GENERATED_GL = \ @@ -67,9 +78,17 @@ GENERATED_GLX = \ $(GENERATED_GLX_INCLUDES) \ $() +GENERATED_EGL_SOURCE = egl_generated_dispatch.c + +GENERATED_EGL = \ + $(GENERATED_EGL_SOURCE) \ + $(GENERATED_EGL_INCLUDES) \ + $() + BUILT_SOURCES = \ $(GENERATED_GL) \ $(GENERATED_GLX) \ + $(GENERATED_EGL) \ $() CLEANFILES = $(BUILT_SOURCES) @@ -82,6 +101,7 @@ libepoxy_la_SOURCES = \ # These are generated alongside the .c file. $(GENERATED_GL_INCLUDES): $(GENERATED_GL_SOURCE) $(GENERATED_GLX_INCLUDES): $(GENERATED_GLX_SOURCE) +$(GENERATED_EGL_INCLUDES): $(GENERATED_EGL_SOURCE) $(GENERATED_GL_SOURCE): $(srcdir)/gen_dispatch.py $(top_srcdir)/registry/gl.xml $(MKDIR_P) $(top_builddir)/include/epoxy @@ -90,3 +110,7 @@ $(GENERATED_GL_SOURCE): $(srcdir)/gen_dispatch.py $(top_srcdir)/registry/gl.xml $(GENERATED_GLX_SOURCE): $(srcdir)/gen_dispatch.py $(top_srcdir)/registry/glx.xml $(MKDIR_P) $(top_builddir)/include/epoxy $(AM_V_GEN)$(PYTHON) $(srcdir)/gen_dispatch.py --dir $(top_builddir) $(top_srcdir)/registry/glx.xml + +$(GENERATED_EGL_SOURCE): $(srcdir)/gen_dispatch.py $(top_srcdir)/registry/egl.xml + $(MKDIR_P) $(top_builddir)/include/epoxy + $(AM_V_GEN)$(PYTHON) $(srcdir)/gen_dispatch.py --dir $(top_builddir) $(top_srcdir)/registry/egl.xml diff --git a/src/dispatch_common.c b/src/dispatch_common.c index 31885fb..90ff92a 100644 --- a/src/dispatch_common.c +++ b/src/dispatch_common.c @@ -93,14 +93,67 @@ #include #include #include +#include +#include #include "epoxy/gl.h" #include "epoxy/glx.h" +#include "epoxy/egl.h" #include "dispatch_common.h" -/* XXX: Make this thread local */ -struct api local_api; +struct api { + /** + * Locking for making sure we don't double-dlopen(). + */ + pthread_mutex_t mutex; + + /** dlopen() return value for libGL.so.1. */ + void *glx_handle; + + /** dlopen() return value for libEGL.so.1 */ + void *egl_handle; + + /** dlopen() return value for libGLESv1_CM.so.1 */ + void *gles1_handle; + + /** dlopen() return value for libGLESv2.so.2 */ + void *gles2_handle; +}; + +static struct api api = { + .mutex = PTHREAD_MUTEX_INITIALIZER, +}; + +static void +get_dlopen_handle(void **handle, const char *lib_name, bool exit_on_fail) +{ + if (*handle) + return; + + pthread_mutex_lock(&api.mutex); + if (!*handle) { + *handle = dlopen(lib_name, RTLD_LAZY | RTLD_LOCAL); + if (!*handle && exit_on_fail) { + fprintf(stderr, "Couldn't open %s: %s", lib_name, dlerror()); + exit(1); + } + } + pthread_mutex_unlock(&api.mutex); +} + +static void * +do_dlsym(void **handle, const char *lib_name, const char *name, + bool exit_on_fail) +{ + void *result; + + get_dlopen_handle(handle, lib_name, exit_on_fail); -struct api *api = &local_api; + result = dlsym(*handle, name); + if (!result) + errx(1, "%s() not found in %s", name, lib_name); + + return result; +} PUBLIC bool epoxy_is_desktop_gl(void) @@ -132,12 +185,6 @@ epoxy_gl_version(void) return 10 * major + minor; } -PUBLIC bool -epoxy_is_glx(void) -{ - return true; /* XXX */ -} - /** * If we can determine the GLX version from the current context, then * return that, otherwise return a version that will just send us on @@ -183,6 +230,30 @@ epoxy_glx_version(Display *dpy, int screen) return server; } +PUBLIC int +epoxy_conservative_egl_version(void) +{ + EGLDisplay *dpy = eglGetCurrentDisplay(); + + if (!dpy) + return 14; + + return epoxy_egl_version(dpy); +} + +PUBLIC int +epoxy_egl_version(EGLDisplay *dpy) +{ + int major, minor; + const char *version_string; + int ret; + + version_string = eglQueryString(dpy, EGL_VERSION); + ret = sscanf(version_string, "%d.%d", &major, &minor); + assert(ret == 2); + return major * 10 + minor; +} + static bool epoxy_extension_in_string(const char *extension_list, const char *ext) { @@ -204,13 +275,22 @@ epoxy_has_gl_extension(const char *ext) ext); } -#if 0 +bool +epoxy_conservative_has_egl_extension(const char *ext) +{ + EGLDisplay *dpy = eglGetCurrentDisplay(); + + if (!dpy) + return true; + + return epoxy_has_egl_extension(dpy, ext); +} + PUBLIC bool -epoxy_has_egl_extension(const char *ext) +epoxy_has_egl_extension(EGLDisplay *dpy, const char *ext) { - return epoxy_extension_in_string(eglQueryString(EGL_EXTENSIONS), ext); + return epoxy_extension_in_string(eglQueryString(dpy, EGL_EXTENSIONS), ext); } -#endif /** * If we can determine the GLX extension support from the current @@ -234,7 +314,7 @@ epoxy_conservative_has_glx_extension(const char *ext) PUBLIC bool epoxy_has_glx_extension(Display *dpy, int screen, const char *ext) -{ + { /* No, you can't just use glXGetClientString or * glXGetServerString() here. Those each tell you about one half * of what's needed for an extension to be supported, and @@ -245,37 +325,78 @@ epoxy_has_glx_extension(Display *dpy, int screen, const char *ext) } void * -epoxy_dlsym(const char *name) +epoxy_egl_dlsym(const char *name) { - assert(api->gl_handle); - return dlsym(api->gl_handle, name); + return do_dlsym(&api.egl_handle, "libEGL.so.1", name, true); } void * -epoxy_get_proc_address(const char *name) +epoxy_glx_dlsym(const char *name) { - return glXGetProcAddress((const GLubyte *)name); + return do_dlsym(&api.glx_handle, "libGL.so.1", name, true); } -void -epoxy_glx_autoinit(void) +void * +epoxy_gl_dlsym(const char *name) { - if (api->gl_handle) - return; + /* There's no library for desktop GL support independent of GLX. */ + return epoxy_glx_dlsym(name); +} - api->gl_handle = dlopen("libGL.so.1", RTLD_LAZY | RTLD_LOCAL); - if (!api->gl_handle) { - fprintf(stderr, "Couldn't open libGL.so.1: %s", dlerror()); - exit(1); - } +void * +epoxy_gles1_dlsym(const char *name) +{ + return do_dlsym(&api.gles1_handle, "libGLESv1_CM.so.1", name, true); +} - api->winsys_handle = api->gl_handle; +void * +epoxy_gles2_dlsym(const char *name) +{ + return do_dlsym(&api.gles1_handle, "libGLESv2.so.2", name, true); } -void -epoxy_platform_autoinit(void) +void * +epoxy_get_proc_address(const char *name) { - epoxy_glx_autoinit(); + if (api.egl_handle) { + return eglGetProcAddress(name); + } else if (api.glx_handle) { + return glXGetProcAddressARB((const GLubyte *)name); + } else { + /* If the application hasn't explicitly called some of our GLX + * or EGL code but has presumably set up a context on its own, + * then we need to figure out how to getprocaddress anyway. + * + * If there's a public GetProcAddress loaded in the + * application's namespace, then use that. + */ + PFNGLXGETPROCADDRESSARBPROC glx_gpa; + PFNEGLGETPROCADDRESSPROC egl_gpa; + + egl_gpa = dlsym(NULL, "eglGetProcAddress"); + if (egl_gpa) + return egl_gpa(name); + + glx_gpa = dlsym(NULL, "glXGetProcAddressARB"); + if (glx_gpa) + return glx_gpa((const GLubyte *)name); + + /* OK, couldn't find anything in the app's address space. + * Presumably they dlopened with RTLD_LOCAL, which hides it + * from us. Just go dlopen()ing likely libraries and try them. + */ + egl_gpa = do_dlsym(&api.egl_handle, "libEGL.so.1", "eglGetProcAddress", + false); + if (egl_gpa) + return egl_gpa(name); + + return do_dlsym(&api.glx_handle, "libGL.so.1", "glXGetProcAddressARB", + false); + if (glx_gpa) + return glx_gpa((const GLubyte *)name); + + errx(1, "Couldn't find GLX or EGL libraries.\n"); + } } void diff --git a/src/dispatch_common.h b/src/dispatch_common.h index 701c59c..34163ec 100644 --- a/src/dispatch_common.h +++ b/src/dispatch_common.h @@ -23,6 +23,7 @@ #include #include "epoxy/gl.h" +#include "epoxy/egl.h" #include "epoxy/glx.h" #ifndef PUBLIC @@ -33,27 +34,17 @@ # endif #endif -struct api { - bool is_glx; - bool is_gl; - bool is_gles1; - bool is_gles2; /**< Also GLES3 */ - - /** dlopen() return value for libGL.so.1, libGLESv2.so.1, etc. */ - void *gl_handle; - - /** dlopen() return value for libGL.so.1 or libEGL.so.1 */ - void *winsys_handle; -}; - -bool epoxy_is_glx(void); - +void *epoxy_egl_dlsym(const char *name); +void *epoxy_glx_dlsym(const char *name); +void *epoxy_gl_dlsym(const char *name); +void *epoxy_gles1_dlsym(const char *name); +void *epoxy_gles2_dlsym(const char *name); void *epoxy_get_proc_address(const char *name); + int epoxy_conservative_glx_version(void); bool epoxy_conservative_has_glx_extension(const char *name); -void *epoxy_dlsym(const char *name); -void epoxy_glx_autoinit(void); -void epoxy_platform_autoinit(void); +int epoxy_conservative_egl_version(void); +bool epoxy_conservative_has_egl_extension(const char *name); void epoxy_print_failure_reasons(const char *name, const char **provider_names, const int *providers); diff --git a/src/gen_dispatch.py b/src/gen_dispatch.py index 4310246..168112b 100755 --- a/src/gen_dispatch.py +++ b/src/gen_dispatch.py @@ -116,9 +116,6 @@ class Generator(object): self.typedefs = '' self.out_file = None - self.dlsym_loader = 'epoxy_dlsym({0})' - self.gpa_loader = 'epoxy_get_proc_address({0})' - # Dictionary mapping human-readable names of providers to a C # enum token that will be used to reference those names, to # reduce generated binary size. @@ -266,36 +263,41 @@ class Generator(object): # else is supposed to not be present, so you have to # glXGetProcAddress() it. if version <= 12: - loader = self.dlsym_loader + loader = 'epoxy_gl_dlsym({0})' else: - loader = self.gpa_loader + loader = 'epoxy_get_proc_address({0})' condition += ' && epoxy_gl_version() >= {0}'.format(version) elif api == 'gles2': human_name = 'OpenGL ES {0}'.format(feature.get('number')) condition = '!epoxy_is_desktop_gl() && epoxy_gl_version() >= {0}'.format(version) if version <= 20: - loader = self.dlsym_loader + loader = 'epoxy_gles2_dlsym({0})' else: - loader = self.gpa_loader + loader = 'epoxy_get_proc_address({0})' elif api == 'gles1': human_name = 'OpenGL ES 1.0' condition = '!epoxy_is_desktop_gl() && epoxy_gl_version() == 10' - - if version <= 20: - loader = self.dlsym_loader - else: - loader = self.gpa_loader + loader = 'epoxy_gles1_dlsym({0})' elif api == 'glx': human_name = 'GLX {0}'.format(version) - condition = 'epoxy_is_glx()' - # We could just always use GPA, but dlsym() is a more + # We could just always use GPA for loading everything + # but glXGetProcAddress(), but dlsym() is a more # efficient lookup. if version > 13: - condition = condition + ' && epoxy_conservative_glx_version() >= {0}'.format(version) - loader = self.gpa_loader + condition = 'epoxy_conservative_glx_version() >= {0}'.format(version) + loader = 'glXGetProcAddress((const GLubyte *){0})' + else: + condition = 'true' + loader = 'epoxy_glx_dlsym({0})' + elif api == 'egl': + human_name = 'EGL {0}'.format(version) + if version > 10: + condition = 'epoxy_conservative_egl_version() >= {0}'.format(version) + loader = 'eglGetProcAddress({0})' else: - loader = self.dlsym_loader + condition = 'true' + loader = 'epoxy_egl_dlsym({0})' else: sys.exit('unknown API: "{0}"'.format(api)) @@ -309,15 +311,20 @@ class Generator(object): if 'glx' in apis: human_name = 'GLX extension \\"{0}\\"'.format(extname) condition = 'epoxy_conservative_has_glx_extension("{0}")'.format(extname) - loader = self.gpa_loader + loader = 'glXGetProcAddress((const GLubyte *){0})' + self.process_require_statements(extension, condition, loader, human_name) + if 'egl' in apis: + human_name = 'EGL extension \\"{0}\\"'.format(extname) + condition = 'epoxy_conservative_has_egl_extension("{0}")'.format(extname) + loader = 'eglGetProcAddress({0})' self.process_require_statements(extension, condition, loader, human_name) if 'gl' in apis: human_name = 'GL extension \\"{0}\\"'.format(extname) condition = 'epoxy_has_gl_extension("{0}")'.format(extname) - loader = self.gpa_loader + loader = 'epoxy_get_proc_address({0})' self.process_require_statements(extension, condition, loader, human_name) - def fixup_bootstrap_function(self, name): + def fixup_bootstrap_function(self, name, loader): # We handle glGetString() and glGetIntegerv() specially, because we # need to use them in the process of deciding on loaders for # resolving, and the naive code generation would result in their @@ -327,7 +334,7 @@ class Generator(object): func = self.functions[name] func.providers = {} - func.add_provider('true', self.dlsym_loader, 'always present') + func.add_provider('true', loader, 'always present') def parse(self, file): reg = ET.parse(file) @@ -375,6 +382,8 @@ class Generator(object): if self.target != "gl": self.outln('#include "epoxy/gl_generated.h"') + if self.target == "egl": + self.outln('#include "EGL/eglplatform.h"') else: # Add some ridiculous inttypes.h redefinitions that are from # khrplatform.h and not included in the XML. @@ -389,6 +398,8 @@ class Generator(object): self.outln('typedef float khronos_float_t;') self.outln('typedef intptr_t khronos_intptr_t;') self.outln('typedef ptrdiff_t khronos_ssize_t;') + self.outln('typedef uint64_t khronos_utime_nanoseconds_t;') + self.outln('typedef int64_t khronos_stime_nanoseconds_t;') if self.target == "glx": self.outln('#include ') @@ -435,12 +446,6 @@ class Generator(object): self.outln(' "{0}",'.format(provider.name)) self.outln(' };') - if 'glX' in func.name: - self.outln(' epoxy_glx_autoinit();') - else: - self.outln(' epoxy_platform_autoinit();') - self.outln('') - self.outln(' return {0}_provider_resolver("{1}",'.format(self.target, func.name)) self.outln(' providers, entrypoints);') @@ -583,13 +588,16 @@ for file in args.files: generator.drop_weird_glx_functions() generator.sort_functions() generator.resolve_aliases() - generator.fixup_bootstrap_function('glGetString') - generator.fixup_bootstrap_function('glGetIntegerv') + generator.fixup_bootstrap_function('glGetString', + 'epoxy_get_proc_address({0})') + generator.fixup_bootstrap_function('glGetIntegerv', + 'epoxy_get_proc_address({0})') # While this is technically exposed as a GLX extension, it's # required to be present as a public symbol by the Linux OpenGL # ABI. - generator.fixup_bootstrap_function('glXGetProcAddress') + generator.fixup_bootstrap_function('glXGetProcAddress', + 'epoxy_glx_dlsym({0})') generator.prepare_provider_enum() -- cgit v1.2.3