summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEric Anholt <eric@anholt.net>2013-12-10 17:14:46 -0800
committerEric Anholt <eric@anholt.net>2013-12-10 17:19:38 -0800
commitf843d63da272a07db5fd767046acf053651fd8ed (patch)
tree23fd7b090f5d6353fae28fe9a82c2a3160b6301e /src
parentca14052cfe5dea77a09fcda4efeacf9ac83b1348 (diff)
Reduce the overhead of the dispatch table usage.
We now initialize our dispatch table with function pointers that go and do the rewrite, then we never have to check for a NULL table entry again. On my 64-bit build, epoxy_glClear() drops from 83 bytes to 14, while the total library size only goes up by 5%. This also paves the way for fixing our dispatch table management using TLS on windows.
Diffstat (limited to 'src')
-rwxr-xr-xsrc/gen_dispatch.py62
1 files changed, 54 insertions, 8 deletions
diff --git a/src/gen_dispatch.py b/src/gen_dispatch.py
index c7d9473..3b55427 100755
--- a/src/gen_dispatch.py
+++ b/src/gen_dispatch.py
@@ -515,7 +515,9 @@ class Generator(object):
self.outln('}')
self.outln('')
- def write_dispatch_table_stub(self, func):
+ def write_dispatch_table_thunk(self, func):
+ # Writes out the thunk that calls through our dispatch table.
+
# Use the same resolver for all the aliases of a particular
# function.
alias_name = func.name
@@ -531,12 +533,11 @@ class Generator(object):
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,
- alias_name))
+ self.outln(' struct dispatch_table *dispatch_table = get_dispatch_table();')
self.outln('')
if func.ret_type == 'void':
self.outln(' {0}({1});'.format(dispatch_table_entry, func.args_list))
@@ -545,6 +546,28 @@ class Generator(object):
self.outln('}')
self.outln('')
+ def write_dispatch_table_rewrite_stub(self, func):
+ # Writes out the stub entrypoint that resolves, writes the
+ # resolved value into the dispatch table, and calls down to
+ # it.
+
+ dispatch_table_entry = 'dispatch_table->p{0}'.format(func.name)
+
+ self.outln('static {0}'.format(func.ret_type))
+ self.outln('epoxy_{0}_rewrite_stub({1})'.format(func.name, func.args_decl))
+ self.outln('{')
+ self.outln(' struct dispatch_table *dispatch_table = get_dispatch_table();')
+ self.outln('')
+ self.outln(' dispatch_table->p{0} = epoxy_{0}_resolver();'.format(func.name))
+ self.outln('')
+
+ if func.ret_type == 'void':
+ self.outln(' dispatch_table->p{0}({1});'.format(func.name, func.args_list))
+ else:
+ self.outln(' return dispatch_table->p{0}({1});'.format(func.name, func.args_list))
+ self.outln('}')
+ self.outln('')
+
def write_provider_enums(self):
self.outln('enum {0}_provider {{'.format(self.target))
@@ -627,9 +650,12 @@ class Generator(object):
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;')
+ # Early declaration, so we can declare the real thing at the
+ # bottom. (I want the function_ptr_resolver as the first
+ # per-GL-call code, since it's the most interesting to see
+ # when you search for the implementation of a call)
+ self.outln('static inline struct dispatch_table *')
+ self.outln('get_dispatch_table(void);')
self.outln('')
self.write_provider_enums()
@@ -641,7 +667,27 @@ class Generator(object):
self.write_function_ptr_resolver(func)
for func in self.sorted_functions:
- self.write_dispatch_table_stub(func)
+ if not func.alias_func:
+ self.write_dispatch_table_rewrite_stub(func)
+
+ for func in self.sorted_functions:
+ self.write_dispatch_table_thunk(func)
+
+ self.outln('static struct dispatch_table resolver_table = {')
+ for func in self.sorted_functions:
+ # Aliases don't get their own slot, since they use a shared resolver.
+ if not func.alias_name:
+ self.outln(' .p{0} = epoxy_{0}_rewrite_stub,'.format(func.name))
+ self.outln('};')
+ self.outln('')
+
+ self.outln('static inline struct dispatch_table *')
+ self.outln('get_dispatch_table(void)')
+ self.outln('{')
+ self.outln(' /* XXX: Make this thread-local and swapped on makecurrent on win32. */')
+ self.outln(' return &resolver_table;')
+ self.outln('}')
+ self.outln('')
argparser = argparse.ArgumentParser(description='Generate GL dispatch wrappers.')
argparser.add_argument('files', metavar='file.xml', nargs='+', help='GL API XML files to be parsed')