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