summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEric Anholt <eric@anholt.net>2013-12-05 13:59:34 -0800
committerEric Anholt <eric@anholt.net>2013-12-05 15:07:08 -0800
commit0983996e49042264f35e47a9161572b30c13a5f2 (patch)
treeab3189099d237f1a8fbcbce2fc6ea811776b44d3 /src
parent9ffa5d25c4e59acf4808d2f87c1980daa8e7d3cb (diff)
Fix calling new entrypoints from within glBegin()/glEnd().
Diffstat (limited to 'src')
-rw-r--r--src/dispatch_common.c107
-rw-r--r--src/dispatch_common.h5
-rwxr-xr-xsrc/gen_dispatch.py23
3 files changed, 124 insertions, 11 deletions
diff --git a/src/dispatch_common.c b/src/dispatch_common.c
index 6d27cb1..7b976a5 100644
--- a/src/dispatch_common.c
+++ b/src/dispatch_common.c
@@ -117,6 +117,20 @@ struct api {
/** dlopen() return value for libGLESv2.so.2 */
void *gles2_handle;
+
+ /**
+ * This value gets incremented when any thread is in
+ * glBegin()/glEnd() called through epoxy.
+ *
+ * We're not guaranteed to be called through our wrapper, so the
+ * conservative paths also try to handle the failure cases they'll
+ * see if begin_count didn't reflect reality. It's also a bit of
+ * a bug that the conservative paths might return success because
+ * some other thread was in epoxy glBegin/glEnd while our thread
+ * is trying to resolve, but given that it's basically just for
+ * informative error messages, we shouldn't need to care.
+ */
+ int begin_count;
};
static struct api api = {
@@ -159,18 +173,34 @@ PUBLIC bool
epoxy_is_desktop_gl(void)
{
const char *es_prefix = "OpenGL ES ";
- const char *version = (const char *)glGetString(GL_VERSION);
+ const char *version;
+
+ if (api.begin_count)
+ return true;
+
+ version = (const char *)glGetString(GL_VERSION);
+
+ /* If we didn't get a version back, there are only two things that
+ * could have happened: either malloc failure (which basically
+ * doesn't exist), or we were called within a glBegin()/glEnd().
+ * Assume the second, which only exists for desktop GL.
+ */
+ if (!version)
+ return true;
return strncmp(es_prefix, version, strlen(es_prefix));
}
-PUBLIC int
-epoxy_gl_version(void)
+static int
+epoxy_internal_gl_version(int error_version)
{
const char *version = (const char *)glGetString(GL_VERSION);
GLint major, minor;
int scanf_count;
+ if (!version)
+ return error_version;
+
/* skip to version number */
while (!isdigit(*version) && *version != '\0')
version++;
@@ -185,6 +215,21 @@ epoxy_gl_version(void)
return 10 * major + minor;
}
+PUBLIC int
+epoxy_gl_version(void)
+{
+ return epoxy_internal_gl_version(0);
+}
+
+PUBLIC int
+epoxy_conservative_gl_version(void)
+{
+ if (api.begin_count)
+ return 100;
+
+ return epoxy_internal_gl_version(100);
+}
+
/**
* If we can determine the GLX version from the current context, then
* return that, otherwise return a version that will just send us on
@@ -268,16 +313,21 @@ epoxy_extension_in_string(const char *extension_list, const char *ext)
return ptr != NULL;
}
-PUBLIC bool
-epoxy_has_gl_extension(const char *ext)
+static bool
+epoxy_internal_has_gl_extension(const char *ext, bool invalid_op_mode)
{
if (epoxy_gl_version() < 30) {
- return epoxy_extension_in_string((const char *)glGetString(GL_EXTENSIONS),
- ext);
+ const char *exts = (const char *)glGetString(GL_EXTENSIONS);
+ if (!exts)
+ return invalid_op_mode;
+ return epoxy_extension_in_string(exts, ext);
} else {
int num_extensions;
glGetIntegerv(GL_NUM_EXTENSIONS, &num_extensions);
+ if (num_extensions == 0)
+ return invalid_op_mode;
+
for (int i = 0; i < num_extensions; i++) {
const char *gl_ext = (const char *)glGetStringi(GL_EXTENSIONS, i);
if (strcmp(ext, gl_ext) == 0)
@@ -288,6 +338,29 @@ epoxy_has_gl_extension(const char *ext)
}
}
+/**
+ * Returns true if the given GL extension is supported in the current context.
+ *
+ * Note that this function can't be called from within glBegin()/glEnd().
+ *
+ * \sa epoxy_has_egl_extension()
+ * \sa epoxy_has_glx_extension()
+ */
+PUBLIC bool
+epoxy_has_gl_extension(const char *ext)
+{
+ return epoxy_internal_has_gl_extension(ext, false);
+}
+
+bool
+epoxy_conservative_has_gl_extension(const char *ext)
+{
+ if (api.begin_count)
+ return true;
+
+ return epoxy_internal_has_gl_extension(ext, true);
+}
+
bool
epoxy_conservative_has_egl_extension(const char *ext)
{
@@ -424,3 +497,23 @@ epoxy_print_failure_reasons(const char *name,
for (i = 0; providers[i] != 0; i++)
puts(provider_names[providers[i]]);
}
+
+PUBLIC void
+epoxy_glBegin(GLenum primtype)
+{
+ pthread_mutex_lock(&api.mutex);
+ api.begin_count++;
+ pthread_mutex_unlock(&api.mutex);
+
+ epoxy_glBegin_unwrapped(primtype);
+}
+
+PUBLIC void
+epoxy_glEnd(void)
+{
+ epoxy_glEnd_unwrapped();
+
+ pthread_mutex_lock(&api.mutex);
+ api.begin_count--;
+ pthread_mutex_unlock(&api.mutex);
+}
diff --git a/src/dispatch_common.h b/src/dispatch_common.h
index 34163ec..f66f165 100644
--- a/src/dispatch_common.h
+++ b/src/dispatch_common.h
@@ -41,6 +41,8 @@ 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_gl_version(void);
+bool epoxy_conservative_has_gl_extension(const char *name);
int epoxy_conservative_glx_version(void);
bool epoxy_conservative_has_glx_extension(const char *name);
int epoxy_conservative_egl_version(void);
@@ -48,3 +50,6 @@ bool epoxy_conservative_has_egl_extension(const char *name);
void epoxy_print_failure_reasons(const char *name,
const char **provider_names,
const int *providers);
+
+void epoxy_glBegin_unwrapped(GLenum primtype);
+void epoxy_glEnd_unwrapped(void);
diff --git a/src/gen_dispatch.py b/src/gen_dispatch.py
index e2c5308..048785f 100755
--- a/src/gen_dispatch.py
+++ b/src/gen_dispatch.py
@@ -130,6 +130,14 @@ class Generator(object):
# provided the name of the symbol to be requested.
self.provider_loader = {}
+ # These are functions with hand-written wrapper code in
+ # dispatch_common.c. Their dispatch stubs will be replaced
+ # with non-public symbols with a "_unwrapped" suffix.
+ self.wrapped_functions = {
+ 'glBegin',
+ 'glEnd'
+ }
+
def all_text_until_element_name(self, element, element_name):
text = ''
@@ -265,7 +273,7 @@ class Generator(object):
loader = 'epoxy_gl_dlsym({0})'
else:
loader = 'epoxy_get_proc_address({0})'
- condition += ' && epoxy_gl_version() >= {0}'.format(version)
+ condition += ' && epoxy_conservative_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)
@@ -319,7 +327,7 @@ class Generator(object):
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)
+ condition = 'epoxy_conservative_has_gl_extension("{0}")'.format(extname)
loader = 'epoxy_get_proc_address({0})'
self.process_require_statements(extension, condition, loader, human_name)
@@ -460,8 +468,15 @@ class Generator(object):
dispatch_table_entry = 'dispatch_table->p{0}'.format(alias_name)
- self.outln('PUBLIC {0}'.format(func.ret_type))
- self.outln('epoxy_{0}({1})'.format(func.name, func.args_decl))
+ if func.name in self.wrapped_functions:
+ function_name = func.name + '_unwrapped'
+ public = ''
+ else:
+ function_name = func.name
+ public = 'PUBLIC '
+
+ self.outln('{0}{1}'.format(public, func.ret_type))
+ self.outln('epoxy_{0}({1})'.format(function_name, func.args_decl))
self.outln('{')
self.outln(' if (!{0})'.format(dispatch_table_entry))
self.outln(' {0} = epoxy_{1}_resolver();'.format(dispatch_table_entry,