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