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