summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore4
-rw-r--r--include/epoxy/egl.h63
-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
-rw-r--r--test/Makefile.am14
-rw-r--r--test/egl_common.c50
-rw-r--r--test/egl_common.h25
-rw-r--r--test/egl_has_extension_nocontext.c70
-rw-r--r--test/headerguards.c3
11 files changed, 452 insertions, 81 deletions
diff --git a/.gitignore b/.gitignore
index 91370fa..ebc2d87 100644
--- a/.gitignore
+++ b/.gitignore
@@ -89,3 +89,7 @@ gl_generated_vtable_defines.h
glx_generated_dispatch.c
glx_generated.h
glx_generated_vtable_defines.h
+
+egl_generated_dispatch.c
+egl_generated.h
+egl_generated_vtable_defines.h
diff --git a/include/epoxy/egl.h b/include/epoxy/egl.h
new file mode 100644
index 0000000..e30f515
--- /dev/null
+++ b/include/epoxy/egl.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright © 2013 Intel Corporation
+ *
+ * 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 (including the next
+ * paragraph) 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.
+ */
+
+/** @file egl.h
+ *
+ * Provides an implementation of a EGL dispatch layer using a hidden
+ * vtable.
+ *
+ * This is a lower performance path than ifuncs when they are
+ * available, but it is required if you might have multiple return
+ * values for GetProcAddress/dlsym()ed functions (for example, if you
+ * unload libGL.so.1).
+ */
+
+#ifndef __EPOXY_EGL_H
+#define __EPOXY_EGL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdbool.h>
+
+#if defined(__egl_h_) || defined(__eglext_h_)
+#error epoxy/egl.h must be included before (or in place of) GL/egl.h
+#else
+#define __egl_h_
+#define __eglext_h_
+#endif
+
+#pragma once
+
+#include "epoxy/egl_generated.h"
+#include "epoxy/egl_generated_vtable_defines.h"
+
+bool epoxy_has_egl_extension(EGLDisplay *dpy, const char *extension);
+int epoxy_egl_version(EGLDisplay *dpy);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* __EPOXY_EGL_H */
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()
diff --git a/test/Makefile.am b/test/Makefile.am
index 81263b0..01fdc65 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -20,7 +20,15 @@
EPOXY = $(builddir)/../src/libepoxy.la
-check_LTLIBRARIES = libglx_common.la
+check_LTLIBRARIES = \
+ libegl_common.la \
+ libglx_common.la \
+ $()
+
+libegl_common_la_SOURCES = \
+ egl_common.c \
+ egl_common.h
+ $()
libglx_common_la_SOURCES = \
glx_common.c \
@@ -32,6 +40,7 @@ AM_CPPFLAGS = \
$(X11_CFLAGS)
TESTS = \
+ egl_has_extension_nocontext \
glx_public_api \
glx_glxgetprocaddress_nocontext \
glx_has_extension_nocontext \
@@ -40,6 +49,9 @@ TESTS = \
check_PROGRAMS = $(TESTS)
+egl_has_extension_nocontext_LDFLAGS = $(X11_LIBS) $(EPOXY) libegl_common.la
+egl_has_extension_nocontext_DEPENDENCIES = libegl_common.la
+
glx_public_api_LDFLAGS = $(X11_LIBS) $(EPOXY) libglx_common.la
glx_public_api_DEPENDENCIES = libglx_common.la
diff --git a/test/egl_common.c b/test/egl_common.c
new file mode 100644
index 0000000..4cc0409
--- /dev/null
+++ b/test/egl_common.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright © 2013 Intel Corporation
+ *
+ * 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 (including the next
+ * paragraph) 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 <err.h>
+#include <epoxy/egl.h>
+
+/**
+ * Do whatever it takes to get us an EGL display for the system.
+ *
+ * This needs to be ported to other window systems.
+ */
+EGLDisplay *
+get_egl_display_or_skip(void)
+{
+ Display *dpy = XOpenDisplay(NULL);
+ EGLint major, minor;
+
+ if (!dpy)
+ errx(77, "couldn't open display\n");
+
+ EGLDisplay *edpy = eglGetDisplay(dpy);
+ if (!edpy)
+ errx(1, "Couldn't get EGL display for X11 Display.\n");
+
+ bool ok = eglInitialize(edpy, &major, &minor);
+ if (!ok)
+ errx(1, "eglInitialize() failed\n");
+
+ return edpy;
+}
diff --git a/test/egl_common.h b/test/egl_common.h
new file mode 100644
index 0000000..1c5963b
--- /dev/null
+++ b/test/egl_common.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright © 2013 Intel Corporation
+ *
+ * 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 (including the next
+ * paragraph) 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.
+ */
+
+EGLDisplay *
+get_egl_display_or_skip(void);
diff --git a/test/egl_has_extension_nocontext.c b/test/egl_has_extension_nocontext.c
new file mode 100644
index 0000000..7f658af
--- /dev/null
+++ b/test/egl_has_extension_nocontext.c
@@ -0,0 +1,70 @@
+/*
+ * Copyright © 2013 Intel Corporation
+ *
+ * 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 (including the next
+ * paragraph) 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.
+ */
+
+/**
+ * @file egl_has_extension_nocontext.c
+ *
+ * Catches a bug in early development where eglGetProcAddress() with
+ * no context bound would fail out in dispatch.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <err.h>
+#include "epoxy/gl.h"
+#include "epoxy/egl.h"
+
+#include "egl_common.h"
+
+int
+main(int argc, char **argv)
+{
+ bool pass = true;
+
+ EGLDisplay *dpy = get_egl_display_or_skip();
+ const char *extensions = eglQueryString(dpy, EGL_EXTENSIONS);
+ char *first_space;
+ char *an_extension;
+
+ /* We don't have any extensions guaranteed by the ABI, so for the
+ * touch test we just check if the first one is reported to be there.
+ */
+ first_space = strstr(extensions, " ");
+ if (first_space) {
+ an_extension = strndup(extensions, first_space - extensions);
+ } else {
+ an_extension = strdup(extensions);
+ }
+
+ if (!epoxy_has_egl_extension(dpy, an_extension))
+ errx(1, "Implementation reported absence of GLX_ARB_get_proc_address");
+
+ free(an_extension);
+
+ if (epoxy_has_egl_extension(dpy, "GLX_ARB_ham_sandwich"))
+ errx(1, "Implementation reported presence of GLX_ARB_ham_sandwich");
+
+ return pass != true;
+}
diff --git a/test/headerguards.c b/test/headerguards.c
index 17e6aef..a270b53 100644
--- a/test/headerguards.c
+++ b/test/headerguards.c
@@ -22,8 +22,11 @@
*/
#include <epoxy/gl.h>
+#include <epoxy/egl.h>
#include <epoxy/glx.h>
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
#include <GL/gl.h>
#include <GL/glext.h>
#include <GL/glx.h>