1e52adb7bSmrg# -*- coding: utf-8 -*-
2e52adb7bSmrg
3e52adb7bSmrg# Copyright © 2013 Intel Corporation
4e52adb7bSmrg#
5e52adb7bSmrg# Permission is hereby granted, free of charge, to any person obtaining a
6e52adb7bSmrg# copy of this software and associated documentation files (the "Software"),
7e52adb7bSmrg# to deal in the Software without restriction, including without limitation
8e52adb7bSmrg# the rights to use, copy, modify, merge, publish, distribute, sublicense,
9e52adb7bSmrg# and/or sell copies of the Software, and to permit persons to whom the
10e52adb7bSmrg# Software is furnished to do so, subject to the following conditions:
11e52adb7bSmrg#
12e52adb7bSmrg# The above copyright notice and this permission notice (including the next
13e52adb7bSmrg# paragraph) shall be included in all copies or substantial portions of the
14e52adb7bSmrg# Software.
15e52adb7bSmrg#
16e52adb7bSmrg# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17e52adb7bSmrg# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18e52adb7bSmrg# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19e52adb7bSmrg# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20e52adb7bSmrg# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21e52adb7bSmrg# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22e52adb7bSmrg# IN THE SOFTWARE.
23e52adb7bSmrg
24e52adb7bSmrgimport sys
25e52adb7bSmrgimport argparse
26e52adb7bSmrgimport xml.etree.ElementTree as ET
27e52adb7bSmrgimport re
28e52adb7bSmrgimport os
29e52adb7bSmrg
30e52adb7bSmrgclass GLProvider(object):
31e52adb7bSmrg    def __init__(self, condition, condition_name, loader, name):
32e52adb7bSmrg        # C code for determining if this function is available.
33e52adb7bSmrg        # (e.g. epoxy_is_desktop_gl() && epoxy_gl_version() >= 20
34e52adb7bSmrg        self.condition = condition
35e52adb7bSmrg
36e52adb7bSmrg        # A string (possibly with spaces) describing the condition.
37e52adb7bSmrg        self.condition_name = condition_name
38e52adb7bSmrg
39e52adb7bSmrg        # The loader for getting the symbol -- either dlsym or
40e52adb7bSmrg        # getprocaddress.  This is a python format string to generate
41e52adb7bSmrg        # C code, given self.name.
42e52adb7bSmrg        self.loader = loader
43e52adb7bSmrg
44e52adb7bSmrg        # The name of the function to be loaded (possibly an
45e52adb7bSmrg        # ARB/EXT/whatever-decorated variant).
46e52adb7bSmrg        self.name = name
47e52adb7bSmrg
48e52adb7bSmrg        # This is the C enum name we'll use for referring to this provider.
49e52adb7bSmrg        self.enum = condition_name
50e52adb7bSmrg        self.enum = self.enum.replace(' ', '_')
51e52adb7bSmrg        self.enum = self.enum.replace('\\"', '')
52e52adb7bSmrg        self.enum = self.enum.replace('.', '_')
53ca86eba8Smrg        self.enum = "PROVIDER_" + self.enum
54e52adb7bSmrg
55e52adb7bSmrgclass GLFunction(object):
56e52adb7bSmrg    def __init__(self, ret_type, name):
57e52adb7bSmrg        self.name = name
58e52adb7bSmrg        self.ptr_type = 'PFN' + name.upper() + 'PROC'
59e52adb7bSmrg        self.ret_type = ret_type
60e52adb7bSmrg        self.providers = {}
61e52adb7bSmrg        self.args = []
62e52adb7bSmrg
63e52adb7bSmrg        # These are functions with hand-written wrapper code in
64e52adb7bSmrg        # dispatch_common.c.  Their dispatch entries are replaced with
65e52adb7bSmrg        # non-public symbols with a "_unwrapped" suffix.
66e52adb7bSmrg        wrapped_functions = {
67e52adb7bSmrg            'glBegin',
68e52adb7bSmrg            'glEnd',
69e52adb7bSmrg            'wglMakeCurrent',
70e52adb7bSmrg            'wglMakeContextCurrentEXT',
71e52adb7bSmrg            'wglMakeContextCurrentARB',
72e52adb7bSmrg            'wglMakeAssociatedContextCurrentAMD',
73e52adb7bSmrg        }
74e52adb7bSmrg
75e52adb7bSmrg        if name in wrapped_functions:
76e52adb7bSmrg            self.wrapped_name = name + '_unwrapped'
77e52adb7bSmrg            self.public = ''
78e52adb7bSmrg        else:
79e52adb7bSmrg            self.wrapped_name = name
80f71742dfSmrg            self.public = 'EPOXY_PUBLIC '
81e52adb7bSmrg
82e52adb7bSmrg        # This is the string of C code for passing through the
83e52adb7bSmrg        # arguments to the function.
84e52adb7bSmrg        self.args_list = ''
85e52adb7bSmrg
86e52adb7bSmrg        # This is the string of C code for declaring the arguments
87e52adb7bSmrg        # list.
88e52adb7bSmrg        self.args_decl = 'void'
89e52adb7bSmrg
90e52adb7bSmrg        # This is the string name of the function that this is an
91e52adb7bSmrg        # alias of, or self.name.  This initially comes from the
92e52adb7bSmrg        # registry, and may get updated if it turns out our alias is
93e52adb7bSmrg        # itself an alias (for example glFramebufferTextureEXT ->
94e52adb7bSmrg        # glFramebufferTextureARB -> glFramebufferTexture)
95e52adb7bSmrg        self.alias_name = name
96e52adb7bSmrg
97e52adb7bSmrg        # After alias resolution, this is the function that this is an
98e52adb7bSmrg        # alias of.
99e52adb7bSmrg        self.alias_func = None
100e52adb7bSmrg
101e52adb7bSmrg        # For the root of an alias tree, this lists the functions that
102e52adb7bSmrg        # are marked as aliases of it, so that it can write a resolver
103e52adb7bSmrg        # for all of them.
104e52adb7bSmrg        self.alias_exts = []
105e52adb7bSmrg
106f71742dfSmrg    def add_arg(self, arg_type, arg_name):
107e52adb7bSmrg        # Reword glDepthRange() arguments to avoid clashing with the
108e52adb7bSmrg        # "near" and "far" keywords on win32.
109f71742dfSmrg        if arg_name == "near":
110f71742dfSmrg            arg_name = "hither"
111f71742dfSmrg        elif arg_name == "far":
112f71742dfSmrg            arg_name = "yon"
113e52adb7bSmrg
114e52adb7bSmrg        # Mac screwed up GLhandleARB and made it a void * instead of
115e52adb7bSmrg        # uint32_t, despite it being specced as only necessarily 32
116e52adb7bSmrg        # bits wide, causing portability problems all over.  There are
117e52adb7bSmrg        # prototype conflicts between things like
118e52adb7bSmrg        # glAttachShader(GLuint program, GLuint shader) and
119e52adb7bSmrg        # glAttachObjectARB(GLhandleARB container, GLhandleARB obj),
120e52adb7bSmrg        # even though they are marked as aliases in the XML (and being
121e52adb7bSmrg        # aliases in Mesa).
122e52adb7bSmrg        #
123e52adb7bSmrg        # We retain those aliases.  In the x86_64 ABI, the first 6
124e52adb7bSmrg        # args are stored in 64-bit registers, so the calls end up
125e52adb7bSmrg        # being the same despite the different types.  We just need to
126e52adb7bSmrg        # add a cast to uintptr_t to shut up the compiler.
127f71742dfSmrg        if arg_type == 'GLhandleARB':
128f71742dfSmrg            assert len(self.args) < 6
129f71742dfSmrg            arg_list_name = '(uintptr_t)' + arg_name
130e52adb7bSmrg        else:
131f71742dfSmrg            arg_list_name = arg_name
132e52adb7bSmrg
133f71742dfSmrg        self.args.append((arg_type, arg_name))
134e52adb7bSmrg        if self.args_decl == 'void':
135e52adb7bSmrg            self.args_list = arg_list_name
136f71742dfSmrg            self.args_decl = arg_type + ' ' + arg_name
137e52adb7bSmrg        else:
138e52adb7bSmrg            self.args_list += ', ' + arg_list_name
139f71742dfSmrg            self.args_decl += ', ' + arg_type + ' ' + arg_name
140e52adb7bSmrg
141e52adb7bSmrg    def add_provider(self, condition, loader, condition_name):
142e52adb7bSmrg        self.providers[condition_name] = GLProvider(condition, condition_name,
143e52adb7bSmrg                                                    loader, self.name)
144e52adb7bSmrg
145e52adb7bSmrg    def add_alias(self, ext):
146e52adb7bSmrg        assert self.alias_func is None
147e52adb7bSmrg
148e52adb7bSmrg        self.alias_exts.append(ext)
149e52adb7bSmrg        ext.alias_func = self
150e52adb7bSmrg
151e52adb7bSmrgclass Generator(object):
152e52adb7bSmrg    def __init__(self, target):
153e52adb7bSmrg        self.target = target
154e52adb7bSmrg        self.enums = {}
155e52adb7bSmrg        self.functions = {}
156f71742dfSmrg        self.sorted_functions = []
157f71742dfSmrg        self.enum_string_offset = {}
158e52adb7bSmrg        self.max_enum_name_len = 1
159f71742dfSmrg        self.entrypoint_string_offset = {}
160e52adb7bSmrg        self.copyright_comment = None
161e52adb7bSmrg        self.typedefs = ''
162e52adb7bSmrg        self.out_file = None
163e52adb7bSmrg
164e52adb7bSmrg        # GL versions named in the registry, which we should generate
165e52adb7bSmrg        # #defines for.
166e52adb7bSmrg        self.supported_versions = set()
167e52adb7bSmrg
168e52adb7bSmrg        # Extensions named in the registry, which we should generate
169e52adb7bSmrg        # #defines for.
170e52adb7bSmrg        self.supported_extensions = set()
171e52adb7bSmrg
172e52adb7bSmrg        # Dictionary mapping human-readable names of providers to a C
173e52adb7bSmrg        # enum token that will be used to reference those names, to
174e52adb7bSmrg        # reduce generated binary size.
175e52adb7bSmrg        self.provider_enum = {}
176e52adb7bSmrg
177e52adb7bSmrg        # Dictionary mapping human-readable names of providers to C
178e52adb7bSmrg        # code to detect if it's present.
179e52adb7bSmrg        self.provider_condition = {}
180e52adb7bSmrg
181e52adb7bSmrg        # Dictionary mapping human-readable names of providers to
182e52adb7bSmrg        # format strings for fetching the function pointer when
183e52adb7bSmrg        # provided the name of the symbol to be requested.
184e52adb7bSmrg        self.provider_loader = {}
185e52adb7bSmrg
186e52adb7bSmrg    def all_text_until_element_name(self, element, element_name):
187e52adb7bSmrg        text = ''
188e52adb7bSmrg
189e52adb7bSmrg        if element.text is not None:
190e52adb7bSmrg            text += element.text
191e52adb7bSmrg
192e52adb7bSmrg        for child in element:
193e52adb7bSmrg            if child.tag == element_name:
194e52adb7bSmrg                break
195e52adb7bSmrg            if child.text:
196e52adb7bSmrg                text += child.text
197e52adb7bSmrg            if child.tail:
198e52adb7bSmrg                text += child.tail
199e52adb7bSmrg        return text
200e52adb7bSmrg
201e52adb7bSmrg    def out(self, text):
202e52adb7bSmrg        self.out_file.write(text)
203e52adb7bSmrg
204e52adb7bSmrg    def outln(self, text):
205e52adb7bSmrg        self.out_file.write(text + '\n')
206e52adb7bSmrg
207e52adb7bSmrg    def parse_typedefs(self, reg):
208e52adb7bSmrg        for t in reg.findall('types/type'):
209e52adb7bSmrg            if 'name' in t.attrib and t.attrib['name'] not in {'GLhandleARB'}:
210e52adb7bSmrg                continue
211e52adb7bSmrg
212e52adb7bSmrg            # The gles1/gles2-specific types are redundant
213e52adb7bSmrg            # declarations, and the different types used for them (int
214e52adb7bSmrg            # vs int32_t) caused problems on win32 builds.
215e52adb7bSmrg            api = t.get('api')
216e52adb7bSmrg            if api:
217e52adb7bSmrg                continue
218e52adb7bSmrg
219e52adb7bSmrg            if t.text is not None:
220e52adb7bSmrg                self.typedefs += t.text
221e52adb7bSmrg
222e52adb7bSmrg            for child in t:
223e52adb7bSmrg                if child.tag == 'apientry':
224e52adb7bSmrg                    self.typedefs += 'APIENTRY'
225e52adb7bSmrg                if child.text:
226e52adb7bSmrg                    self.typedefs += child.text
227e52adb7bSmrg                if child.tail:
228e52adb7bSmrg                    self.typedefs += child.tail
229e52adb7bSmrg            self.typedefs += '\n'
230e52adb7bSmrg
231e52adb7bSmrg    def parse_enums(self, reg):
232e52adb7bSmrg        for enum in reg.findall('enums/enum'):
233e52adb7bSmrg            name = enum.get('name')
234e52adb7bSmrg
235e52adb7bSmrg            # wgl.xml's 0xwhatever definitions end up colliding with
236e52adb7bSmrg            # wingdi.h's decimal definitions of these.
237f71742dfSmrg            if name in ['WGL_SWAP_OVERLAY', 'WGL_SWAP_UNDERLAY', 'WGL_SWAP_MAIN_PLANE']:
238e52adb7bSmrg                continue
239e52adb7bSmrg
240e52adb7bSmrg            self.max_enum_name_len = max(self.max_enum_name_len, len(name))
241e52adb7bSmrg            self.enums[name] = enum.get('value')
242e52adb7bSmrg
243e52adb7bSmrg    def get_function_return_type(self, proto):
244e52adb7bSmrg        # Everything up to the start of the name element is the return type.
245e52adb7bSmrg        return self.all_text_until_element_name(proto, 'name').strip()
246e52adb7bSmrg
247e52adb7bSmrg    def parse_function_definitions(self, reg):
248e52adb7bSmrg        for command in reg.findall('commands/command'):
249e52adb7bSmrg            proto = command.find('proto')
250e52adb7bSmrg            name = proto.find('name').text
251e52adb7bSmrg            ret_type = self.get_function_return_type(proto)
252e52adb7bSmrg
253e52adb7bSmrg            func = GLFunction(ret_type, name)
254e52adb7bSmrg
255e52adb7bSmrg            for arg in command.findall('param'):
256e52adb7bSmrg                func.add_arg(self.all_text_until_element_name(arg, 'name').strip(),
257e52adb7bSmrg                             arg.find('name').text)
258e52adb7bSmrg
259e52adb7bSmrg            alias = command.find('alias')
260e52adb7bSmrg            if alias is not None:
261e52adb7bSmrg                # Note that some alias references appear before the
262e52adb7bSmrg                # target command is defined (glAttachObjectARB() ->
263e52adb7bSmrg                # glAttachShader(), for example).
264e52adb7bSmrg                func.alias_name = alias.get('name')
265e52adb7bSmrg
266e52adb7bSmrg            self.functions[name] = func
267e52adb7bSmrg
268e52adb7bSmrg    def drop_weird_glx_functions(self):
269e52adb7bSmrg        # Drop a few ancient SGIX GLX extensions that use types not defined
270e52adb7bSmrg        # anywhere in Xlib.  In glxext.h, they're protected by #ifdefs for the
271e52adb7bSmrg        # headers that defined them.
272e52adb7bSmrg        weird_functions = [name for name, func in self.functions.items()
273e52adb7bSmrg                           if 'VLServer' in func.args_decl
274e52adb7bSmrg                           or 'DMparams' in func.args_decl]
275e52adb7bSmrg
276e52adb7bSmrg        for name in weird_functions:
277e52adb7bSmrg            del self.functions[name]
278e52adb7bSmrg
279e52adb7bSmrg    def resolve_aliases(self):
280e52adb7bSmrg        for func in self.functions.values():
281e52adb7bSmrg            # Find the root of the alias tree, and add ourselves to it.
282e52adb7bSmrg            if func.alias_name != func.name:
283e52adb7bSmrg                alias_func = func
284e52adb7bSmrg                while alias_func.alias_name != alias_func.name:
285e52adb7bSmrg                    alias_func = self.functions[alias_func.alias_name]
286e52adb7bSmrg                func.alias_name = alias_func.name
287e52adb7bSmrg                func.alias_func = alias_func
288e52adb7bSmrg                alias_func.alias_exts.append(func)
289e52adb7bSmrg
290e52adb7bSmrg    def prepare_provider_enum(self):
291e52adb7bSmrg        self.provider_enum = {}
292e52adb7bSmrg
293e52adb7bSmrg        # We assume that for any given provider, all functions using
294e52adb7bSmrg        # it will have the same loader.  This lets us generate a
295e52adb7bSmrg        # general C function for detecting conditions and calling the
296e52adb7bSmrg        # dlsym/getprocaddress, and have our many resolver stubs just
297e52adb7bSmrg        # call it with a table of values.
298e52adb7bSmrg        for func in self.functions.values():
299e52adb7bSmrg            for provider in func.providers.values():
300e52adb7bSmrg                if provider.condition_name in self.provider_enum:
301f71742dfSmrg                    assert self.provider_condition[provider.condition_name] == provider.condition
302f71742dfSmrg                    assert self.provider_loader[provider.condition_name] == provider.loader
303e52adb7bSmrg                    continue
304e52adb7bSmrg
305f71742dfSmrg                self.provider_enum[provider.condition_name] = provider.enum
306f71742dfSmrg                self.provider_condition[provider.condition_name] = provider.condition
307f71742dfSmrg                self.provider_loader[provider.condition_name] = provider.loader
308e52adb7bSmrg
309e52adb7bSmrg    def sort_functions(self):
310f71742dfSmrg        self.sorted_functions = sorted(self.functions.values(), key=lambda func: func.name)
311e52adb7bSmrg
312e52adb7bSmrg    def process_require_statements(self, feature, condition, loader, human_name):
313e52adb7bSmrg        for command in feature.findall('require/command'):
314e52adb7bSmrg            name = command.get('name')
315e52adb7bSmrg
316e52adb7bSmrg            # wgl.xml describes 6 functions in WGL 1.0 that are in
317e52adb7bSmrg            # gdi32.dll instead of opengl32.dll, and we would need to
318e52adb7bSmrg            # change up our symbol loading to support that.  Just
319e52adb7bSmrg            # don't wrap those functions.
320e52adb7bSmrg            if self.target == 'wgl' and 'wgl' not in name:
321e52adb7bSmrg                del self.functions[name]
322f71742dfSmrg                continue
323e52adb7bSmrg
324e52adb7bSmrg            func = self.functions[name]
325e52adb7bSmrg            func.add_provider(condition, loader, human_name)
326e52adb7bSmrg
327e52adb7bSmrg    def parse_function_providers(self, reg):
328e52adb7bSmrg        for feature in reg.findall('feature'):
329e52adb7bSmrg            api = feature.get('api') # string gl, gles1, gles2, glx
330f71742dfSmrg            m = re.match(r'([0-9])\.([0-9])', feature.get('number'))
331e52adb7bSmrg            version = int(m.group(1)) * 10 + int(m.group(2))
332e52adb7bSmrg
333e52adb7bSmrg            self.supported_versions.add(feature.get('name'))
334e52adb7bSmrg
335e52adb7bSmrg            if api == 'gl':
336e52adb7bSmrg                human_name = 'Desktop OpenGL {0}'.format(feature.get('number'))
337e52adb7bSmrg                condition = 'epoxy_is_desktop_gl()'
338e52adb7bSmrg
339e52adb7bSmrg                loader = 'epoxy_get_core_proc_address({0}, {1})'.format('{0}', version)
340e52adb7bSmrg                if version >= 11:
341e52adb7bSmrg                    condition += ' && epoxy_conservative_gl_version() >= {0}'.format(version)
342e52adb7bSmrg            elif api == 'gles2':
343e52adb7bSmrg                human_name = 'OpenGL ES {0}'.format(feature.get('number'))
344e52adb7bSmrg                condition = '!epoxy_is_desktop_gl() && epoxy_gl_version() >= {0}'.format(version)
345e52adb7bSmrg
346e52adb7bSmrg                if version <= 20:
347e52adb7bSmrg                    loader = 'epoxy_gles2_dlsym({0})'
348e52adb7bSmrg                else:
349e52adb7bSmrg                    loader = 'epoxy_gles3_dlsym({0})'
350e52adb7bSmrg            elif api == 'gles1':
351e52adb7bSmrg                human_name = 'OpenGL ES 1.0'
352e52adb7bSmrg                condition = '!epoxy_is_desktop_gl() && epoxy_gl_version() >= 10 && epoxy_gl_version() < 20'
353e52adb7bSmrg                loader = 'epoxy_gles1_dlsym({0})'
354e52adb7bSmrg            elif api == 'glx':
355e52adb7bSmrg                human_name = 'GLX {0}'.format(version)
356e52adb7bSmrg                # We could just always use GPA for loading everything
357e52adb7bSmrg                # but glXGetProcAddress(), but dlsym() is a more
358e52adb7bSmrg                # efficient lookup.
359e52adb7bSmrg                if version > 13:
360e52adb7bSmrg                    condition = 'epoxy_conservative_glx_version() >= {0}'.format(version)
361e52adb7bSmrg                    loader = 'glXGetProcAddress((const GLubyte *){0})'
362e52adb7bSmrg                else:
363e52adb7bSmrg                    condition = 'true'
364e52adb7bSmrg                    loader = 'epoxy_glx_dlsym({0})'
365e52adb7bSmrg            elif api == 'egl':
366e52adb7bSmrg                human_name = 'EGL {0}'.format(version)
367e52adb7bSmrg                if version > 10:
368e52adb7bSmrg                    condition = 'epoxy_conservative_egl_version() >= {0}'.format(version)
369e52adb7bSmrg                else:
370e52adb7bSmrg                    condition = 'true'
371e52adb7bSmrg                # All EGL core entrypoints must be dlsym()ed out --
372e52adb7bSmrg                # eglGetProcAdddress() will return NULL.
373e52adb7bSmrg                loader = 'epoxy_egl_dlsym({0})'
374e52adb7bSmrg            elif api == 'wgl':
375e52adb7bSmrg                human_name = 'WGL {0}'.format(version)
376e52adb7bSmrg                condition = 'true'
377e52adb7bSmrg                loader = 'epoxy_gl_dlsym({0})'
378f71742dfSmrg            elif api == 'glsc2':
379f71742dfSmrg                continue
380e52adb7bSmrg            else:
381e52adb7bSmrg                sys.exit('unknown API: "{0}"'.format(api))
382e52adb7bSmrg
383e52adb7bSmrg            self.process_require_statements(feature, condition, loader, human_name)
384e52adb7bSmrg
385e52adb7bSmrg        for extension in reg.findall('extensions/extension'):
386e52adb7bSmrg            extname = extension.get('name')
387ca86eba8Smrg            cond_extname = "enum_string[enum_string_offsets[i]]"
388e52adb7bSmrg
389e52adb7bSmrg            self.supported_extensions.add(extname)
390e52adb7bSmrg
391e52adb7bSmrg            # 'supported' is a set of strings like gl, gles1, gles2,
392e52adb7bSmrg            # or glx, which are separated by '|'
393e52adb7bSmrg            apis = extension.get('supported').split('|')
394e52adb7bSmrg            if 'glx' in apis:
395ca86eba8Smrg                condition = 'epoxy_conservative_has_glx_extension(provider_name)'
396e52adb7bSmrg                loader = 'glXGetProcAddress((const GLubyte *){0})'
397ca86eba8Smrg                self.process_require_statements(extension, condition, loader, extname)
398e52adb7bSmrg            if 'egl' in apis:
399ca86eba8Smrg                condition = 'epoxy_conservative_has_egl_extension(provider_name)'
400e52adb7bSmrg                loader = 'eglGetProcAddress({0})'
401ca86eba8Smrg                self.process_require_statements(extension, condition, loader, extname)
402e52adb7bSmrg            if 'wgl' in apis:
403ca86eba8Smrg                condition = 'epoxy_conservative_has_wgl_extension(provider_name)'
404e52adb7bSmrg                loader = 'wglGetProcAddress({0})'
405ca86eba8Smrg                self.process_require_statements(extension, condition, loader, extname)
406e52adb7bSmrg            if {'gl', 'gles1', 'gles2'}.intersection(apis):
407ca86eba8Smrg                condition = 'epoxy_conservative_has_gl_extension(provider_name)'
408e52adb7bSmrg                loader = 'epoxy_get_proc_address({0})'
409ca86eba8Smrg                self.process_require_statements(extension, condition, loader, extname)
410e52adb7bSmrg
411e52adb7bSmrg    def fixup_bootstrap_function(self, name, loader):
412e52adb7bSmrg        # We handle glGetString(), glGetIntegerv(), and
413e52adb7bSmrg        # glXGetProcAddressARB() specially, because we need to use
414e52adb7bSmrg        # them in the process of deciding on loaders for resolving,
415e52adb7bSmrg        # and the naive code generation would result in their
416e52adb7bSmrg        # resolvers calling their own resolvers.
417e52adb7bSmrg        if name not in self.functions:
418e52adb7bSmrg            return
419e52adb7bSmrg
420e52adb7bSmrg        func = self.functions[name]
421e52adb7bSmrg        func.providers = {}
422e52adb7bSmrg        func.add_provider('true', loader, 'always present')
423e52adb7bSmrg
424f71742dfSmrg    def parse(self, xml_file):
425f71742dfSmrg        reg = ET.parse(xml_file)
426f71742dfSmrg        comment = reg.find('comment')
427f71742dfSmrg        if comment is not None:
428f71742dfSmrg            self.copyright_comment = comment.text
429e52adb7bSmrg        else:
430e52adb7bSmrg            self.copyright_comment = ''
431e52adb7bSmrg        self.parse_typedefs(reg)
432e52adb7bSmrg        self.parse_enums(reg)
433e52adb7bSmrg        self.parse_function_definitions(reg)
434e52adb7bSmrg        self.parse_function_providers(reg)
435e52adb7bSmrg
436e52adb7bSmrg    def write_copyright_comment_body(self):
437e52adb7bSmrg        for line in self.copyright_comment.splitlines():
438e52adb7bSmrg            if '-----' in line:
439e52adb7bSmrg                break
440e52adb7bSmrg            self.outln(' * ' + line)
441e52adb7bSmrg
442e52adb7bSmrg    def write_enums(self):
443e52adb7bSmrg        for name in sorted(self.supported_versions):
444e52adb7bSmrg            self.outln('#define {0} 1'.format(name))
445e52adb7bSmrg        self.outln('')
446e52adb7bSmrg
447e52adb7bSmrg        for name in sorted(self.supported_extensions):
448e52adb7bSmrg            self.outln('#define {0} 1'.format(name))
449e52adb7bSmrg        self.outln('')
450e52adb7bSmrg
451e52adb7bSmrg        # We want to sort by enum number (which puts a bunch of things
452e52adb7bSmrg        # in a logical order), then by name after that, so we do those
453e52adb7bSmrg        # sorts in reverse.  This is still way uglier than doing some
454e52adb7bSmrg        # sort based on what version/extensions things are introduced
455e52adb7bSmrg        # in, but we haven't paid any attention to those attributes
456e52adb7bSmrg        # for enums yet.
457e52adb7bSmrg        sorted_by_name = sorted(self.enums.keys())
458e52adb7bSmrg        sorted_by_number = sorted(sorted_by_name, key=lambda name: self.enums[name])
459e52adb7bSmrg        for name in sorted_by_number:
460e52adb7bSmrg            self.outln('#define ' + name.ljust(self.max_enum_name_len + 3) + self.enums[name] + '')
461e52adb7bSmrg
462e52adb7bSmrg    def write_function_ptr_typedefs(self):
463e52adb7bSmrg        for func in self.sorted_functions:
464e52adb7bSmrg            self.outln('typedef {0} (GLAPIENTRY *{1})({2});'.format(func.ret_type,
465e52adb7bSmrg                                                                    func.ptr_type,
466e52adb7bSmrg                                                                    func.args_decl))
467e52adb7bSmrg
468f71742dfSmrg    def write_header_header(self, out_file):
469f71742dfSmrg        self.out_file = open(out_file, 'w')
470e52adb7bSmrg
471e52adb7bSmrg        self.outln('/* GL dispatch header.')
472e52adb7bSmrg        self.outln(' * This is code-generated from the GL API XML files from Khronos.')
473e52adb7bSmrg        self.write_copyright_comment_body()
474e52adb7bSmrg        self.outln(' */')
475e52adb7bSmrg        self.outln('')
476e52adb7bSmrg
477e52adb7bSmrg        self.outln('#pragma once')
478e52adb7bSmrg
479e52adb7bSmrg        self.outln('#include <inttypes.h>')
480e52adb7bSmrg        self.outln('#include <stddef.h>')
481e52adb7bSmrg        self.outln('')
482e52adb7bSmrg
483f71742dfSmrg    def write_header(self, out_file):
484f71742dfSmrg        self.write_header_header(out_file)
485f71742dfSmrg
486f71742dfSmrg        self.outln('#include "epoxy/common.h"')
487e52adb7bSmrg
488e52adb7bSmrg        if self.target != "gl":
489e52adb7bSmrg            self.outln('#include "epoxy/gl.h"')
490e52adb7bSmrg            if self.target == "egl":
491e52adb7bSmrg                self.outln('#include "EGL/eglplatform.h"')
492ca86eba8Smrg                # Account for older eglplatform.h, which doesn't define
493ca86eba8Smrg                # the EGL_CAST macro.
494ca86eba8Smrg                self.outln('#ifndef EGL_CAST')
495ca86eba8Smrg                self.outln('#if defined(__cplusplus)')
496ca86eba8Smrg                self.outln('#define EGL_CAST(type, value) (static_cast<type>(value))')
497ca86eba8Smrg                self.outln('#else')
498ca86eba8Smrg                self.outln('#define EGL_CAST(type, value) ((type) (value))')
499ca86eba8Smrg                self.outln('#endif')
500ca86eba8Smrg                self.outln('#endif')
501e52adb7bSmrg        else:
502e52adb7bSmrg            # Add some ridiculous inttypes.h redefinitions that are
503e52adb7bSmrg            # from khrplatform.h and not included in the XML.  We
504e52adb7bSmrg            # don't directly include khrplatform.h because it's not
505e52adb7bSmrg            # present on many systems, and coming up with #ifdefs to
506e52adb7bSmrg            # decide when it's not present would be hard.
507e52adb7bSmrg            self.outln('#define __khrplatform_h_ 1')
508e52adb7bSmrg            self.outln('typedef int8_t khronos_int8_t;')
509e52adb7bSmrg            self.outln('typedef int16_t khronos_int16_t;')
510e52adb7bSmrg            self.outln('typedef int32_t khronos_int32_t;')
511e52adb7bSmrg            self.outln('typedef int64_t khronos_int64_t;')
512e52adb7bSmrg            self.outln('typedef uint8_t khronos_uint8_t;')
513e52adb7bSmrg            self.outln('typedef uint16_t khronos_uint16_t;')
514e52adb7bSmrg            self.outln('typedef uint32_t khronos_uint32_t;')
515e52adb7bSmrg            self.outln('typedef uint64_t khronos_uint64_t;')
516e52adb7bSmrg            self.outln('typedef float khronos_float_t;')
517e52adb7bSmrg            self.outln('typedef long khronos_intptr_t;')
518e52adb7bSmrg            self.outln('typedef long khronos_ssize_t;')
519e52adb7bSmrg            self.outln('typedef unsigned long khronos_usize_t;')
520e52adb7bSmrg            self.outln('typedef uint64_t khronos_utime_nanoseconds_t;')
521e52adb7bSmrg            self.outln('typedef int64_t khronos_stime_nanoseconds_t;')
522e52adb7bSmrg            self.outln('#define KHRONOS_MAX_ENUM 0x7FFFFFFF')
523e52adb7bSmrg            self.outln('typedef enum {')
524e52adb7bSmrg            self.outln('    KHRONOS_FALSE = 0,')
525e52adb7bSmrg            self.outln('    KHRONOS_TRUE  = 1,')
526e52adb7bSmrg            self.outln('    KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM')
527e52adb7bSmrg            self.outln('} khronos_boolean_enum_t;')
528e52adb7bSmrg            self.outln('typedef uintptr_t khronos_uintptr_t;')
529e52adb7bSmrg
530e52adb7bSmrg        if self.target == "glx":
531e52adb7bSmrg            self.outln('#include <X11/Xlib.h>')
532e52adb7bSmrg            self.outln('#include <X11/Xutil.h>')
533e52adb7bSmrg
534e52adb7bSmrg        self.out(self.typedefs)
535e52adb7bSmrg        self.outln('')
536e52adb7bSmrg        self.write_enums()
537e52adb7bSmrg        self.outln('')
538e52adb7bSmrg        self.write_function_ptr_typedefs()
539e52adb7bSmrg
540e52adb7bSmrg        for func in self.sorted_functions:
541f71742dfSmrg            self.outln('EPOXY_PUBLIC {0} (EPOXY_CALLSPEC *epoxy_{1})({2});'.format(func.ret_type,
542f71742dfSmrg                                                                                   func.name,
543f71742dfSmrg                                                                                   func.args_decl))
544e52adb7bSmrg            self.outln('')
545e52adb7bSmrg
546e52adb7bSmrg        for func in self.sorted_functions:
547e52adb7bSmrg            self.outln('#define {0} epoxy_{0}'.format(func.name))
548e52adb7bSmrg
549e52adb7bSmrg    def write_function_ptr_resolver(self, func):
550e52adb7bSmrg        self.outln('static {0}'.format(func.ptr_type))
551e52adb7bSmrg        self.outln('epoxy_{0}_resolver(void)'.format(func.wrapped_name))
552e52adb7bSmrg        self.outln('{')
553e52adb7bSmrg
554e52adb7bSmrg        providers = []
555e52adb7bSmrg        # Make a local list of all the providers for this alias group
556f71742dfSmrg        alias_root = func
557e52adb7bSmrg        if func.alias_func:
558e52adb7bSmrg            alias_root = func.alias_func
559e52adb7bSmrg        for provider in alias_root.providers.values():
560e52adb7bSmrg            providers.append(provider)
561e52adb7bSmrg        for alias_func in alias_root.alias_exts:
562e52adb7bSmrg            for provider in alias_func.providers.values():
563e52adb7bSmrg                providers.append(provider)
564e52adb7bSmrg
565e52adb7bSmrg        # Add some partial aliases of a few functions.  These are ones
566e52adb7bSmrg        # that aren't quite aliases, because of some trivial behavior
567e52adb7bSmrg        # difference (like whether to produce an error for a
568e52adb7bSmrg        # non-Genned name), but where we'd like to fall back to the
569e52adb7bSmrg        # similar function if the proper one isn't present.
570e52adb7bSmrg        half_aliases = {
571e52adb7bSmrg            'glBindVertexArray' : 'glBindVertexArrayAPPLE',
572e52adb7bSmrg            'glBindVertexArrayAPPLE' : 'glBindVertexArray',
573e52adb7bSmrg            'glBindFramebuffer' : 'glBindFramebufferEXT',
574e52adb7bSmrg            'glBindFramebufferEXT' : 'glBindFramebuffer',
575f71742dfSmrg            'glBindRenderbuffer' : 'glBindRenderbufferEXT',
576f71742dfSmrg            'glBindRenderbufferEXT' : 'glBindRenderbuffer',
577e52adb7bSmrg        }
578e52adb7bSmrg        if func.name in half_aliases:
579e52adb7bSmrg            alias_func = self.functions[half_aliases[func.name]]
580e52adb7bSmrg            for provider in alias_func.providers.values():
581e52adb7bSmrg                providers.append(provider)
582e52adb7bSmrg
583e52adb7bSmrg        def provider_sort(provider):
584e52adb7bSmrg            return (provider.name != func.name, provider.name, provider.enum)
585f71742dfSmrg        providers.sort(key=provider_sort)
586e52adb7bSmrg
587e52adb7bSmrg        if len(providers) != 1:
588e52adb7bSmrg            self.outln('    static const enum {0}_provider providers[] = {{'.format(self.target))
589e52adb7bSmrg            for provider in providers:
590e52adb7bSmrg                self.outln('        {0},'.format(provider.enum))
591e52adb7bSmrg            self.outln('        {0}_provider_terminator'.format(self.target))
592e52adb7bSmrg            self.outln('    };')
593e52adb7bSmrg
594f71742dfSmrg            self.outln('    static const uint32_t entrypoints[] = {')
595e52adb7bSmrg            if len(providers) > 1:
596e52adb7bSmrg                for provider in providers:
597e52adb7bSmrg                    self.outln('        {0} /* "{1}" */,'.format(self.entrypoint_string_offset[provider.name], provider.name))
598e52adb7bSmrg            else:
599f71742dfSmrg                self.outln('        0 /* None */,')
600e52adb7bSmrg            self.outln('    };')
601e52adb7bSmrg
602e52adb7bSmrg            self.outln('    return {0}_provider_resolver(entrypoint_strings + {1} /* "{2}" */,'.format(self.target,
603e52adb7bSmrg                                                                                                       self.entrypoint_string_offset[func.name],
604e52adb7bSmrg                                                                                                       func.name))
605e52adb7bSmrg            self.outln('                                providers, entrypoints);')
606e52adb7bSmrg        else:
607f71742dfSmrg            assert providers[0].name == func.name
608e52adb7bSmrg            self.outln('    return {0}_single_resolver({1}, {2} /* {3} */);'.format(self.target,
609e52adb7bSmrg                                                                                    providers[0].enum,
610e52adb7bSmrg                                                                                    self.entrypoint_string_offset[func.name],
611e52adb7bSmrg                                                                                    func.name))
612e52adb7bSmrg        self.outln('}')
613e52adb7bSmrg        self.outln('')
614e52adb7bSmrg
615e52adb7bSmrg    def write_thunks(self, func):
616e52adb7bSmrg        # Writes out the function that's initially plugged into the
617e52adb7bSmrg        # global function pointer, which resolves, updates the global
618e52adb7bSmrg        # function pointer, and calls down to it.
619e52adb7bSmrg        #
620e52adb7bSmrg        # It also writes out the actual initialized global function
621e52adb7bSmrg        # pointer.
622e52adb7bSmrg        if func.ret_type == 'void':
623e52adb7bSmrg            self.outln('GEN_THUNKS({0}, ({1}), ({2}))'.format(func.wrapped_name,
624e52adb7bSmrg                                                              func.args_decl,
625e52adb7bSmrg                                                              func.args_list))
626e52adb7bSmrg        else:
627e52adb7bSmrg            self.outln('GEN_THUNKS_RET({0}, {1}, ({2}), ({3}))'.format(func.ret_type,
628e52adb7bSmrg                                                                       func.wrapped_name,
629e52adb7bSmrg                                                                       func.args_decl,
630e52adb7bSmrg                                                                       func.args_list))
631e52adb7bSmrg
632e52adb7bSmrg    def write_function_pointer(self, func):
633f71742dfSmrg        self.outln('{0} epoxy_{1} = epoxy_{1}_global_rewrite_ptr;'.format(func.ptr_type, func.wrapped_name))
634e52adb7bSmrg        self.outln('')
635e52adb7bSmrg
636e52adb7bSmrg    def write_provider_enums(self):
637e52adb7bSmrg        # Writes the enum declaration for the list of providers
638e52adb7bSmrg        # supported by gl_provider_resolver()
639e52adb7bSmrg
640f71742dfSmrg        self.outln('')
641e52adb7bSmrg        self.outln('enum {0}_provider {{'.format(self.target))
642e52adb7bSmrg
643e52adb7bSmrg        sorted_providers = sorted(self.provider_enum.keys())
644e52adb7bSmrg
645e52adb7bSmrg        # We always put a 0 enum first so that we can have a
646e52adb7bSmrg        # terminator in our arrays
647e52adb7bSmrg        self.outln('    {0}_provider_terminator = 0,'.format(self.target))
648e52adb7bSmrg
649e52adb7bSmrg        for human_name in sorted_providers:
650e52adb7bSmrg            enum = self.provider_enum[human_name]
651e52adb7bSmrg            self.outln('    {0},'.format(enum))
652e52adb7bSmrg        self.outln('} PACKED;')
653f71742dfSmrg        self.outln('ENDPACKED')
654e52adb7bSmrg        self.outln('')
655e52adb7bSmrg
656e52adb7bSmrg    def write_provider_enum_strings(self):
657e52adb7bSmrg        # Writes the mapping from enums to the strings describing them
658e52adb7bSmrg        # for epoxy_print_failure_reasons().
659e52adb7bSmrg
660e52adb7bSmrg        sorted_providers = sorted(self.provider_enum.keys())
661e52adb7bSmrg
662e52adb7bSmrg        offset = 0
663e52adb7bSmrg        self.outln('static const char *enum_string =')
664e52adb7bSmrg        for human_name in sorted_providers:
665f71742dfSmrg            self.outln('    "{0}\\0"'.format(human_name))
666e52adb7bSmrg            self.enum_string_offset[human_name] = offset
667e52adb7bSmrg            offset += len(human_name.replace('\\', '')) + 1
668e52adb7bSmrg        self.outln('     ;')
669e52adb7bSmrg        self.outln('')
670e52adb7bSmrg        # We're using uint16_t for the offsets.
671f71742dfSmrg        assert offset < 65536
672e52adb7bSmrg
673e52adb7bSmrg        self.outln('static const uint16_t enum_string_offsets[] = {')
674f71742dfSmrg        self.outln('    -1, /* {0}_provider_terminator, unused */'.format(self.target))
675e52adb7bSmrg        for human_name in sorted_providers:
676e52adb7bSmrg            enum = self.provider_enum[human_name]
677ca86eba8Smrg            self.outln('    {1}, /* {0} */'.format(human_name, self.enum_string_offset[human_name]))
678e52adb7bSmrg        self.outln('};')
679e52adb7bSmrg        self.outln('')
680e52adb7bSmrg
681e52adb7bSmrg    def write_entrypoint_strings(self):
682f71742dfSmrg        self.outln('static const char entrypoint_strings[] = {')
683e52adb7bSmrg        offset = 0
684e52adb7bSmrg        for func in self.sorted_functions:
685e52adb7bSmrg            if func.name not in self.entrypoint_string_offset:
686e52adb7bSmrg                self.entrypoint_string_offset[func.name] = offset
687e52adb7bSmrg                offset += len(func.name) + 1
688f71742dfSmrg                for c in func.name:
689f71742dfSmrg                    self.outln("   '{0}',".format(c))
690f71742dfSmrg                self.outln('   0, // {0}'.format(func.name))
691f71742dfSmrg        self.outln('    0 };')
692e52adb7bSmrg        # We're using uint16_t for the offsets.
693f71742dfSmrg        #assert(offset < 65536)
694e52adb7bSmrg        self.outln('')
695e52adb7bSmrg
696e52adb7bSmrg    def write_provider_resolver(self):
697e52adb7bSmrg        self.outln('static void *{0}_provider_resolver(const char *name,'.format(self.target))
698e52adb7bSmrg        self.outln('                                   const enum {0}_provider *providers,'.format(self.target))
699f71742dfSmrg        self.outln('                                   const uint32_t *entrypoints)')
700e52adb7bSmrg        self.outln('{')
701e52adb7bSmrg        self.outln('    int i;')
702e52adb7bSmrg
703e52adb7bSmrg        self.outln('    for (i = 0; providers[i] != {0}_provider_terminator; i++) {{'.format(self.target))
704ca86eba8Smrg        self.outln('        const char *provider_name = enum_string + enum_string_offsets[providers[i]];')
705e52adb7bSmrg        self.outln('        switch (providers[i]) {')
706ca86eba8Smrg        self.outln('')
707e52adb7bSmrg
708e52adb7bSmrg        for human_name in sorted(self.provider_enum.keys()):
709e52adb7bSmrg            enum = self.provider_enum[human_name]
710e52adb7bSmrg            self.outln('        case {0}:'.format(enum))
711e52adb7bSmrg            self.outln('            if ({0})'.format(self.provider_condition[human_name]))
712e52adb7bSmrg            self.outln('                return {0};'.format(self.provider_loader[human_name]).format("entrypoint_strings + entrypoints[i]"))
713e52adb7bSmrg            self.outln('            break;')
714e52adb7bSmrg
715e52adb7bSmrg        self.outln('        case {0}_provider_terminator:'.format(self.target))
716e52adb7bSmrg        self.outln('            abort(); /* Not reached */')
717e52adb7bSmrg        self.outln('        }')
718e52adb7bSmrg        self.outln('    }')
719e52adb7bSmrg        self.outln('')
720e52adb7bSmrg
721ca86eba8Smrg        self.outln('    if (epoxy_resolver_failure_handler)')
722ca86eba8Smrg        self.outln('        return epoxy_resolver_failure_handler(name);')
723ca86eba8Smrg        self.outln('')
724ca86eba8Smrg
725e52adb7bSmrg        # If the function isn't provided by any known extension, print
726e52adb7bSmrg        # something useful for the poor application developer before
727e52adb7bSmrg        # aborting.  (In non-epoxy GL usage, the app developer would
728e52adb7bSmrg        # call into some blank stub function and segfault).
729e52adb7bSmrg        self.outln('    fprintf(stderr, "No provider of %s found.  Requires one of:\\n", name);')
730e52adb7bSmrg        self.outln('    for (i = 0; providers[i] != {0}_provider_terminator; i++) {{'.format(self.target))
731e52adb7bSmrg        self.outln('        fprintf(stderr, "    %s\\n", enum_string + enum_string_offsets[providers[i]]);')
732e52adb7bSmrg        self.outln('    }')
733e52adb7bSmrg        self.outln('    if (providers[0] == {0}_provider_terminator) {{'.format(self.target))
734e52adb7bSmrg        self.outln('        fprintf(stderr, "    No known providers.  This is likely a bug "')
735e52adb7bSmrg        self.outln('                        "in libepoxy code generation\\n");')
736e52adb7bSmrg        self.outln('    }')
737e52adb7bSmrg        self.outln('    abort();')
738e52adb7bSmrg
739e52adb7bSmrg        self.outln('}')
740e52adb7bSmrg        self.outln('')
741e52adb7bSmrg
742f71742dfSmrg        single_resolver_proto = '{0}_single_resolver(enum {0}_provider provider, uint32_t entrypoint_offset)'.format(self.target)
743e52adb7bSmrg        self.outln('EPOXY_NOINLINE static void *')
744e52adb7bSmrg        self.outln('{0};'.format(single_resolver_proto))
745e52adb7bSmrg        self.outln('')
746e52adb7bSmrg        self.outln('static void *')
747e52adb7bSmrg        self.outln('{0}'.format(single_resolver_proto))
748e52adb7bSmrg        self.outln('{')
749e52adb7bSmrg        self.outln('    enum {0}_provider providers[] = {{'.format(self.target))
750e52adb7bSmrg        self.outln('        provider,')
751e52adb7bSmrg        self.outln('        {0}_provider_terminator'.format(self.target))
752e52adb7bSmrg        self.outln('    };')
753e52adb7bSmrg        self.outln('    return {0}_provider_resolver(entrypoint_strings + entrypoint_offset,'.format(self.target))
754e52adb7bSmrg        self.outln('                                providers, &entrypoint_offset);')
755e52adb7bSmrg        self.outln('}')
756e52adb7bSmrg        self.outln('')
757e52adb7bSmrg
758f71742dfSmrg    def write_source(self, f):
759f71742dfSmrg        self.out_file = open(f, 'w')
760e52adb7bSmrg
761e52adb7bSmrg        self.outln('/* GL dispatch code.')
762e52adb7bSmrg        self.outln(' * This is code-generated from the GL API XML files from Khronos.')
763e52adb7bSmrg        self.write_copyright_comment_body()
764e52adb7bSmrg        self.outln(' */')
765e52adb7bSmrg        self.outln('')
766f71742dfSmrg        self.outln('#include "config.h"')
767f71742dfSmrg        self.outln('')
768e52adb7bSmrg        self.outln('#include <stdlib.h>')
769e52adb7bSmrg        self.outln('#include <string.h>')
770e52adb7bSmrg        self.outln('#include <stdio.h>')
771e52adb7bSmrg        self.outln('')
772e52adb7bSmrg        self.outln('#include "dispatch_common.h"')
773e52adb7bSmrg        self.outln('#include "epoxy/{0}.h"'.format(self.target))
774e52adb7bSmrg        self.outln('')
775e52adb7bSmrg        self.outln('#ifdef __GNUC__')
776e52adb7bSmrg        self.outln('#define EPOXY_NOINLINE __attribute__((noinline))')
777e52adb7bSmrg        self.outln('#elif defined (_MSC_VER)')
778e52adb7bSmrg        self.outln('#define EPOXY_NOINLINE __declspec(noinline)')
779e52adb7bSmrg        self.outln('#endif')
780e52adb7bSmrg
781e52adb7bSmrg        self.outln('struct dispatch_table {')
782e52adb7bSmrg        for func in self.sorted_functions:
783e52adb7bSmrg            self.outln('    {0} epoxy_{1};'.format(func.ptr_type, func.wrapped_name))
784e52adb7bSmrg        self.outln('};')
785e52adb7bSmrg        self.outln('')
786e52adb7bSmrg
787e52adb7bSmrg        # Early declaration, so we can declare the real thing at the
788e52adb7bSmrg        # bottom. (I want the function_ptr_resolver as the first
789e52adb7bSmrg        # per-GL-call code, since it's the most interesting to see
790e52adb7bSmrg        # when you search for the implementation of a call)
791e52adb7bSmrg        self.outln('#if USING_DISPATCH_TABLE')
792e52adb7bSmrg        self.outln('static inline struct dispatch_table *')
793e52adb7bSmrg        self.outln('get_dispatch_table(void);')
794e52adb7bSmrg        self.outln('')
795e52adb7bSmrg        self.outln('#endif')
796e52adb7bSmrg
797e52adb7bSmrg        self.write_provider_enums()
798e52adb7bSmrg        self.write_provider_enum_strings()
799e52adb7bSmrg        self.write_entrypoint_strings()
800e52adb7bSmrg        self.write_provider_resolver()
801e52adb7bSmrg
802e52adb7bSmrg        for func in self.sorted_functions:
803e52adb7bSmrg            self.write_function_ptr_resolver(func)
804e52adb7bSmrg
805e52adb7bSmrg        for func in self.sorted_functions:
806e52adb7bSmrg            self.write_thunks(func)
807e52adb7bSmrg        self.outln('')
808e52adb7bSmrg
809e52adb7bSmrg        self.outln('#if USING_DISPATCH_TABLE')
810e52adb7bSmrg
811e52adb7bSmrg        self.outln('static struct dispatch_table resolver_table = {')
812e52adb7bSmrg        for func in self.sorted_functions:
813f71742dfSmrg            self.outln('    epoxy_{0}_dispatch_table_rewrite_ptr, /* {0} */'.format(func.wrapped_name))
814e52adb7bSmrg        self.outln('};')
815e52adb7bSmrg        self.outln('')
816e52adb7bSmrg
817e52adb7bSmrg        self.outln('uint32_t {0}_tls_index;'.format(self.target))
818e52adb7bSmrg        self.outln('uint32_t {0}_tls_size = sizeof(struct dispatch_table);'.format(self.target))
819e52adb7bSmrg        self.outln('')
820e52adb7bSmrg
821e52adb7bSmrg        self.outln('static inline struct dispatch_table *')
822e52adb7bSmrg        self.outln('get_dispatch_table(void)')
823e52adb7bSmrg        self.outln('{')
824e52adb7bSmrg        self.outln('	return TlsGetValue({0}_tls_index);'.format(self.target))
825e52adb7bSmrg        self.outln('}')
826e52adb7bSmrg        self.outln('')
827e52adb7bSmrg
828e52adb7bSmrg        self.outln('void')
829e52adb7bSmrg        self.outln('{0}_init_dispatch_table(void)'.format(self.target))
830e52adb7bSmrg        self.outln('{')
831e52adb7bSmrg        self.outln('    struct dispatch_table *dispatch_table = get_dispatch_table();')
832e52adb7bSmrg        self.outln('    memcpy(dispatch_table, &resolver_table, sizeof(resolver_table));')
833e52adb7bSmrg        self.outln('}')
834e52adb7bSmrg        self.outln('')
835e52adb7bSmrg
836e52adb7bSmrg        self.outln('void')
837e52adb7bSmrg        self.outln('{0}_switch_to_dispatch_table(void)'.format(self.target))
838e52adb7bSmrg        self.outln('{')
839e52adb7bSmrg
840e52adb7bSmrg        for func in self.sorted_functions:
841e52adb7bSmrg            self.outln('    epoxy_{0} = epoxy_{0}_dispatch_table_thunk;'.format(func.wrapped_name))
842e52adb7bSmrg
843e52adb7bSmrg        self.outln('}')
844e52adb7bSmrg        self.outln('')
845e52adb7bSmrg
846e52adb7bSmrg        self.outln('#endif /* !USING_DISPATCH_TABLE */')
847e52adb7bSmrg
848e52adb7bSmrg        for func in self.sorted_functions:
849e52adb7bSmrg            self.write_function_pointer(func)
850e52adb7bSmrg
851e52adb7bSmrgargparser = argparse.ArgumentParser(description='Generate GL dispatch wrappers.')
852e52adb7bSmrgargparser.add_argument('files', metavar='file.xml', nargs='+', help='GL API XML files to be parsed')
853f71742dfSmrgargparser.add_argument('--outputdir', metavar='dir', required=False, help='Destination directory for files (default to current dir)')
854f71742dfSmrgargparser.add_argument('--includedir', metavar='dir', required=False, help='Destination directory for headers')
855f71742dfSmrgargparser.add_argument('--srcdir', metavar='dir', required=False, help='Destination directory for source')
856f71742dfSmrgargparser.add_argument('--source', dest='source', action='store_true', required=False, help='Generate the source file')
857f71742dfSmrgargparser.add_argument('--no-source', dest='source', action='store_false', required=False, help='Do not generate the source file')
858f71742dfSmrgargparser.add_argument('--header', dest='header', action='store_true', required=False, help='Generate the header file')
859f71742dfSmrgargparser.add_argument('--no-header', dest='header', action='store_false', required=False, help='Do not generate the header file')
860e52adb7bSmrgargs = argparser.parse_args()
861e52adb7bSmrg
862f71742dfSmrgif args.outputdir:
863f71742dfSmrg    outputdir = args.outputdir
864f71742dfSmrgelse:
865f71742dfSmrg    outputdir = os.getcwd()
866f71742dfSmrg
867f71742dfSmrgif args.includedir:
868f71742dfSmrg    includedir = args.includedir
869f71742dfSmrgelse:
870f71742dfSmrg    includedir = outputdir
871f71742dfSmrg
872f71742dfSmrgif args.srcdir:
873f71742dfSmrg    srcdir = args.srcdir
874f71742dfSmrgelse:
875f71742dfSmrg    srcdir = outputdir
876f71742dfSmrg
877f71742dfSmrgbuild_source = args.source
878f71742dfSmrgbuild_header = args.header
879f71742dfSmrg
880f71742dfSmrgif not build_source and not build_header:
881f71742dfSmrg    build_source = True
882f71742dfSmrg    build_header = True
883e52adb7bSmrg
884f71742dfSmrgfor f in args.files:
885f71742dfSmrg    name = os.path.basename(f).split('.xml')[0]
886e52adb7bSmrg    generator = Generator(name)
887f71742dfSmrg    generator.parse(f)
888e52adb7bSmrg
889e52adb7bSmrg    generator.drop_weird_glx_functions()
890e52adb7bSmrg
891e52adb7bSmrg    # This is an ANSI vs Unicode function, handled specially by
892e52adb7bSmrg    # include/epoxy/wgl.h
893e52adb7bSmrg    if 'wglUseFontBitmaps' in generator.functions:
894e52adb7bSmrg        del generator.functions['wglUseFontBitmaps']
895e52adb7bSmrg
896e52adb7bSmrg    generator.sort_functions()
897e52adb7bSmrg    generator.resolve_aliases()
898e52adb7bSmrg    generator.fixup_bootstrap_function('glGetString',
899e52adb7bSmrg                                       'epoxy_get_bootstrap_proc_address({0})')
900e52adb7bSmrg    generator.fixup_bootstrap_function('glGetIntegerv',
901e52adb7bSmrg                                       'epoxy_get_bootstrap_proc_address({0})')
902e52adb7bSmrg
903e52adb7bSmrg    # While this is technically exposed as a GLX extension, it's
904e52adb7bSmrg    # required to be present as a public symbol by the Linux OpenGL
905e52adb7bSmrg    # ABI.
906e52adb7bSmrg    generator.fixup_bootstrap_function('glXGetProcAddress',
907e52adb7bSmrg                                       'epoxy_glx_dlsym({0})')
908e52adb7bSmrg
909e52adb7bSmrg    generator.prepare_provider_enum()
910e52adb7bSmrg
911f71742dfSmrg    if build_header:
912f71742dfSmrg        generator.write_header(os.path.join(includedir, name + '_generated.h'))
913f71742dfSmrg    if build_source:
914f71742dfSmrg        generator.write_source(os.path.join(srcdir, name + '_generated_dispatch.c'))
915