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