1848b8605Smrg 2848b8605Smrg# (C) Copyright IBM Corporation 2004, 2005 3848b8605Smrg# All Rights Reserved. 4848b8605Smrg# 5848b8605Smrg# Permission is hereby granted, free of charge, to any person obtaining a 6848b8605Smrg# copy of this software and associated documentation files (the "Software"), 7848b8605Smrg# to deal in the Software without restriction, including without limitation 8848b8605Smrg# on the rights to use, copy, modify, merge, publish, distribute, sub 9848b8605Smrg# license, and/or sell copies of the Software, and to permit persons to whom 10848b8605Smrg# the Software is furnished to do so, subject to the following conditions: 11848b8605Smrg# 12848b8605Smrg# The above copyright notice and this permission notice (including the next 13848b8605Smrg# paragraph) shall be included in all copies or substantial portions of the 14848b8605Smrg# Software. 15848b8605Smrg# 16848b8605Smrg# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17848b8605Smrg# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18848b8605Smrg# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 19848b8605Smrg# IBM AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20848b8605Smrg# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21848b8605Smrg# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 22848b8605Smrg# IN THE SOFTWARE. 23848b8605Smrg# 24848b8605Smrg# Authors: 25848b8605Smrg# Ian Romanick <idr@us.ibm.com> 26848b8605Smrg 27b8e80941Smrgfrom __future__ import print_function 28b8e80941Smrg 29b8e80941Smrgfrom collections import OrderedDict 30848b8605Smrgfrom decimal import Decimal 31848b8605Smrgimport xml.etree.ElementTree as ET 32b8e80941Smrgimport re, sys 33848b8605Smrgimport os.path 34848b8605Smrgimport typeexpr 35b8e80941Smrgimport static_data 36848b8605Smrg 37848b8605Smrg 38848b8605Smrgdef parse_GL_API( file_name, factory = None ): 39848b8605Smrg 40848b8605Smrg if not factory: 41848b8605Smrg factory = gl_item_factory() 42848b8605Smrg 43848b8605Smrg api = factory.create_api() 44848b8605Smrg api.parse_file( file_name ) 45848b8605Smrg 46848b8605Smrg # After the XML has been processed, we need to go back and assign 47848b8605Smrg # dispatch offsets to the functions that request that their offsets 48848b8605Smrg # be assigned by the scripts. Typically this means all functions 49848b8605Smrg # that are not part of the ABI. 50848b8605Smrg 51848b8605Smrg for func in api.functionIterateByCategory(): 52b8e80941Smrg if func.assign_offset and func.offset < 0: 53848b8605Smrg func.offset = api.next_offset; 54848b8605Smrg api.next_offset += 1 55848b8605Smrg 56848b8605Smrg return api 57848b8605Smrg 58848b8605Smrg 59848b8605Smrgdef is_attr_true( element, name, default = "false" ): 60848b8605Smrg """Read a name value from an element's attributes. 61848b8605Smrg 62848b8605Smrg The value read from the attribute list must be either 'true' or 63848b8605Smrg 'false'. If the value is 'false', zero will be returned. If the 64848b8605Smrg value is 'true', non-zero will be returned. An exception will be 65848b8605Smrg raised for any other value.""" 66848b8605Smrg 67848b8605Smrg value = element.get( name, default ) 68848b8605Smrg if value == "true": 69848b8605Smrg return 1 70848b8605Smrg elif value == "false": 71848b8605Smrg return 0 72848b8605Smrg else: 73848b8605Smrg raise RuntimeError('Invalid value "%s" for boolean "%s".' % (value, name)) 74848b8605Smrg 75848b8605Smrg 76848b8605Smrgclass gl_print_base(object): 77848b8605Smrg """Base class of all API pretty-printers. 78848b8605Smrg 79848b8605Smrg In the model-view-controller pattern, this is the view. Any derived 80848b8605Smrg class will want to over-ride the printBody, printRealHader, and 81848b8605Smrg printRealFooter methods. Some derived classes may want to over-ride 82848b8605Smrg printHeader and printFooter, or even Print (though this is unlikely). 83848b8605Smrg """ 84848b8605Smrg 85848b8605Smrg def __init__(self): 86848b8605Smrg # Name of the script that is generating the output file. 87848b8605Smrg # Every derived class should set this to the name of its 88848b8605Smrg # source file. 89848b8605Smrg 90848b8605Smrg self.name = "a" 91848b8605Smrg 92848b8605Smrg 93848b8605Smrg # License on the *generated* source file. This may differ 94848b8605Smrg # from the license on the script that is generating the file. 95848b8605Smrg # Every derived class should set this to some reasonable 96848b8605Smrg # value. 97848b8605Smrg # 98848b8605Smrg # See license.py for an example of a reasonable value. 99848b8605Smrg 100848b8605Smrg self.license = "The license for this file is unspecified." 101848b8605Smrg 102848b8605Smrg 103848b8605Smrg # The header_tag is the name of the C preprocessor define 104848b8605Smrg # used to prevent multiple inclusion. Typically only 105848b8605Smrg # generated C header files need this to be set. Setting it 106848b8605Smrg # causes code to be generated automatically in printHeader 107848b8605Smrg # and printFooter. 108848b8605Smrg 109848b8605Smrg self.header_tag = None 110848b8605Smrg 111848b8605Smrg 112848b8605Smrg # List of file-private defines that must be undefined at the 113848b8605Smrg # end of the file. This can be used in header files to define 114848b8605Smrg # names for use in the file, then undefine them at the end of 115848b8605Smrg # the header file. 116848b8605Smrg 117848b8605Smrg self.undef_list = [] 118848b8605Smrg return 119848b8605Smrg 120848b8605Smrg 121848b8605Smrg def Print(self, api): 122848b8605Smrg self.printHeader() 123848b8605Smrg self.printBody(api) 124848b8605Smrg self.printFooter() 125848b8605Smrg return 126848b8605Smrg 127848b8605Smrg 128848b8605Smrg def printHeader(self): 129848b8605Smrg """Print the header associated with all files and call the printRealHeader method.""" 130848b8605Smrg 131b8e80941Smrg print('/* DO NOT EDIT - This file generated automatically by %s script */' \ 132b8e80941Smrg % (self.name)) 133b8e80941Smrg print('') 134b8e80941Smrg print('/*') 135b8e80941Smrg print((' * ' + self.license.replace('\n', '\n * ')).replace(' \n', '\n')) 136b8e80941Smrg print(' */') 137b8e80941Smrg print('') 138848b8605Smrg if self.header_tag: 139b8e80941Smrg print('#if !defined( %s )' % (self.header_tag)) 140b8e80941Smrg print('# define %s' % (self.header_tag)) 141b8e80941Smrg print('') 142848b8605Smrg self.printRealHeader(); 143848b8605Smrg return 144848b8605Smrg 145848b8605Smrg 146848b8605Smrg def printFooter(self): 147848b8605Smrg """Print the header associated with all files and call the printRealFooter method.""" 148848b8605Smrg 149848b8605Smrg self.printRealFooter() 150848b8605Smrg 151848b8605Smrg if self.undef_list: 152b8e80941Smrg print('') 153848b8605Smrg for u in self.undef_list: 154b8e80941Smrg print("# undef %s" % (u)) 155848b8605Smrg 156848b8605Smrg if self.header_tag: 157b8e80941Smrg print('') 158b8e80941Smrg print('#endif /* !defined( %s ) */' % (self.header_tag)) 159848b8605Smrg 160848b8605Smrg 161848b8605Smrg def printRealHeader(self): 162848b8605Smrg """Print the "real" header for the created file. 163848b8605Smrg 164848b8605Smrg In the base class, this function is empty. All derived 165848b8605Smrg classes should over-ride this function.""" 166848b8605Smrg return 167848b8605Smrg 168848b8605Smrg 169848b8605Smrg def printRealFooter(self): 170848b8605Smrg """Print the "real" footer for the created file. 171848b8605Smrg 172848b8605Smrg In the base class, this function is empty. All derived 173848b8605Smrg classes should over-ride this function.""" 174848b8605Smrg return 175848b8605Smrg 176848b8605Smrg 177848b8605Smrg def printPure(self): 178848b8605Smrg """Conditionally define `PURE' function attribute. 179848b8605Smrg 180848b8605Smrg Conditionally defines a preprocessor macro `PURE' that wraps 181848b8605Smrg GCC's `pure' function attribute. The conditional code can be 182848b8605Smrg easilly adapted to other compilers that support a similar 183848b8605Smrg feature. 184848b8605Smrg 185848b8605Smrg The name is also added to the file's undef_list. 186848b8605Smrg """ 187848b8605Smrg self.undef_list.append("PURE") 188b8e80941Smrg print("""# if defined(__GNUC__) || (defined(__SUNPRO_C) && (__SUNPRO_C >= 0x590)) 189848b8605Smrg# define PURE __attribute__((pure)) 190848b8605Smrg# else 191848b8605Smrg# define PURE 192b8e80941Smrg# endif""") 193848b8605Smrg return 194848b8605Smrg 195848b8605Smrg 196848b8605Smrg def printFastcall(self): 197848b8605Smrg """Conditionally define `FASTCALL' function attribute. 198848b8605Smrg 199848b8605Smrg Conditionally defines a preprocessor macro `FASTCALL' that 200848b8605Smrg wraps GCC's `fastcall' function attribute. The conditional 201848b8605Smrg code can be easilly adapted to other compilers that support a 202848b8605Smrg similar feature. 203848b8605Smrg 204848b8605Smrg The name is also added to the file's undef_list. 205848b8605Smrg """ 206848b8605Smrg 207848b8605Smrg self.undef_list.append("FASTCALL") 208b8e80941Smrg print("""# if defined(__i386__) && defined(__GNUC__) && !defined(__CYGWIN__) && !defined(__MINGW32__) 209848b8605Smrg# define FASTCALL __attribute__((fastcall)) 210848b8605Smrg# else 211848b8605Smrg# define FASTCALL 212b8e80941Smrg# endif""") 213848b8605Smrg return 214848b8605Smrg 215848b8605Smrg 216848b8605Smrg def printVisibility(self, S, s): 217848b8605Smrg """Conditionally define visibility function attribute. 218848b8605Smrg 219848b8605Smrg Conditionally defines a preprocessor macro name S that wraps 220848b8605Smrg GCC's visibility function attribute. The visibility used is 221848b8605Smrg the parameter s. The conditional code can be easilly adapted 222848b8605Smrg to other compilers that support a similar feature. 223848b8605Smrg 224848b8605Smrg The name is also added to the file's undef_list. 225848b8605Smrg """ 226848b8605Smrg 227848b8605Smrg self.undef_list.append(S) 228b8e80941Smrg print("""# if defined(__GNUC__) && !defined(__CYGWIN__) && !defined(__MINGW32__) 229848b8605Smrg# define %s __attribute__((visibility("%s"))) 230848b8605Smrg# else 231848b8605Smrg# define %s 232b8e80941Smrg# endif""" % (S, s, S)) 233848b8605Smrg return 234848b8605Smrg 235848b8605Smrg 236848b8605Smrg def printNoinline(self): 237848b8605Smrg """Conditionally define `NOINLINE' function attribute. 238848b8605Smrg 239848b8605Smrg Conditionally defines a preprocessor macro `NOINLINE' that 240848b8605Smrg wraps GCC's `noinline' function attribute. The conditional 241848b8605Smrg code can be easilly adapted to other compilers that support a 242848b8605Smrg similar feature. 243848b8605Smrg 244848b8605Smrg The name is also added to the file's undef_list. 245848b8605Smrg """ 246848b8605Smrg 247848b8605Smrg self.undef_list.append("NOINLINE") 248b8e80941Smrg print("""# if defined(__GNUC__) 249848b8605Smrg# define NOINLINE __attribute__((noinline)) 250848b8605Smrg# else 251848b8605Smrg# define NOINLINE 252b8e80941Smrg# endif""") 253848b8605Smrg return 254848b8605Smrg 255848b8605Smrg 256848b8605Smrgdef real_function_name(element): 257848b8605Smrg name = element.get( "name" ) 258848b8605Smrg alias = element.get( "alias" ) 259848b8605Smrg 260848b8605Smrg if alias: 261848b8605Smrg return alias 262848b8605Smrg else: 263848b8605Smrg return name 264848b8605Smrg 265848b8605Smrg 266848b8605Smrgdef real_category_name(c): 267848b8605Smrg if re.compile("[1-9][0-9]*[.][0-9]+").match(c): 268848b8605Smrg return "GL_VERSION_" + c.replace(".", "_") 269848b8605Smrg else: 270848b8605Smrg return c 271848b8605Smrg 272848b8605Smrg 273848b8605Smrgdef classify_category(name, number): 274848b8605Smrg """Based on the category name and number, select a numerical class for it. 275848b8605Smrg 276848b8605Smrg Categories are divided into four classes numbered 0 through 3. The 277848b8605Smrg classes are: 278848b8605Smrg 279848b8605Smrg 0. Core GL versions, sorted by version number. 280848b8605Smrg 1. ARB extensions, sorted by extension number. 281848b8605Smrg 2. Non-ARB extensions, sorted by extension number. 282848b8605Smrg 3. Un-numbered extensions, sorted by extension name. 283848b8605Smrg """ 284848b8605Smrg 285848b8605Smrg try: 286848b8605Smrg core_version = float(name) 287b8e80941Smrg except Exception: 288848b8605Smrg core_version = 0.0 289848b8605Smrg 290848b8605Smrg if core_version > 0.0: 291848b8605Smrg cat_type = 0 292848b8605Smrg key = name 293848b8605Smrg elif name.startswith("GL_ARB_") or name.startswith("GLX_ARB_") or name.startswith("WGL_ARB_"): 294848b8605Smrg cat_type = 1 295848b8605Smrg key = int(number) 296848b8605Smrg else: 297848b8605Smrg if number != None: 298848b8605Smrg cat_type = 2 299848b8605Smrg key = int(number) 300848b8605Smrg else: 301848b8605Smrg cat_type = 3 302848b8605Smrg key = name 303848b8605Smrg 304848b8605Smrg 305848b8605Smrg return [cat_type, key] 306848b8605Smrg 307848b8605Smrg 308848b8605Smrgdef create_parameter_string(parameters, include_names): 309848b8605Smrg """Create a parameter string from a list of gl_parameters.""" 310848b8605Smrg 311848b8605Smrg list = [] 312848b8605Smrg for p in parameters: 313848b8605Smrg if p.is_padding: 314848b8605Smrg continue 315848b8605Smrg 316848b8605Smrg if include_names: 317848b8605Smrg list.append( p.string() ) 318848b8605Smrg else: 319848b8605Smrg list.append( p.type_string() ) 320848b8605Smrg 321848b8605Smrg if len(list) == 0: list = ["void"] 322848b8605Smrg 323b8e80941Smrg return ", ".join(list) 324848b8605Smrg 325848b8605Smrg 326848b8605Smrgclass gl_item(object): 327848b8605Smrg def __init__(self, element, context, category): 328848b8605Smrg self.context = context 329848b8605Smrg self.name = element.get( "name" ) 330848b8605Smrg self.category = real_category_name( category ) 331848b8605Smrg 332848b8605Smrg return 333848b8605Smrg 334848b8605Smrg 335848b8605Smrgclass gl_type( gl_item ): 336848b8605Smrg def __init__(self, element, context, category): 337848b8605Smrg gl_item.__init__(self, element, context, category) 338848b8605Smrg self.size = int( element.get( "size" ), 0 ) 339848b8605Smrg 340848b8605Smrg te = typeexpr.type_expression( None ) 341848b8605Smrg tn = typeexpr.type_node() 342848b8605Smrg tn.size = int( element.get( "size" ), 0 ) 343848b8605Smrg tn.integer = not is_attr_true( element, "float" ) 344848b8605Smrg tn.unsigned = is_attr_true( element, "unsigned" ) 345848b8605Smrg tn.pointer = is_attr_true( element, "pointer" ) 346848b8605Smrg tn.name = "GL" + self.name 347848b8605Smrg te.set_base_type_node( tn ) 348848b8605Smrg 349848b8605Smrg self.type_expr = te 350848b8605Smrg return 351848b8605Smrg 352848b8605Smrg 353848b8605Smrg def get_type_expression(self): 354848b8605Smrg return self.type_expr 355848b8605Smrg 356848b8605Smrg 357848b8605Smrgclass gl_enum( gl_item ): 358848b8605Smrg def __init__(self, element, context, category): 359848b8605Smrg gl_item.__init__(self, element, context, category) 360848b8605Smrg self.value = int( element.get( "value" ), 0 ) 361848b8605Smrg 362848b8605Smrg temp = element.get( "count" ) 363848b8605Smrg if not temp or temp == "?": 364848b8605Smrg self.default_count = -1 365848b8605Smrg else: 366848b8605Smrg try: 367848b8605Smrg c = int(temp) 368b8e80941Smrg except Exception: 369848b8605Smrg raise RuntimeError('Invalid count value "%s" for enum "%s" in function "%s" when an integer was expected.' % (temp, self.name, n)) 370848b8605Smrg 371848b8605Smrg self.default_count = c 372848b8605Smrg 373848b8605Smrg return 374848b8605Smrg 375848b8605Smrg 376848b8605Smrg def priority(self): 377848b8605Smrg """Calculate a 'priority' for this enum name. 378848b8605Smrg 379848b8605Smrg When an enum is looked up by number, there may be many 380848b8605Smrg possible names, but only one is the 'prefered' name. The 381848b8605Smrg priority is used to select which name is the 'best'. 382848b8605Smrg 383848b8605Smrg Highest precedence is given to core GL name. ARB extension 384848b8605Smrg names have the next highest, followed by EXT extension names. 385848b8605Smrg Vendor extension names are the lowest. 386848b8605Smrg """ 387848b8605Smrg 388848b8605Smrg if self.name.endswith( "_BIT" ): 389848b8605Smrg bias = 1 390848b8605Smrg else: 391848b8605Smrg bias = 0 392848b8605Smrg 393848b8605Smrg if self.category.startswith( "GL_VERSION_" ): 394848b8605Smrg priority = 0 395848b8605Smrg elif self.category.startswith( "GL_ARB_" ): 396848b8605Smrg priority = 2 397848b8605Smrg elif self.category.startswith( "GL_EXT_" ): 398848b8605Smrg priority = 4 399848b8605Smrg else: 400848b8605Smrg priority = 6 401848b8605Smrg 402848b8605Smrg return priority + bias 403848b8605Smrg 404848b8605Smrg 405848b8605Smrg 406848b8605Smrgclass gl_parameter(object): 407848b8605Smrg def __init__(self, element, context): 408848b8605Smrg self.name = element.get( "name" ) 409848b8605Smrg 410848b8605Smrg ts = element.get( "type" ) 411848b8605Smrg self.type_expr = typeexpr.type_expression( ts, context ) 412848b8605Smrg 413848b8605Smrg temp = element.get( "variable_param" ) 414848b8605Smrg if temp: 415848b8605Smrg self.count_parameter_list = temp.split( ' ' ) 416848b8605Smrg else: 417848b8605Smrg self.count_parameter_list = [] 418848b8605Smrg 419848b8605Smrg # The count tag can be either a numeric string or the name of 420848b8605Smrg # a variable. If it is the name of a variable, the int(c) 421848b8605Smrg # statement will throw an exception, and the except block will 422848b8605Smrg # take over. 423848b8605Smrg 424848b8605Smrg c = element.get( "count" ) 425848b8605Smrg try: 426848b8605Smrg count = int(c) 427848b8605Smrg self.count = count 428848b8605Smrg self.counter = None 429b8e80941Smrg except Exception: 430848b8605Smrg count = 1 431848b8605Smrg self.count = 0 432848b8605Smrg self.counter = c 433848b8605Smrg 434848b8605Smrg self.count_scale = int(element.get( "count_scale", "1" )) 435848b8605Smrg 436848b8605Smrg elements = (count * self.count_scale) 437848b8605Smrg if elements == 1: 438848b8605Smrg elements = 0 439848b8605Smrg 440848b8605Smrg #if ts == "GLdouble": 441848b8605Smrg # print '/* stack size -> %s = %u (before)*/' % (self.name, self.type_expr.get_stack_size()) 442848b8605Smrg # print '/* # elements = %u */' % (elements) 443848b8605Smrg self.type_expr.set_elements( elements ) 444848b8605Smrg #if ts == "GLdouble": 445848b8605Smrg # print '/* stack size -> %s = %u (after) */' % (self.name, self.type_expr.get_stack_size()) 446848b8605Smrg 447848b8605Smrg self.is_client_only = is_attr_true( element, 'client_only' ) 448848b8605Smrg self.is_counter = is_attr_true( element, 'counter' ) 449848b8605Smrg self.is_output = is_attr_true( element, 'output' ) 450848b8605Smrg 451848b8605Smrg 452848b8605Smrg # Pixel data has special parameters. 453848b8605Smrg 454848b8605Smrg self.width = element.get('img_width') 455848b8605Smrg self.height = element.get('img_height') 456848b8605Smrg self.depth = element.get('img_depth') 457848b8605Smrg self.extent = element.get('img_extent') 458848b8605Smrg 459848b8605Smrg self.img_xoff = element.get('img_xoff') 460848b8605Smrg self.img_yoff = element.get('img_yoff') 461848b8605Smrg self.img_zoff = element.get('img_zoff') 462848b8605Smrg self.img_woff = element.get('img_woff') 463848b8605Smrg 464848b8605Smrg self.img_format = element.get('img_format') 465848b8605Smrg self.img_type = element.get('img_type') 466848b8605Smrg self.img_target = element.get('img_target') 467848b8605Smrg 468848b8605Smrg self.img_pad_dimensions = is_attr_true( element, 'img_pad_dimensions' ) 469848b8605Smrg self.img_null_flag = is_attr_true( element, 'img_null_flag' ) 470848b8605Smrg self.img_send_null = is_attr_true( element, 'img_send_null' ) 471848b8605Smrg 472848b8605Smrg self.is_padding = is_attr_true( element, 'padding' ) 473848b8605Smrg return 474848b8605Smrg 475848b8605Smrg 476848b8605Smrg def compatible(self, other): 477848b8605Smrg return 1 478848b8605Smrg 479848b8605Smrg 480848b8605Smrg def is_array(self): 481848b8605Smrg return self.is_pointer() 482848b8605Smrg 483848b8605Smrg 484848b8605Smrg def is_pointer(self): 485848b8605Smrg return self.type_expr.is_pointer() 486848b8605Smrg 487848b8605Smrg 488848b8605Smrg def is_image(self): 489848b8605Smrg if self.width: 490848b8605Smrg return 1 491848b8605Smrg else: 492848b8605Smrg return 0 493848b8605Smrg 494848b8605Smrg 495848b8605Smrg def is_variable_length(self): 496848b8605Smrg return len(self.count_parameter_list) or self.counter 497848b8605Smrg 498848b8605Smrg 499848b8605Smrg def is_64_bit(self): 500848b8605Smrg count = self.type_expr.get_element_count() 501848b8605Smrg if count: 502848b8605Smrg if (self.size() / count) == 8: 503848b8605Smrg return 1 504848b8605Smrg else: 505848b8605Smrg if self.size() == 8: 506848b8605Smrg return 1 507848b8605Smrg 508848b8605Smrg return 0 509848b8605Smrg 510848b8605Smrg 511848b8605Smrg def string(self): 512848b8605Smrg return self.type_expr.original_string + " " + self.name 513848b8605Smrg 514848b8605Smrg 515848b8605Smrg def type_string(self): 516848b8605Smrg return self.type_expr.original_string 517848b8605Smrg 518848b8605Smrg 519848b8605Smrg def get_base_type_string(self): 520848b8605Smrg return self.type_expr.get_base_name() 521848b8605Smrg 522848b8605Smrg 523848b8605Smrg def get_dimensions(self): 524848b8605Smrg if not self.width: 525848b8605Smrg return [ 0, "0", "0", "0", "0" ] 526848b8605Smrg 527848b8605Smrg dim = 1 528848b8605Smrg w = self.width 529848b8605Smrg h = "1" 530848b8605Smrg d = "1" 531848b8605Smrg e = "1" 532848b8605Smrg 533848b8605Smrg if self.height: 534848b8605Smrg dim = 2 535848b8605Smrg h = self.height 536848b8605Smrg 537848b8605Smrg if self.depth: 538848b8605Smrg dim = 3 539848b8605Smrg d = self.depth 540848b8605Smrg 541848b8605Smrg if self.extent: 542848b8605Smrg dim = 4 543848b8605Smrg e = self.extent 544848b8605Smrg 545848b8605Smrg return [ dim, w, h, d, e ] 546848b8605Smrg 547848b8605Smrg 548848b8605Smrg def get_stack_size(self): 549848b8605Smrg return self.type_expr.get_stack_size() 550848b8605Smrg 551848b8605Smrg 552848b8605Smrg def size(self): 553848b8605Smrg if self.is_image(): 554848b8605Smrg return 0 555848b8605Smrg else: 556848b8605Smrg return self.type_expr.get_element_size() 557848b8605Smrg 558848b8605Smrg 559848b8605Smrg def get_element_count(self): 560848b8605Smrg c = self.type_expr.get_element_count() 561848b8605Smrg if c == 0: 562848b8605Smrg return 1 563848b8605Smrg 564848b8605Smrg return c 565848b8605Smrg 566848b8605Smrg 567848b8605Smrg def size_string(self, use_parens = 1): 568848b8605Smrg s = self.size() 569848b8605Smrg if self.counter or self.count_parameter_list: 570848b8605Smrg list = [ "compsize" ] 571848b8605Smrg 572848b8605Smrg if self.counter and self.count_parameter_list: 573848b8605Smrg list.append( self.counter ) 574848b8605Smrg elif self.counter: 575848b8605Smrg list = [ self.counter ] 576848b8605Smrg 577848b8605Smrg if s > 1: 578848b8605Smrg list.append( str(s) ) 579848b8605Smrg 580848b8605Smrg if len(list) > 1 and use_parens : 581b8e80941Smrg return "safe_mul(%s)" % ", ".join(list) 582848b8605Smrg else: 583b8e80941Smrg return " * ".join(list) 584848b8605Smrg 585848b8605Smrg elif self.is_image(): 586848b8605Smrg return "compsize" 587848b8605Smrg else: 588848b8605Smrg return str(s) 589848b8605Smrg 590848b8605Smrg 591848b8605Smrg def format_string(self): 592848b8605Smrg if self.type_expr.original_string == "GLenum": 593848b8605Smrg return "0x%x" 594848b8605Smrg else: 595848b8605Smrg return self.type_expr.format_string() 596848b8605Smrg 597848b8605Smrg 598848b8605Smrgclass gl_function( gl_item ): 599848b8605Smrg def __init__(self, element, context): 600848b8605Smrg self.context = context 601848b8605Smrg self.name = None 602848b8605Smrg 603848b8605Smrg self.entry_points = [] 604848b8605Smrg self.return_type = "void" 605848b8605Smrg self.parameters = [] 606848b8605Smrg self.offset = -1 607848b8605Smrg self.initialized = 0 608848b8605Smrg self.images = [] 609848b8605Smrg self.exec_flavor = 'mesa' 610848b8605Smrg self.desktop = True 611848b8605Smrg self.deprecated = None 612b8e80941Smrg self.has_no_error_variant = False 613848b8605Smrg 614848b8605Smrg # self.api_map[api] is a decimal value indicating the earliest 615848b8605Smrg # version of the given API in which ANY alias for the function 616848b8605Smrg # exists. The map only lists APIs which contain the function 617848b8605Smrg # in at least one version. For example, for the ClipPlanex 618b8e80941Smrg # function, self.api_map == { 'es1': 619848b8605Smrg # Decimal('1.1') }. 620848b8605Smrg self.api_map = {} 621848b8605Smrg 622b8e80941Smrg self.assign_offset = False 623848b8605Smrg 624848b8605Smrg self.static_entry_points = [] 625848b8605Smrg 626848b8605Smrg # Track the parameter string (for the function prototype) 627848b8605Smrg # for each entry-point. This is done because some functions 628848b8605Smrg # change their prototype slightly when promoted from extension 629848b8605Smrg # to ARB extension to core. glTexImage3DEXT and glTexImage3D 630848b8605Smrg # are good examples of this. Scripts that need to generate 631848b8605Smrg # code for these differing aliases need to real prototype 632848b8605Smrg # for each entry-point. Otherwise, they may generate code 633848b8605Smrg # that won't compile. 634848b8605Smrg 635848b8605Smrg self.entry_point_parameters = {} 636848b8605Smrg 637848b8605Smrg self.process_element( element ) 638848b8605Smrg 639848b8605Smrg return 640848b8605Smrg 641848b8605Smrg 642848b8605Smrg def process_element(self, element): 643848b8605Smrg name = element.get( "name" ) 644848b8605Smrg alias = element.get( "alias" ) 645848b8605Smrg 646b8e80941Smrg if name in static_data.functions: 647848b8605Smrg self.static_entry_points.append(name) 648848b8605Smrg 649848b8605Smrg self.entry_points.append( name ) 650848b8605Smrg 651848b8605Smrg for api in ('es1', 'es2'): 652848b8605Smrg version_str = element.get(api, 'none') 653848b8605Smrg assert version_str is not None 654848b8605Smrg if version_str != 'none': 655848b8605Smrg version_decimal = Decimal(version_str) 656848b8605Smrg if api not in self.api_map or \ 657848b8605Smrg version_decimal < self.api_map[api]: 658848b8605Smrg self.api_map[api] = version_decimal 659848b8605Smrg 660848b8605Smrg exec_flavor = element.get('exec') 661848b8605Smrg if exec_flavor: 662848b8605Smrg self.exec_flavor = exec_flavor 663848b8605Smrg 664848b8605Smrg deprecated = element.get('deprecated', 'none') 665848b8605Smrg if deprecated != 'none': 666848b8605Smrg self.deprecated = Decimal(deprecated) 667848b8605Smrg 668848b8605Smrg if not is_attr_true(element, 'desktop', 'true'): 669848b8605Smrg self.desktop = False 670848b8605Smrg 671b8e80941Smrg if self.has_no_error_variant or is_attr_true(element, 'no_error'): 672b8e80941Smrg self.has_no_error_variant = True 673b8e80941Smrg else: 674b8e80941Smrg self.has_no_error_variant = False 675b8e80941Smrg 676848b8605Smrg if alias: 677848b8605Smrg true_name = alias 678848b8605Smrg else: 679848b8605Smrg true_name = name 680848b8605Smrg 681848b8605Smrg # Only try to set the offset when a non-alias entry-point 682848b8605Smrg # is being processed. 683848b8605Smrg 684b8e80941Smrg if name in static_data.offsets and static_data.offsets[name] <= static_data.MAX_OFFSETS: 685b8e80941Smrg self.offset = static_data.offsets[name] 686b8e80941Smrg elif name in static_data.offsets and static_data.offsets[name] > static_data.MAX_OFFSETS: 687b8e80941Smrg self.offset = static_data.offsets[name] 688b8e80941Smrg self.assign_offset = True 689b8e80941Smrg else: 690b8e80941Smrg if self.exec_flavor != "skip": 691b8e80941Smrg raise RuntimeError("Entry-point %s is missing offset in static_data.py. Add one at the bottom of the list." % (name)) 692b8e80941Smrg self.assign_offset = self.exec_flavor != "skip" or name in static_data.unused_functions 693848b8605Smrg 694848b8605Smrg if not self.name: 695848b8605Smrg self.name = true_name 696848b8605Smrg elif self.name != true_name: 697848b8605Smrg raise RuntimeError("Function true name redefined. Was %s, now %s." % (self.name, true_name)) 698848b8605Smrg 699848b8605Smrg 700848b8605Smrg # There are two possible cases. The first time an entry-point 701848b8605Smrg # with data is seen, self.initialized will be 0. On that 702848b8605Smrg # pass, we just fill in the data. The next time an 703848b8605Smrg # entry-point with data is seen, self.initialized will be 1. 704848b8605Smrg # On that pass we have to make that the new values match the 705848b8605Smrg # valuse from the previous entry-point. 706848b8605Smrg 707848b8605Smrg parameters = [] 708848b8605Smrg return_type = "void" 709848b8605Smrg for child in element.getchildren(): 710848b8605Smrg if child.tag == "return": 711848b8605Smrg return_type = child.get( "type", "void" ) 712848b8605Smrg elif child.tag == "param": 713848b8605Smrg param = self.context.factory.create_parameter(child, self.context) 714848b8605Smrg parameters.append( param ) 715848b8605Smrg 716848b8605Smrg 717848b8605Smrg if self.initialized: 718848b8605Smrg if self.return_type != return_type: 719848b8605Smrg raise RuntimeError( "Return type changed in %s. Was %s, now %s." % (name, self.return_type, return_type)) 720848b8605Smrg 721848b8605Smrg if len(parameters) != len(self.parameters): 722848b8605Smrg raise RuntimeError( "Parameter count mismatch in %s. Was %d, now %d." % (name, len(self.parameters), len(parameters))) 723848b8605Smrg 724848b8605Smrg for j in range(0, len(parameters)): 725848b8605Smrg p1 = parameters[j] 726848b8605Smrg p2 = self.parameters[j] 727848b8605Smrg if not p1.compatible( p2 ): 728848b8605Smrg raise RuntimeError( 'Parameter type mismatch in %s. "%s" was "%s", now "%s".' % (name, p2.name, p2.type_expr.original_string, p1.type_expr.original_string)) 729848b8605Smrg 730848b8605Smrg 731848b8605Smrg if true_name == name or not self.initialized: 732848b8605Smrg self.return_type = return_type 733848b8605Smrg self.parameters = parameters 734848b8605Smrg 735848b8605Smrg for param in self.parameters: 736848b8605Smrg if param.is_image(): 737848b8605Smrg self.images.append( param ) 738848b8605Smrg 739848b8605Smrg if element.getchildren(): 740848b8605Smrg self.initialized = 1 741848b8605Smrg self.entry_point_parameters[name] = parameters 742848b8605Smrg else: 743848b8605Smrg self.entry_point_parameters[name] = [] 744848b8605Smrg 745848b8605Smrg return 746848b8605Smrg 747848b8605Smrg def filter_entry_points(self, entry_point_list): 748848b8605Smrg """Filter out entry points not in entry_point_list.""" 749848b8605Smrg if not self.initialized: 750848b8605Smrg raise RuntimeError('%s is not initialized yet' % self.name) 751848b8605Smrg 752848b8605Smrg entry_points = [] 753848b8605Smrg for ent in self.entry_points: 754848b8605Smrg if ent not in entry_point_list: 755848b8605Smrg if ent in self.static_entry_points: 756848b8605Smrg self.static_entry_points.remove(ent) 757848b8605Smrg self.entry_point_parameters.pop(ent) 758848b8605Smrg else: 759848b8605Smrg entry_points.append(ent) 760848b8605Smrg 761848b8605Smrg if not entry_points: 762848b8605Smrg raise RuntimeError('%s has no entry point after filtering' % self.name) 763848b8605Smrg 764848b8605Smrg self.entry_points = entry_points 765848b8605Smrg if self.name not in entry_points: 766848b8605Smrg # use the first remaining entry point 767848b8605Smrg self.name = entry_points[0] 768848b8605Smrg self.parameters = self.entry_point_parameters[entry_points[0]] 769848b8605Smrg 770848b8605Smrg def get_images(self): 771848b8605Smrg """Return potentially empty list of input images.""" 772848b8605Smrg return self.images 773848b8605Smrg 774848b8605Smrg 775848b8605Smrg def parameterIterator(self, name = None): 776848b8605Smrg if name is not None: 777b8e80941Smrg return iter(self.entry_point_parameters[name]); 778848b8605Smrg else: 779b8e80941Smrg return iter(self.parameters); 780848b8605Smrg 781848b8605Smrg 782848b8605Smrg def get_parameter_string(self, entrypoint = None): 783848b8605Smrg if entrypoint: 784848b8605Smrg params = self.entry_point_parameters[ entrypoint ] 785848b8605Smrg else: 786848b8605Smrg params = self.parameters 787848b8605Smrg 788848b8605Smrg return create_parameter_string( params, 1 ) 789848b8605Smrg 790848b8605Smrg def get_called_parameter_string(self): 791848b8605Smrg p_string = "" 792848b8605Smrg comma = "" 793848b8605Smrg 794848b8605Smrg for p in self.parameterIterator(): 795848b8605Smrg if p.is_padding: 796848b8605Smrg continue 797848b8605Smrg p_string = p_string + comma + p.name 798848b8605Smrg comma = ", " 799848b8605Smrg 800848b8605Smrg return p_string 801848b8605Smrg 802848b8605Smrg 803848b8605Smrg def is_abi(self): 804848b8605Smrg return (self.offset >= 0 and not self.assign_offset) 805848b8605Smrg 806848b8605Smrg def is_static_entry_point(self, name): 807848b8605Smrg return name in self.static_entry_points 808848b8605Smrg 809848b8605Smrg def dispatch_name(self): 810848b8605Smrg if self.name in self.static_entry_points: 811848b8605Smrg return self.name 812848b8605Smrg else: 813848b8605Smrg return "_dispatch_stub_%u" % (self.offset) 814848b8605Smrg 815848b8605Smrg def static_name(self, name): 816848b8605Smrg if name in self.static_entry_points: 817848b8605Smrg return name 818848b8605Smrg else: 819848b8605Smrg return "_dispatch_stub_%u" % (self.offset) 820848b8605Smrg 821848b8605Smrgclass gl_item_factory(object): 822848b8605Smrg """Factory to create objects derived from gl_item.""" 823848b8605Smrg 824848b8605Smrg def create_function(self, element, context): 825848b8605Smrg return gl_function(element, context) 826848b8605Smrg 827848b8605Smrg def create_type(self, element, context, category): 828848b8605Smrg return gl_type(element, context, category) 829848b8605Smrg 830848b8605Smrg def create_enum(self, element, context, category): 831848b8605Smrg return gl_enum(element, context, category) 832848b8605Smrg 833848b8605Smrg def create_parameter(self, element, context): 834848b8605Smrg return gl_parameter(element, context) 835848b8605Smrg 836848b8605Smrg def create_api(self): 837848b8605Smrg return gl_api(self) 838848b8605Smrg 839848b8605Smrg 840848b8605Smrgclass gl_api(object): 841848b8605Smrg def __init__(self, factory): 842b8e80941Smrg self.functions_by_name = OrderedDict() 843848b8605Smrg self.enums_by_name = {} 844848b8605Smrg self.types_by_name = {} 845848b8605Smrg 846848b8605Smrg self.category_dict = {} 847848b8605Smrg self.categories = [{}, {}, {}, {}] 848848b8605Smrg 849848b8605Smrg self.factory = factory 850848b8605Smrg 851848b8605Smrg self.next_offset = 0 852848b8605Smrg 853848b8605Smrg typeexpr.create_initial_types() 854848b8605Smrg return 855848b8605Smrg 856848b8605Smrg def parse_file(self, file_name): 857848b8605Smrg doc = ET.parse( file_name ) 858848b8605Smrg self.process_element(file_name, doc) 859848b8605Smrg 860848b8605Smrg 861848b8605Smrg def process_element(self, file_name, doc): 862848b8605Smrg element = doc.getroot() 863848b8605Smrg if element.tag == "OpenGLAPI": 864848b8605Smrg self.process_OpenGLAPI(file_name, element) 865848b8605Smrg return 866848b8605Smrg 867848b8605Smrg 868848b8605Smrg def process_OpenGLAPI(self, file_name, element): 869848b8605Smrg for child in element.getchildren(): 870848b8605Smrg if child.tag == "category": 871848b8605Smrg self.process_category( child ) 872848b8605Smrg elif child.tag == "OpenGLAPI": 873848b8605Smrg self.process_OpenGLAPI( file_name, child ) 874848b8605Smrg elif child.tag == '{http://www.w3.org/2001/XInclude}include': 875848b8605Smrg href = child.get('href') 876848b8605Smrg href = os.path.join(os.path.dirname(file_name), href) 877848b8605Smrg self.parse_file(href) 878848b8605Smrg 879848b8605Smrg return 880848b8605Smrg 881848b8605Smrg 882848b8605Smrg def process_category(self, cat): 883848b8605Smrg cat_name = cat.get( "name" ) 884848b8605Smrg cat_number = cat.get( "number" ) 885848b8605Smrg 886848b8605Smrg [cat_type, key] = classify_category(cat_name, cat_number) 887848b8605Smrg self.categories[cat_type][key] = [cat_name, cat_number] 888848b8605Smrg 889848b8605Smrg for child in cat.getchildren(): 890848b8605Smrg if child.tag == "function": 891848b8605Smrg func_name = real_function_name( child ) 892848b8605Smrg 893848b8605Smrg temp_name = child.get( "name" ) 894848b8605Smrg self.category_dict[ temp_name ] = [cat_name, cat_number] 895848b8605Smrg 896b8e80941Smrg if func_name in self.functions_by_name: 897848b8605Smrg func = self.functions_by_name[ func_name ] 898848b8605Smrg func.process_element( child ) 899848b8605Smrg else: 900848b8605Smrg func = self.factory.create_function( child, self ) 901848b8605Smrg self.functions_by_name[ func_name ] = func 902848b8605Smrg 903848b8605Smrg if func.offset >= self.next_offset: 904848b8605Smrg self.next_offset = func.offset + 1 905848b8605Smrg 906848b8605Smrg 907848b8605Smrg elif child.tag == "enum": 908848b8605Smrg enum = self.factory.create_enum( child, self, cat_name ) 909848b8605Smrg self.enums_by_name[ enum.name ] = enum 910848b8605Smrg elif child.tag == "type": 911848b8605Smrg t = self.factory.create_type( child, self, cat_name ) 912848b8605Smrg self.types_by_name[ "GL" + t.name ] = t 913848b8605Smrg 914848b8605Smrg return 915848b8605Smrg 916848b8605Smrg 917848b8605Smrg def functionIterateByCategory(self, cat = None): 918848b8605Smrg """Iterate over functions by category. 919848b8605Smrg 920848b8605Smrg If cat is None, all known functions are iterated in category 921848b8605Smrg order. See classify_category for details of the ordering. 922848b8605Smrg Within a category, functions are sorted by name. If cat is 923848b8605Smrg not None, then only functions in that category are iterated. 924848b8605Smrg """ 925848b8605Smrg lists = [{}, {}, {}, {}] 926848b8605Smrg 927848b8605Smrg for func in self.functionIterateAll(): 928848b8605Smrg [cat_name, cat_number] = self.category_dict[func.name] 929848b8605Smrg 930848b8605Smrg if (cat == None) or (cat == cat_name): 931848b8605Smrg [func_cat_type, key] = classify_category(cat_name, cat_number) 932848b8605Smrg 933b8e80941Smrg if key not in lists[func_cat_type]: 934848b8605Smrg lists[func_cat_type][key] = {} 935848b8605Smrg 936848b8605Smrg lists[func_cat_type][key][func.name] = func 937848b8605Smrg 938848b8605Smrg 939848b8605Smrg functions = [] 940848b8605Smrg for func_cat_type in range(0,4): 941b8e80941Smrg keys = sorted(lists[func_cat_type].keys()) 942848b8605Smrg 943848b8605Smrg for key in keys: 944b8e80941Smrg names = sorted(lists[func_cat_type][key].keys()) 945848b8605Smrg 946848b8605Smrg for name in names: 947848b8605Smrg functions.append(lists[func_cat_type][key][name]) 948848b8605Smrg 949b8e80941Smrg return iter(functions) 950848b8605Smrg 951848b8605Smrg 952848b8605Smrg def functionIterateByOffset(self): 953848b8605Smrg max_offset = -1 954b8e80941Smrg for func in self.functions_by_name.values(): 955848b8605Smrg if func.offset > max_offset: 956848b8605Smrg max_offset = func.offset 957848b8605Smrg 958848b8605Smrg 959848b8605Smrg temp = [None for i in range(0, max_offset + 1)] 960b8e80941Smrg for func in self.functions_by_name.values(): 961848b8605Smrg if func.offset != -1: 962848b8605Smrg temp[ func.offset ] = func 963848b8605Smrg 964848b8605Smrg 965848b8605Smrg list = [] 966848b8605Smrg for i in range(0, max_offset + 1): 967848b8605Smrg if temp[i]: 968848b8605Smrg list.append(temp[i]) 969848b8605Smrg 970b8e80941Smrg return iter(list); 971848b8605Smrg 972848b8605Smrg 973848b8605Smrg def functionIterateAll(self): 974b8e80941Smrg return self.functions_by_name.values() 975848b8605Smrg 976848b8605Smrg 977848b8605Smrg def enumIterateByName(self): 978b8e80941Smrg keys = sorted(self.enums_by_name.keys()) 979848b8605Smrg 980848b8605Smrg list = [] 981848b8605Smrg for enum in keys: 982848b8605Smrg list.append( self.enums_by_name[ enum ] ) 983848b8605Smrg 984b8e80941Smrg return iter(list) 985848b8605Smrg 986848b8605Smrg 987848b8605Smrg def categoryIterate(self): 988848b8605Smrg """Iterate over categories. 989848b8605Smrg 990848b8605Smrg Iterate over all known categories in the order specified by 991848b8605Smrg classify_category. Each iterated value is a tuple of the 992848b8605Smrg name and number (which may be None) of the category. 993848b8605Smrg """ 994848b8605Smrg 995848b8605Smrg list = [] 996848b8605Smrg for cat_type in range(0,4): 997b8e80941Smrg keys = sorted(self.categories[cat_type].keys()) 998848b8605Smrg 999848b8605Smrg for key in keys: 1000848b8605Smrg list.append(self.categories[cat_type][key]) 1001848b8605Smrg 1002b8e80941Smrg return iter(list) 1003848b8605Smrg 1004848b8605Smrg 1005848b8605Smrg def get_category_for_name( self, name ): 1006b8e80941Smrg if name in self.category_dict: 1007848b8605Smrg return self.category_dict[name] 1008848b8605Smrg else: 1009848b8605Smrg return ["<unknown category>", None] 1010848b8605Smrg 1011848b8605Smrg 1012848b8605Smrg def typeIterate(self): 1013b8e80941Smrg return self.types_by_name.values() 1014848b8605Smrg 1015848b8605Smrg 1016848b8605Smrg def find_type( self, type_name ): 1017848b8605Smrg if type_name in self.types_by_name: 1018848b8605Smrg return self.types_by_name[ type_name ].type_expr 1019848b8605Smrg else: 1020b8e80941Smrg print("Unable to find base type matching \"%s\"." % (type_name)) 1021848b8605Smrg return None 1022