summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore4
-rw-r--r--CMakeLists.txt17
-rw-r--r--src/waffle/CMakeLists.txt47
-rw-r--r--src/waffle/dispatch/dispatch_common.c179
-rw-r--r--src/waffle/dispatch/dispatch_common.h31
-rwxr-xr-xsrc/waffle/dispatch/gen_dispatch.py357
6 files changed, 635 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
index 9a6d58e..76c95f9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -51,6 +51,10 @@ Makefile
/examples/simple-x11-egl
/lib/
/src/waffle/libwaffle_static.a
+/src/waffle/dispatch/gl_dispatch.c
+/src/waffle/dispatch/gl_dispatch.h
+/src/waffle/dispatch/glx_dispatch.c
+/src/waffle/dispatch/glx_dispatch.h
/tests/functional/gl_basic_test
/tests/waffle_test/libwaffle_test.dylib
/tests/unittests/waffle-unittest
diff --git a/CMakeLists.txt b/CMakeLists.txt
index a6695fe..48ff5ff 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -40,6 +40,23 @@ include(GNUInstallDirs)
find_package(PkgConfig)
+# Check for presence of Python 2.6 or greater.
+foreach(python_cmd python2 python)
+ execute_process(
+ COMMAND ${python_cmd} -c "import sys; assert '2.6' <= sys.version < '3'"
+ OUTPUT_QUIET
+ ERROR_QUIET
+ RESULT_VARIABLE python_version_check_error_code)
+ if(python_version_check_error_code EQUAL 0)
+ set(python ${python_cmd})
+ break()
+ endif(python_version_check_error_code EQUAL 0)
+endforeach(python_cmd)
+
+if(NOT DEFINED python)
+ message(FATAL_ERROR "python version 2.x (where x >= 6) required")
+endif(NOT DEFINED python)
+
# ------------------------------------------------------------------------------
# Add subdirectories
# ------------------------------------------------------------------------------
diff --git a/src/waffle/CMakeLists.txt b/src/waffle/CMakeLists.txt
index a743096..986884d 100644
--- a/src/waffle/CMakeLists.txt
+++ b/src/waffle/CMakeLists.txt
@@ -39,6 +39,15 @@ set(waffle_libdeps
${xcb_LDFLAGS}
)
+
+set(gl_generated_dispatch_c
+ ${CMAKE_CURRENT_BINARY_DIR}/dispatch/gl_dispatch.c
+ )
+
+set(glx_generated_dispatch_c
+ ${CMAKE_CURRENT_BINARY_DIR}/dispatch/glx_dispatch.c
+ )
+
set(waffle_sources
api/api_priv.c
api/waffle_attrib_list.c
@@ -57,6 +66,9 @@ set(waffle_sources
core/wcore_error.c
core/wcore_tinfo.c
core/wcore_util.c
+ dispatch/dispatch_common.c
+ ${gl_generated_dispatch_c}
+ ${glx_generated_dispatch_c}
)
if(waffle_on_mac)
@@ -193,3 +205,38 @@ set_target_properties(waffle_static
PROPERTIES
LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib
)
+
+set(gl_generated_dispatch_h ${CMAKE_CURRENT_BINARY_DIR}/dispatch/gl_dispatch.h)
+set(glx_generated_dispatch_h ${CMAKE_CURRENT_BINARY_DIR}/dispatch/glx_dispatch.h)
+
+add_custom_command(
+ OUTPUT ${gl_generated_dispatch_c}
+ ${gl_generated_dispatch_h}
+ COMMAND ${python}
+ dispatch/gen_dispatch.py
+ --output-c ${gl_generated_dispatch_c}
+ --output-h ${gl_generated_dispatch_h}
+ dispatch/gl.xml
+ DEPENDS dispatch/gen_dispatch.py dispatch/gl.xml
+ )
+
+add_custom_command(
+ OUTPUT ${glx_generated_dispatch_c}
+ ${glx_generated_dispatch_h}
+ COMMAND ${python}
+ dispatch/gen_dispatch.py
+ --output-c ${glx_generated_dispatch_c}
+ --output-h ${glx_generated_dispatch_h}
+ dispatch/glx.xml
+ DEPENDS dispatch/gen_dispatch.py dispatch/glx.xml
+ )
+
+add_custom_target(gen_dispatch
+ DEPENDS ${dispatch_gl_outputs}
+ )
+
+install(
+ FILES ${gl_generated_dispatch_h}
+ ${glx_generated_dispatch_h}
+ DESTINATION ${CMAKE_INSTALL_FULL_INCLUDEDIR}/${waffle_libname}
+ )
diff --git a/src/waffle/dispatch/dispatch_common.c b/src/waffle/dispatch/dispatch_common.c
new file mode 100644
index 0000000..1af1a44
--- /dev/null
+++ b/src/waffle/dispatch/dispatch_common.c
@@ -0,0 +1,179 @@
+/*
+ * 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 dispatch_common.c
+ *
+ * Implements common code shared by the generated GL/EGL/GLX dispatch code.
+ *
+ * A collection of some important specs on getting GL function pointers.
+ *
+ * From the linux GL ABI (http://www.opengl.org/registry/ABI/):
+ *
+ * "3.4. The libraries must export all OpenGL 1.2, GLU 1.3, GLX 1.3, and
+ * ARB_multitexture entry points statically.
+ *
+ * 3.5. Because non-ARB extensions vary so widely and are constantly
+ * increasing in number, it's infeasible to require that they all be
+ * supported, and extensions can always be added to hardware drivers
+ * after the base link libraries are released. These drivers are
+ * dynamically loaded by libGL, so extensions not in the base
+ * library must also be obtained dynamically.
+ *
+ * 3.6. To perform the dynamic query, libGL also must export an entry
+ * point called
+ *
+ * void (*glXGetProcAddressARB(const GLubyte *))();
+ *
+ * The full specification of this function is available separately. It
+ * takes the string name of a GL or GLX entry point and returns a pointer
+ * to a function implementing that entry point. It is functionally
+ * identical to the wglGetProcAddress query defined by the Windows OpenGL
+ * library, except that the function pointers returned are context
+ * independent, unlike the WGL query."
+ *
+ * From the EGL 1.4 spec:
+ *
+ * "Client API function pointers returned by eglGetProcAddress are
+ * independent of the display and the currently bound client API context,
+ * and may be used by any client API context which supports the extension.
+ *
+ * eglGetProcAddress may be queried for all of the following functions:
+ *
+ * • All EGL and client API extension functions supported by the
+ * implementation (whether those extensions are supported by the current
+ * client API context or not). This includes any mandatory OpenGL ES
+ * extensions.
+ *
+ * eglGetProcAddress may not be queried for core (non-extension) functions
+ * in EGL or client APIs 20 .
+ *
+ * For functions that are queryable with eglGetProcAddress,
+ * implementations may choose to also export those functions statically
+ * from the object libraries im- plementing those functions. However,
+ * portable clients cannot rely on this behavior.
+ *
+ * From the GLX 1.4 spec:
+ *
+ * "glXGetProcAddress may be queried for all of the following functions:
+ *
+ * • All GL and GLX extension functions supported by the implementation
+ * (whether those extensions are supported by the current context or
+ * not).
+ *
+ * • All core (non-extension) functions in GL and GLX from version 1.0 up
+ * to and including the versions of those specifications supported by
+ * the implementation, as determined by glGetString(GL VERSION) and
+ * glXQueryVersion queries."
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include "dispatch_common.h"
+#include "api_priv.h"
+#include "gl_dispatch.h"
+#include "glx_dispatch.h"
+
+bool
+is_desktop_gl(void)
+{
+ return true; /* XXX */
+}
+
+bool
+has_gl_version(int ver)
+{
+ GLint major, minor;
+
+ glGetIntegerv(GL_MAJOR_VERSION, &major);
+ glGetIntegerv(GL_MAJOR_VERSION, &minor);
+
+ return major * 10 + minor >= ver;
+}
+
+static bool
+extension_in_string(const char *extension_list, const char *ext)
+{
+ const char *ptr = extension_list;
+ int len = strlen(ext);
+
+ /* Make sure that don't just find an extension with our name as a prefix. */
+ do {
+ ptr = strstr(ptr, ext);
+ } while (ptr && (ptr[len] != ' ' && ptr[len] != 0));
+
+ return ptr != NULL;
+}
+
+bool
+has_gl_extension(const char *ext)
+{
+ return extension_in_string((const char *)glGetString(GL_EXTENSIONS), ext);
+}
+
+bool
+has_egl_extension(const char *ext)
+{
+/*
+ return extension_in_string(eglQueryString(EGL_EXTENSIONS), ext);
+*/
+ return true; /* XXX */
+}
+
+bool
+has_glx_extension(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 glXQueryExtensionsString().
+ */
+ Display *dpy = glXGetCurrentDisplay();
+ int screen = 0;
+
+ if (!dpy) {
+ fprintf(stderr, "waffle needs a display!"); /* XXX */
+ return false;
+ }
+
+ return extension_in_string(glXQueryExtensionsString(dpy, screen), ext);
+}
+
+void
+waffle_dispatch_platform_autoinit(void)
+{
+ static const int32_t attribs[] = {WAFFLE_PLATFORM, WAFFLE_PLATFORM_GLX, 0};
+
+ if (api_platform)
+ return;
+
+ waffle_init(attribs);
+
+#if 0
+ static struct wcore_platform *glx_plat = NULL;
+
+
+ if (!glx_plat)
+ glx_plat = glx_platform_create();
+#endif
+}
+
diff --git a/src/waffle/dispatch/dispatch_common.h b/src/waffle/dispatch/dispatch_common.h
new file mode 100644
index 0000000..736325c
--- /dev/null
+++ b/src/waffle/dispatch/dispatch_common.h
@@ -0,0 +1,31 @@
+/*
+ * 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 <stdbool.h>
+
+bool is_desktop_gl(void);
+bool has_gl_version(int ver);
+bool has_gl_extension(const char *ext);
+bool has_glx_extension(const char *ext);
+bool has_egl_extension(const char *ext);
+void waffle_dispatch_platform_autoinit(void);
diff --git a/src/waffle/dispatch/gen_dispatch.py b/src/waffle/dispatch/gen_dispatch.py
new file mode 100755
index 0000000..5b4336c
--- /dev/null
+++ b/src/waffle/dispatch/gen_dispatch.py
@@ -0,0 +1,357 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# 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.
+
+import sys
+import argparse
+import xml.etree.ElementTree as ET
+import re
+
+class GLFunction(object):
+ def __init__(self, ret_type, name):
+ self.name = name
+ self.ptr_type = 'PFN' + name.upper()
+ self.ret_type = ret_type
+ self.providers = []
+ self.args = []
+ self.args_list = ''
+ self.args_decl = 'void'
+
+ def add_arg(self, type, name):
+ self.args.append((type, name))
+ if self.args_decl == 'void':
+ self.args_list = name
+ self.args_decl = type + ' ' + name
+ else:
+ self.args_list += ', ' + name
+ self.args_decl += ', ' + type + ' ' + name
+
+ def add_provider(self, condition, loader, human_name):
+ self.providers.append((condition, loader, human_name))
+
+class Generator(object):
+ def __init__(self):
+ self.enums = {}
+ self.functions = {}
+ self.max_enum_name_len = 1
+ self.copyright_comment = None
+ self.typedefs = ''
+ self.out_file = None
+
+ def all_text_until_element_name(self, element, element_name):
+ text = ''
+
+ if element.text is not None:
+ text += element.text
+
+ for child in element:
+ if child.tag == element_name:
+ break
+ if child.text:
+ text += child.text
+ if child.tail:
+ text += child.tail
+ return text
+
+ def out(self, text):
+ self.out_file.write(text)
+
+ def outln(self, text):
+ self.out_file.write(text + '\n')
+
+ def parse_typedefs(self, reg):
+ for t in reg.findall('types/type'):
+ if 'name' in t.attrib and t.attrib['name'] not in {'GLhandleARB'}:
+ continue
+
+ if t.text is not None:
+ self.typedefs += t.text
+
+ for child in t:
+ if child.text:
+ self.typedefs += child.text
+ if child.tail:
+ self.typedefs += child.tail
+ self.typedefs += '\n'
+
+ def parse_enums(self, reg):
+ for enum in reg.findall('enums/enum'):
+ name = enum.get('name')
+ self.max_enum_name_len = max(self.max_enum_name_len, len(name))
+ self.enums[name] = enum.get('value')
+
+ def get_function_return_type(self, proto):
+ # Everything up to the start of the name element is the return type.
+ return self.all_text_until_element_name(proto, 'name').strip()
+
+ def parse_function_definitions(self, reg):
+ for command in reg.findall('commands/command'):
+ proto = command.find('proto')
+ name = proto.find('name').text
+ ret_type = self.get_function_return_type(proto)
+
+ func = GLFunction(ret_type, name)
+
+ for arg in command.findall('param'):
+ func.add_arg(self.all_text_until_element_name(arg, 'name').strip(),
+ arg.find('name').text)
+
+ self.functions[name] = func
+
+ def drop_weird_glx_functions(self):
+ # Drop a few ancient SGIX GLX extensions that use types not defined
+ # anywhere in Xlib. In glxext.h, they're protected by #ifdefs for the
+ # headers that defined them.
+ weird_functions = [name for name, func in self.functions.iteritems()
+ if 'VLServer' in func.args_decl
+ or 'DMparams' in func.args_decl]
+
+ for name in weird_functions:
+ del self.functions[name]
+
+ def process_require_statements(self, feature, condition, loader, human_name):
+ for command in feature.findall('require/command'):
+ name = command.get('name')
+ func = self.functions[name]
+ func.add_provider(condition, loader.format(name), human_name)
+
+ def parse_function_providers(self, reg):
+ for feature in reg.findall('feature'):
+ api = feature.get('api') # string gl, gles1, gles2, glx
+ if api == 'gl':
+ m = re.match('GL_VERSION_([0-9])_([0-9])', feature.get('name'))
+ human_name = 'Desktop OpenGL {0}.{1}'.format(m.group(1), m.group(2))
+ gl_ver = int(m.group(1)) * 10 + int(m.group(2))
+ condition = 'is_desktop_gl()'
+
+ # Everything in GL 1.2 is guaranteed to be present as
+ # public symbols in the Linux libGL ABI. Everything
+ # else is supposed to not be present, so you have to
+ # glXGetProcAddress() it.
+ if gl_ver <= 12:
+ loader = 'waffle_dl_sym(WAFFLE_DL_OPENGL, "{0}")'
+ else:
+ loader = 'waffle_get_proc_address("{0}")'
+ condition += ' && has_gl_version({0})'.format(gl_ver)
+ else:
+ human_name = ''
+ condition = 'true'
+ loader = 'waffle_dl_sym(WAFFLE_DL_OPENGL, "{0}")'
+
+ self.process_require_statements(feature, condition, loader, human_name)
+
+ for extension in reg.findall('extensions/extension'):
+ extname = extension.get('name')
+ # 'supported' is a set of strings like gl, gles1, gles2, or glx, which are
+ # separated by '|'
+ apis = extension.get('supported').split('|')
+ if 'glx' in apis:
+ human_name = 'GLX extension \\"{0}\\"'.format(extname)
+ condition = 'has_glx_extension("{0}")'.format(extname)
+ loader = 'waffle_get_proc_address("{0}")'
+ self.process_require_statements(extension, condition, loader, human_name)
+ if 'gl' in apis:
+ human_name = 'GL extension \\"{0}\\"'.format(extname)
+ condition = 'has_gl_extension("{0}")'.format(extname)
+ loader = 'waffle_get_proc_address("{0}")'
+ self.process_require_statements(extension, condition, loader, human_name)
+
+ def parse(self, file):
+ reg = ET.parse(file)
+ if reg.find('comment') != None:
+ self.copyright_comment = reg.find('comment').text
+ else:
+ self.copyright_comment = ''
+ self.parse_typedefs(reg)
+ self.parse_enums(reg)
+ self.parse_function_definitions(reg)
+ self.parse_function_providers(reg)
+
+ def write_copyright_comment_body(self):
+ for line in self.copyright_comment.splitlines():
+ if '-----' in line:
+ break
+ self.outln(' * ' + line)
+
+ def write_enums(self):
+ for name, value in self.enums.iteritems():
+ self.outln('#define ' + name.ljust(self.max_enum_name_len + 3) + value + '')
+
+ def write_function_ptr_typedefs(self):
+ for func in self.functions.values():
+ self.outln('typedef {0} (*{1})({2});'.format(func.ret_type, func.ptr_type,
+ func.args_decl))
+
+ def write_dispatch_defines(self):
+ for func in self.functions.values():
+ self.outln('#define {0} waffle_dispatch_{0}'.format(func.name))
+
+ def write_header(self, file):
+ self.out_file = open(file, 'w')
+
+ self.outln('/* GL dispatch header for waffle users.')
+ self.outln(' * This is code-generated from the GL API XML files from Khronos.')
+ self.write_copyright_comment_body()
+ self.outln(' */')
+ self.outln('')
+
+ self.outln('#pragma once')
+
+ self.outln('#include <inttypes.h>')
+ self.outln('#include <stddef.h>')
+ self.outln('')
+
+ if 'gl_dispatch.h' not in file:
+ self.outln('#include "gl_dispatch.h"')
+ else:
+ # Add some ridiculous inttypes.h redefinitions that are from
+ # khrplatform.h and not included in the XML.
+ self.outln('typedef int8_t khronos_int8_t;')
+ self.outln('typedef int16_t khronos_int16_t;')
+ self.outln('typedef int32_t khronos_int32_t;')
+ self.outln('typedef int64_t khronos_int64_t;')
+ self.outln('typedef uint8_t khronos_uint8_t;')
+ self.outln('typedef uint16_t khronos_uint16_t;')
+ self.outln('typedef uint32_t khronos_uint32_t;')
+ self.outln('typedef uint64_t khronos_uint64_t;')
+ self.outln('typedef float khronos_float_t;')
+ self.outln('typedef intptr_t khronos_intptr_t;')
+ self.outln('typedef ptrdiff_t khronos_ssize_t;')
+
+ if 'glx_dispatch.h' in file:
+ self.outln('#include <X11/Xlib.h>')
+ self.outln('#include <X11/Xutil.h>')
+
+ self.out(self.typedefs)
+ self.outln('')
+ self.write_enums()
+ self.outln('')
+ self.write_dispatch_defines()
+ self.outln('')
+ self.write_function_ptr_typedefs()
+
+ for func in self.functions.values():
+ self.outln('{0} waffle_dispatch_{1}({2});'.format(func.ret_type, func.name,
+ func.args_decl))
+
+ def write_function_ptr_resolver(self, func):
+ self.outln('static {0}'.format(func.ptr_type))
+ self.outln('waffle_dispatch_{0}_resolver(void)'.format(func.name))
+ self.outln('{')
+
+ self.outln(' waffle_dispatch_platform_autoinit();')
+ self.outln('')
+ # Walk the sources of aliases of this function and see if we
+ # have any. If so, get the function pointer and return.
+ for provider in func.providers:
+ condition = provider[0]
+ loader = provider[1]
+ self.outln(' if ({0})'.format(condition))
+ self.outln(' return {0};'.format(loader))
+ self.outln('')
+
+ # If the function isn't provided by any known extension, print
+ # something useful for the poor application developer before
+ # aborting. (In non-waffle-dispatch GL usage, the app
+ # developer would call into some blank stub function and
+ # segfault).
+ self.outln(' printf("No provider of \\"{0}\\" found. Requires one of:\\n");'.format(func.name))
+ if len(func.providers) == 0:
+ self.outln(' printf(" unknown\\n");')
+ else:
+ for provider in func.providers:
+ self.outln(' printf(" {0}\\n");'.format(provider[2]))
+
+ self.outln(' abort();')
+
+ self.outln('}')
+ self.outln('')
+
+ def write_dispatch_table_stub(self, func):
+ dispatch_table_entry = 'dispatch_table->p{0}'.format(func.name)
+
+ self.outln('WAFFLE_API {0}'.format(func.ret_type))
+ self.outln('waffle_dispatch_{0}({1})'.format(func.name, func.args_decl))
+ self.outln('{')
+ self.outln(' if (!{0})'.format(dispatch_table_entry))
+ self.outln(' {0} = waffle_dispatch_{1}_resolver();'.format(dispatch_table_entry, func.name))
+ self.outln('')
+ if func.ret_type == 'void':
+ self.outln(' {0}({1});'.format(dispatch_table_entry, func.args_list))
+ else:
+ self.outln(' return {0}({1});'.format(dispatch_table_entry, func.args_list))
+ self.outln('}')
+ self.outln('')
+
+ def write_ifunc_stub(self, func):
+ self.outln('WAFFLE_API void *waffle_ifunc_dispatch_{0}() __attribute__((ifunc("waffle_dispatch_{0}_resolver")));'.format(func.name))
+ self.outln('')
+
+
+ def write_source(self, file):
+ self.out_file = open(file, 'w')
+
+ self.outln('/* GL dispatch code for waffle.')
+ self.outln(' * This is code-generated from the GL API XML files from Khronos.')
+ self.write_copyright_comment_body()
+ self.outln(' */')
+ self.outln('')
+ self.outln('#include <stdlib.h>')
+ self.outln('#include <stdio.h>')
+ self.outln('')
+ self.outln('#include "waffle.h"')
+ self.outln('#include "dispatch_common.h"')
+ if 'glx_dispatch.c' in file:
+ self.outln('#include "glx_dispatch.h"')
+ else:
+ self.outln('#include "gl_dispatch.h"')
+ self.outln('')
+
+ self.outln('struct dispatch_table {')
+ for func in self.functions.values():
+ self.outln(' {0} p{1};'.format(func.ptr_type, func.name))
+ self.outln('};')
+ self.outln('')
+
+ self.outln('/* XXX: Make this thread-local and swapped on makecurrent. */')
+ self.outln('static struct dispatch_table local_dispatch_table;')
+ self.outln('static struct dispatch_table *dispatch_table = &local_dispatch_table;')
+ self.outln('')
+
+ for func in self.functions.values():
+ self.write_function_ptr_resolver(func)
+ self.write_dispatch_table_stub(func)
+ self.write_ifunc_stub(func)
+
+argparser = argparse.ArgumentParser(description='Generate GL dispatch wrappers.')
+argparser.add_argument('--output-c', help='private .c file to be built into libwaffle')
+argparser.add_argument('--output-h', help='public .h file to be installed')
+argparser.add_argument('files', metavar='file.xml', nargs='+', help='GL API XML files to be parsed')
+args = argparser.parse_args()
+
+generator = Generator()
+for file in args.files:
+ generator.parse(file)
+generator.drop_weird_glx_functions()
+generator.write_header(args.output_h)
+generator.write_source(args.output_c)