summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEric Anholt <eric@anholt.net>2013-12-02 16:25:02 -0800
committerEric Anholt <eric@anholt.net>2013-12-05 12:38:15 -0800
commit0270c80008e3c6b9f2f5dfba03631f72c7920796 (patch)
tree0f09c960c787fe3a67213f214263d4f983472213 /src
parent111c54992b54f090b63278daa541e29b341bb2ad (diff)
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.
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am24
-rw-r--r--src/dispatch_common.c185
-rw-r--r--src/dispatch_common.h27
-rwxr-xr-xsrc/gen_dispatch.py68
4 files changed, 224 insertions, 80 deletions
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 <string.h>
#include <ctype.h>
#include <stdio.h>
+#include <pthread.h>
+#include <err.h>
#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 <stdbool.h>
#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 <X11/Xlib.h>')
@@ -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()