From f843d63da272a07db5fd767046acf053651fd8ed Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Tue, 10 Dec 2013 17:14:46 -0800 Subject: [PATCH] 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. --- src/gen_dispatch.py | 62 +++++++++++++++++++++++++++++++++++++++------ 1 file 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')