1 2# (C) Copyright IBM Corporation 2004, 2005 3# All Rights Reserved. 4# 5# Permission is hereby granted, free of charge, to any person obtaining a 6# copy of this software and associated documentation files (the "Software"), 7# to deal in the Software without restriction, including without limitation 8# on the rights to use, copy, modify, merge, publish, distribute, sub 9# license, and/or sell copies of the Software, and to permit persons to whom 10# the Software is furnished to do so, subject to the following conditions: 11# 12# The above copyright notice and this permission notice (including the next 13# paragraph) shall be included in all copies or substantial portions of the 14# Software. 15# 16# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 19# IBM AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 22# IN THE SOFTWARE. 23# 24# Authors: 25# Ian Romanick <[email protected]> 26 27from collections import OrderedDict 28from decimal import Decimal 29import xml.etree.ElementTree as ET 30import re, sys 31import os.path 32import typeexpr 33import static_data 34 35 36def parse_GL_API(file_name, factory=None, pointer_size=0): 37 38 if not factory: 39 factory = gl_item_factory() 40 41 api = factory.create_api(pointer_size) 42 api.parse_file(file_name) 43 44 # After the XML has been processed, we need to go back and assign 45 # dispatch offsets to the functions that request that their offsets 46 # be assigned by the scripts. Typically this means all functions 47 # that are not part of the ABI. 48 49 for func in api.functionIterateByCategory(): 50 if func.assign_offset and func.offset < 0: 51 func.offset = api.next_offset; 52 api.next_offset += 1 53 54 return api 55 56 57def is_attr_true( element, name, default = "false" ): 58 """Read a name value from an element's attributes. 59 60 The value read from the attribute list must be either 'true' or 61 'false'. If the value is 'false', zero will be returned. If the 62 value is 'true', non-zero will be returned. An exception will be 63 raised for any other value.""" 64 65 value = element.get( name, default ) 66 if value == "true": 67 return 1 68 elif value == "false": 69 return 0 70 else: 71 raise RuntimeError('Invalid value "%s" for boolean "%s".' % (value, name)) 72 73 74class gl_print_base(object): 75 """Base class of all API pretty-printers. 76 77 In the model-view-controller pattern, this is the view. Any derived 78 class will want to over-ride the printBody, printRealHader, and 79 printRealFooter methods. Some derived classes may want to over-ride 80 printHeader and printFooter, or even Print (though this is unlikely). 81 """ 82 83 def __init__(self): 84 # Name of the script that is generating the output file. 85 # Every derived class should set this to the name of its 86 # source file. 87 88 self.name = "a" 89 90 91 # License on the *generated* source file. This may differ 92 # from the license on the script that is generating the file. 93 # Every derived class should set this to some reasonable 94 # value. 95 # 96 # See license.py for an example of a reasonable value. 97 98 self.license = "The license for this file is unspecified." 99 100 101 # The header_tag is the name of the C preprocessor define 102 # used to prevent multiple inclusion. Typically only 103 # generated C header files need this to be set. Setting it 104 # causes code to be generated automatically in printHeader 105 # and printFooter. 106 107 self.header_tag = None 108 109 110 # List of file-private defines that must be undefined at the 111 # end of the file. This can be used in header files to define 112 # names for use in the file, then undefine them at the end of 113 # the header file. 114 115 self.undef_list = [] 116 return 117 118 119 def Print(self, api): 120 self.printHeader() 121 self.printBody(api) 122 self.printFooter() 123 return 124 125 126 def printHeader(self): 127 """Print the header associated with all files and call the printRealHeader method.""" 128 129 print('/* DO NOT EDIT - This file generated automatically by %s script */' \ 130 % (self.name)) 131 print('') 132 print('/*') 133 print((' * ' + self.license.replace('\n', '\n * ')).replace(' \n', '\n')) 134 print(' */') 135 print('') 136 if self.header_tag: 137 print('#if !defined( %s )' % (self.header_tag)) 138 print('# define %s' % (self.header_tag)) 139 print('') 140 self.printRealHeader(); 141 return 142 143 144 def printFooter(self): 145 """Print the header associated with all files and call the printRealFooter method.""" 146 147 self.printRealFooter() 148 149 if self.undef_list: 150 print('') 151 for u in self.undef_list: 152 print("# undef %s" % (u)) 153 154 if self.header_tag: 155 print('') 156 print('#endif /* !defined( %s ) */' % (self.header_tag)) 157 158 159 def printRealHeader(self): 160 """Print the "real" header for the created file. 161 162 In the base class, this function is empty. All derived 163 classes should over-ride this function.""" 164 return 165 166 167 def printRealFooter(self): 168 """Print the "real" footer for the created file. 169 170 In the base class, this function is empty. All derived 171 classes should over-ride this function.""" 172 return 173 174 175 def printPure(self): 176 """Conditionally define `PURE' function attribute. 177 178 Conditionally defines a preprocessor macro `PURE' that wraps 179 GCC's `pure' function attribute. The conditional code can be 180 easilly adapted to other compilers that support a similar 181 feature. 182 183 The name is also added to the file's undef_list. 184 """ 185 self.undef_list.append("PURE") 186 print("""# if defined(__GNUC__) || (defined(__SUNPRO_C) && (__SUNPRO_C >= 0x590)) 187# define PURE __attribute__((pure)) 188# else 189# define PURE 190# endif""") 191 return 192 193 194 def printFastcall(self): 195 """Conditionally define `FASTCALL' function attribute. 196 197 Conditionally defines a preprocessor macro `FASTCALL' that 198 wraps GCC's `fastcall' function attribute. The conditional 199 code can be easilly adapted to other compilers that support a 200 similar feature. 201 202 The name is also added to the file's undef_list. 203 """ 204 205 self.undef_list.append("FASTCALL") 206 print("""# if defined(__i386__) && defined(__GNUC__) && !defined(__CYGWIN__) && !defined(__MINGW32__) 207# define FASTCALL __attribute__((fastcall)) 208# else 209# define FASTCALL 210# endif""") 211 return 212 213 214 def printVisibility(self, S, s): 215 """Conditionally define visibility function attribute. 216 217 Conditionally defines a preprocessor macro name S that wraps 218 GCC's visibility function attribute. The visibility used is 219 the parameter s. The conditional code can be easilly adapted 220 to other compilers that support a similar feature. 221 222 The name is also added to the file's undef_list. 223 """ 224 225 self.undef_list.append(S) 226 print("""# if defined(__GNUC__) && !defined(__CYGWIN__) && !defined(__MINGW32__) 227# define %s __attribute__((visibility("%s"))) 228# else 229# define %s 230# endif""" % (S, s, S)) 231 return 232 233 234 def printNoinline(self): 235 """Conditionally define `NOINLINE' function attribute. 236 237 Conditionally defines a preprocessor macro `NOINLINE' that 238 wraps GCC's `noinline' function attribute. The conditional 239 code can be easilly adapted to other compilers that support a 240 similar feature. 241 242 The name is also added to the file's undef_list. 243 """ 244 245 self.undef_list.append("NOINLINE") 246 print("""# if defined(__GNUC__) 247# define NOINLINE __attribute__((noinline)) 248# else 249# define NOINLINE 250# endif""") 251 return 252 253 254def real_function_name(element): 255 name = element.get( "name" ) 256 alias = element.get( "alias" ) 257 258 if alias: 259 return alias 260 else: 261 return name 262 263 264def real_category_name(c): 265 if re.compile("[1-9][0-9]*[.][0-9]+").match(c): 266 return "GL_VERSION_" + c.replace(".", "_") 267 else: 268 return c 269 270 271def classify_category(name, number): 272 """Based on the category name and number, select a numerical class for it. 273 274 Categories are divided into four classes numbered 0 through 3. The 275 classes are: 276 277 0. Core GL versions, sorted by version number. 278 1. ARB extensions, sorted by extension number. 279 2. Non-ARB extensions, sorted by extension number. 280 3. Un-numbered extensions, sorted by extension name. 281 """ 282 283 try: 284 core_version = float(name) 285 except Exception: 286 core_version = 0.0 287 288 if core_version > 0.0: 289 cat_type = 0 290 key = name 291 elif name.startswith("GL_ARB_") or name.startswith("GLX_ARB_") or name.startswith("WGL_ARB_"): 292 cat_type = 1 293 key = int(number) 294 else: 295 if number != None: 296 cat_type = 2 297 key = int(number) 298 else: 299 cat_type = 3 300 key = name 301 302 303 return [cat_type, key] 304 305 306def create_parameter_string(parameters, include_names): 307 """Create a parameter string from a list of gl_parameters.""" 308 309 list = [] 310 for p in parameters: 311 if p.is_padding: 312 continue 313 314 if include_names: 315 list.append( p.string() ) 316 else: 317 list.append( p.type_string() ) 318 319 if len(list) == 0: list = ["void"] 320 321 return ", ".join(list) 322 323 324class gl_item(object): 325 def __init__(self, element, context, category): 326 self.context = context 327 self.name = element.get( "name" ) 328 self.category = real_category_name( category ) 329 330 return 331 332 333class gl_type( gl_item ): 334 def __init__(self, element, context, category): 335 gl_item.__init__(self, element, context, category) 336 self.size = int( element.get( "size" ), 0 ) 337 338 te = typeexpr.type_expression( None ) 339 tn = typeexpr.type_node() 340 tn.size = int( element.get( "size" ), 0 ) 341 tn.integer = not is_attr_true( element, "float" ) 342 tn.unsigned = is_attr_true( element, "unsigned" ) 343 tn.pointer = is_attr_true( element, "pointer" ) 344 tn.name = "GL" + self.name 345 te.set_base_type_node( tn ) 346 347 self.type_expr = te 348 return 349 350 351 def get_type_expression(self): 352 return self.type_expr 353 354 355class gl_enum( gl_item ): 356 def __init__(self, element, context, category): 357 gl_item.__init__(self, element, context, category) 358 self.value = int( element.get( "value" ), 0 ) 359 360 temp = element.get( "count" ) 361 if not temp or temp == "?": 362 self.default_count = -1 363 else: 364 try: 365 c = int(temp) 366 except Exception: 367 raise RuntimeError('Invalid count value "%s" for enum "%s" in function "%s" when an integer was expected.' % (temp, self.name, n)) 368 369 self.default_count = c 370 371 return 372 373 374 def priority(self): 375 """Calculate a 'priority' for this enum name. 376 377 When an enum is looked up by number, there may be many 378 possible names, but only one is the 'prefered' name. The 379 priority is used to select which name is the 'best'. 380 381 Highest precedence is given to core GL name. ARB extension 382 names have the next highest, followed by EXT extension names. 383 Vendor extension names are the lowest. 384 """ 385 386 if self.name.endswith( "_BIT" ): 387 bias = 1 388 else: 389 bias = 0 390 391 if self.category.startswith( "GL_VERSION_" ): 392 priority = 0 393 elif self.category.startswith( "GL_ARB_" ): 394 priority = 2 395 elif self.category.startswith( "GL_EXT_" ): 396 priority = 4 397 else: 398 priority = 6 399 400 return priority + bias 401 402 403 404class gl_parameter(object): 405 def __init__(self, element, context): 406 self.name = element.get( "name" ) 407 408 ts = element.get( "type" ) 409 self.type_expr = typeexpr.type_expression( ts, context ) 410 411 temp = element.get( "variable_param" ) 412 if temp: 413 self.count_parameter_list = temp.split( ' ' ) 414 else: 415 self.count_parameter_list = [] 416 417 # The count tag can be either a numeric string or the name of 418 # a variable. If it is the name of a variable, the int(c) 419 # statement will throw an exception, and the except block will 420 # take over. 421 422 c = element.get( "count" ) 423 try: 424 count = int(c) 425 self.count = count 426 self.counter = None 427 except Exception: 428 count = 1 429 self.count = 0 430 self.counter = c 431 432 self.marshal_count = element.get("marshal_count") 433 self.marshal_large_count = element.get("marshal_large_count") 434 self.count_scale = int(element.get( "count_scale", "1" )) 435 436 elements = (count * self.count_scale) 437 if elements == 1: 438 elements = 0 439 440 #if ts == "GLdouble": 441 # print '/* stack size -> %s = %u (before)*/' % (self.name, self.type_expr.get_stack_size()) 442 # print '/* # elements = %u */' % (elements) 443 self.type_expr.set_elements( elements ) 444 #if ts == "GLdouble": 445 # print '/* stack size -> %s = %u (after) */' % (self.name, self.type_expr.get_stack_size()) 446 447 self.is_client_only = is_attr_true( element, 'client_only' ) 448 self.is_counter = is_attr_true( element, 'counter' ) 449 self.is_output = is_attr_true( element, 'output' ) 450 451 452 # Pixel data has special parameters. 453 454 self.width = element.get('img_width') 455 self.height = element.get('img_height') 456 self.depth = element.get('img_depth') 457 self.extent = element.get('img_extent') 458 459 self.img_xoff = element.get('img_xoff') 460 self.img_yoff = element.get('img_yoff') 461 self.img_zoff = element.get('img_zoff') 462 self.img_woff = element.get('img_woff') 463 464 self.img_format = element.get('img_format') 465 self.img_type = element.get('img_type') 466 self.img_target = element.get('img_target') 467 468 self.img_pad_dimensions = is_attr_true( element, 'img_pad_dimensions' ) 469 self.img_null_flag = is_attr_true( element, 'img_null_flag' ) 470 self.img_send_null = is_attr_true( element, 'img_send_null' ) 471 472 self.is_padding = is_attr_true( element, 'padding' ) 473 return 474 475 476 def compatible(self, other): 477 return 1 478 479 480 def is_array(self): 481 return self.is_pointer() 482 483 484 def is_pointer(self): 485 return self.type_expr.is_pointer() 486 487 488 def is_image(self): 489 if self.width: 490 return 1 491 else: 492 return 0 493 494 495 def is_variable_length(self): 496 return (len(self.count_parameter_list) or self.counter or 497 self.marshal_count or self.marshal_large_count) 498 499 500 def is_64_bit(self): 501 count = self.type_expr.get_element_count() 502 if count: 503 if (self.size() / count) == 8: 504 return 1 505 else: 506 if self.size() == 8: 507 return 1 508 509 return 0 510 511 512 def string(self): 513 if self.type_expr.original_string[-1] == '*': 514 return self.type_expr.original_string + self.name 515 else: 516 return self.type_expr.original_string + " " + self.name 517 518 519 def type_string(self): 520 return self.type_expr.original_string 521 522 523 def get_base_type_string(self): 524 return self.type_expr.get_base_name() 525 526 527 def get_dimensions(self): 528 if not self.width: 529 return [ 0, "0", "0", "0", "0" ] 530 531 dim = 1 532 w = self.width 533 h = "1" 534 d = "1" 535 e = "1" 536 537 if self.height: 538 dim = 2 539 h = self.height 540 541 if self.depth: 542 dim = 3 543 d = self.depth 544 545 if self.extent: 546 dim = 4 547 e = self.extent 548 549 return [ dim, w, h, d, e ] 550 551 552 def get_stack_size(self): 553 return self.type_expr.get_stack_size() 554 555 556 def size(self): 557 if self.is_image(): 558 return 0 559 else: 560 return self.type_expr.get_element_size() 561 562 563 def get_element_count(self): 564 c = self.type_expr.get_element_count() 565 if c == 0: 566 return 1 567 568 return c 569 570 571 def size_string(self, use_parens = 1, marshal = 0): 572 base_size_str = "" 573 574 count = self.get_element_count() 575 if count: 576 base_size_str = "%d * " % count 577 578 base_size_str += "sizeof(%s)" % ( self.get_base_type_string() ) 579 580 if (self.counter or self.count_parameter_list or 581 (marshal and (self.marshal_count or self.marshal_large_count))): 582 list = [ "compsize" ] 583 584 if marshal and self.marshal_count: 585 list = [ self.marshal_count ] 586 elif marshal and self.marshal_large_count: 587 list = [ self.marshal_large_count ] 588 elif self.counter and self.count_parameter_list: 589 list.append( self.counter ) 590 elif self.counter: 591 list = [ self.counter ] 592 593 if self.size() > 1: 594 list.append( base_size_str ) 595 596 # Don't use safe_mul if marshal_count is used, which indicates 597 # a small size. 598 if len(list) > 1 and use_parens and not self.marshal_count: 599 return "safe_mul(%s)" % ", ".join(list) 600 else: 601 return " * ".join(list) 602 603 elif self.is_image(): 604 return "compsize" 605 else: 606 return base_size_str 607 608 609 def format_string(self): 610 if self.type_expr.original_string == "GLenum": 611 return "0x%x" 612 else: 613 return self.type_expr.format_string() 614 615 616class gl_function( gl_item ): 617 def __init__(self, element, context): 618 self.context = context 619 self.name = None 620 621 self.entry_points = [] 622 self.return_type = "void" 623 self.parameters = [] 624 self.offset = -1 625 self.initialized = 0 626 self.images = [] 627 self.exec_flavor = 'mesa' 628 self.has_hw_select_variant = False 629 self.desktop = True 630 self.deprecated = None 631 self.has_no_error_variant = False 632 633 # self.api_map[api] is a decimal value indicating the earliest 634 # version of the given API in which ANY alias for the function 635 # exists. The map only lists APIs which contain the function 636 # in at least one version. For example, for the ClipPlanex 637 # function, self.api_map == { 'es1': 638 # Decimal('1.1') }. 639 self.api_map = {} 640 641 self.assign_offset = False 642 643 self.static_entry_points = [] 644 645 # Track the parameter string (for the function prototype) 646 # for each entry-point. This is done because some functions 647 # change their prototype slightly when promoted from extension 648 # to ARB extension to core. glTexImage3DEXT and glTexImage3D 649 # are good examples of this. Scripts that need to generate 650 # code for these differing aliases need to real prototype 651 # for each entry-point. Otherwise, they may generate code 652 # that won't compile. 653 654 self.entry_point_parameters = {} 655 656 self.process_element( element ) 657 658 return 659 660 661 def process_element(self, element): 662 name = element.get( "name" ) 663 alias = element.get( "alias" ) 664 665 # marshal isn't allowed with alias 666 assert not alias or not element.get('marshal') 667 assert not alias or not element.get('marshal_count') 668 assert not alias or not element.get('marshal_large_count') 669 assert not alias or not element.get('marshal_sync') 670 assert not alias or not element.get('marshal_call_before') 671 assert not alias or not element.get('marshal_call_after') 672 assert not alias or not element.get('deprecated') 673 674 if name in static_data.functions: 675 self.static_entry_points.append(name) 676 677 self.entry_points.append( name ) 678 679 for api in ('es1', 'es2'): 680 version_str = element.get(api, 'none') 681 assert version_str is not None 682 if version_str != 'none': 683 version_decimal = Decimal(version_str) 684 if api not in self.api_map or \ 685 version_decimal < self.api_map[api]: 686 self.api_map[api] = version_decimal 687 688 exec_flavor = element.get('exec') 689 if exec_flavor: 690 self.exec_flavor = exec_flavor 691 692 deprecated = element.get('deprecated', 'none') 693 if deprecated != 'none': 694 self.deprecated = Decimal(deprecated) 695 696 if not is_attr_true(element, 'desktop', 'true'): 697 self.desktop = False 698 699 if self.has_no_error_variant or is_attr_true(element, 'no_error'): 700 self.has_no_error_variant = True 701 else: 702 self.has_no_error_variant = False 703 704 if alias: 705 true_name = alias 706 else: 707 true_name = name 708 709 self.has_hw_select_variant = exec_flavor == 'beginend' and name[0:6] == 'Vertex' 710 711 # Only try to set the offset when a non-alias entry-point 712 # is being processed. 713 714 if name in static_data.offsets and static_data.offsets[name] <= static_data.MAX_OFFSETS: 715 self.offset = static_data.offsets[name] 716 elif name in static_data.offsets and static_data.offsets[name] > static_data.MAX_OFFSETS: 717 self.offset = static_data.offsets[name] 718 self.assign_offset = True 719 else: 720 if self.exec_flavor != "skip": 721 raise RuntimeError("Entry-point %s is missing offset in static_data.py. Add one at the bottom of the list." % (name)) 722 self.assign_offset = False 723 724 if not self.name: 725 self.name = true_name 726 elif self.name != true_name: 727 raise RuntimeError("Function true name redefined. Was %s, now %s." % (self.name, true_name)) 728 729 730 # There are two possible cases. The first time an entry-point 731 # with data is seen, self.initialized will be 0. On that 732 # pass, we just fill in the data. The next time an 733 # entry-point with data is seen, self.initialized will be 1. 734 # On that pass we have to make that the new values match the 735 # valuse from the previous entry-point. 736 737 parameters = [] 738 return_type = "void" 739 for child in element: 740 if child.tag == "return": 741 return_type = child.get( "type", "void" ) 742 elif child.tag == "param": 743 param = self.context.factory.create_parameter(child, self.context) 744 parameters.append( param ) 745 746 747 if self.initialized: 748 if self.return_type != return_type: 749 raise RuntimeError( "Return type changed in %s. Was %s, now %s." % (name, self.return_type, return_type)) 750 751 if len(parameters) != len(self.parameters): 752 raise RuntimeError( "Parameter count mismatch in %s. Was %d, now %d." % (name, len(self.parameters), len(parameters))) 753 754 for j in range(0, len(parameters)): 755 p1 = parameters[j] 756 p2 = self.parameters[j] 757 if not p1.compatible( p2 ): 758 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)) 759 760 761 if true_name == name or not self.initialized: 762 self.return_type = return_type 763 self.parameters = parameters 764 765 for param in self.parameters: 766 if param.is_image(): 767 self.images.append( param ) 768 769 if list(element): 770 self.initialized = 1 771 self.entry_point_parameters[name] = parameters 772 else: 773 self.entry_point_parameters[name] = [] 774 775 return 776 777 def filter_entry_points(self, entry_point_list): 778 """Filter out entry points not in entry_point_list.""" 779 if not self.initialized: 780 raise RuntimeError('%s is not initialized yet' % self.name) 781 782 entry_points = [] 783 for ent in self.entry_points: 784 if ent not in entry_point_list: 785 if ent in self.static_entry_points: 786 self.static_entry_points.remove(ent) 787 self.entry_point_parameters.pop(ent) 788 else: 789 entry_points.append(ent) 790 791 if not entry_points: 792 raise RuntimeError('%s has no entry point after filtering' % self.name) 793 794 self.entry_points = entry_points 795 if self.name not in entry_points: 796 # use the first remaining entry point 797 self.name = entry_points[0] 798 self.parameters = self.entry_point_parameters[entry_points[0]] 799 800 def get_images(self): 801 """Return potentially empty list of input images.""" 802 return self.images 803 804 805 def parameterIterator(self, name = None): 806 if name is not None: 807 return iter(self.entry_point_parameters[name]); 808 else: 809 return iter(self.parameters); 810 811 812 def get_parameter_string(self, entrypoint = None): 813 if entrypoint: 814 params = self.entry_point_parameters[ entrypoint ] 815 else: 816 params = self.parameters 817 818 return create_parameter_string( params, 1 ) 819 820 def get_called_parameter_string(self): 821 p_string = "" 822 comma = "" 823 824 for p in self.parameterIterator(): 825 if p.is_padding: 826 continue 827 p_string = p_string + comma + p.name 828 comma = ", " 829 830 return p_string 831 832 833 def is_abi(self): 834 return (self.offset >= 0 and not self.assign_offset) 835 836 def is_static_entry_point(self, name): 837 return name in self.static_entry_points 838 839 def dispatch_name(self): 840 if self.name in self.static_entry_points: 841 return self.name 842 else: 843 return "_dispatch_stub_%u" % (self.offset) 844 845 def static_name(self, name): 846 if name in self.static_entry_points: 847 return name 848 else: 849 return "_dispatch_stub_%u" % (self.offset) 850 851class gl_item_factory(object): 852 """Factory to create objects derived from gl_item.""" 853 854 def create_function(self, element, context): 855 return gl_function(element, context) 856 857 def create_type(self, element, context, category): 858 return gl_type(element, context, category) 859 860 def create_enum(self, element, context, category): 861 return gl_enum(element, context, category) 862 863 def create_parameter(self, element, context): 864 return gl_parameter(element, context) 865 866 def create_api(self, pointer_size): 867 return gl_api(self, pointer_size) 868 869 870class gl_api(object): 871 def __init__(self, factory, pointer_size): 872 self.functions_by_name = OrderedDict() 873 self.enums_by_name = {} 874 self.types_by_name = {} 875 876 self.category_dict = {} 877 self.categories = [{}, {}, {}, {}] 878 879 self.factory = factory 880 881 self.next_offset = 0 882 self.pointer_size = pointer_size 883 884 typeexpr.create_initial_types() 885 return 886 887 def parse_file(self, file_name): 888 doc = ET.parse( file_name ) 889 self.process_element(file_name, doc) 890 891 892 def process_element(self, file_name, doc): 893 element = doc.getroot() 894 if element.tag == "OpenGLAPI": 895 self.process_OpenGLAPI(file_name, element) 896 return 897 898 899 def process_OpenGLAPI(self, file_name, element): 900 for child in element: 901 if child.tag == "category": 902 self.process_category( child ) 903 elif child.tag == "OpenGLAPI": 904 self.process_OpenGLAPI( file_name, child ) 905 elif child.tag == '{http://www.w3.org/2001/XInclude}include': 906 href = child.get('href') 907 href = os.path.join(os.path.dirname(file_name), href) 908 self.parse_file(href) 909 910 return 911 912 913 def process_category(self, cat): 914 cat_name = cat.get( "name" ) 915 cat_number = cat.get( "number" ) 916 917 [cat_type, key] = classify_category(cat_name, cat_number) 918 self.categories[cat_type][key] = [cat_name, cat_number] 919 920 for child in cat: 921 if child.tag == "function": 922 func_name = real_function_name( child ) 923 924 temp_name = child.get( "name" ) 925 self.category_dict[ temp_name ] = [cat_name, cat_number] 926 927 if func_name in self.functions_by_name: 928 func = self.functions_by_name[ func_name ] 929 func.process_element( child ) 930 else: 931 func = self.factory.create_function( child, self ) 932 self.functions_by_name[ func_name ] = func 933 934 if func.offset >= self.next_offset: 935 self.next_offset = func.offset + 1 936 937 938 elif child.tag == "enum": 939 enum = self.factory.create_enum( child, self, cat_name ) 940 self.enums_by_name[ enum.name ] = enum 941 elif child.tag == "type": 942 t = self.factory.create_type( child, self, cat_name ) 943 self.types_by_name[ "GL" + t.name ] = t 944 945 return 946 947 948 def functionIterateByCategory(self, cat = None): 949 """Iterate over functions by category. 950 951 If cat is None, all known functions are iterated in category 952 order. See classify_category for details of the ordering. 953 Within a category, functions are sorted by name. If cat is 954 not None, then only functions in that category are iterated. 955 """ 956 lists = [{}, {}, {}, {}] 957 958 for func in self.functionIterateAll(): 959 [cat_name, cat_number] = self.category_dict[func.name] 960 961 if (cat == None) or (cat == cat_name): 962 [func_cat_type, key] = classify_category(cat_name, cat_number) 963 964 if key not in lists[func_cat_type]: 965 lists[func_cat_type][key] = {} 966 967 lists[func_cat_type][key][func.name] = func 968 969 970 functions = [] 971 for func_cat_type in range(0,4): 972 keys = sorted(lists[func_cat_type].keys()) 973 974 for key in keys: 975 names = sorted(lists[func_cat_type][key].keys()) 976 977 for name in names: 978 functions.append(lists[func_cat_type][key][name]) 979 980 return iter(functions) 981 982 983 def functionIterateByOffset(self): 984 max_offset = -1 985 for func in self.functions_by_name.values(): 986 if func.offset > max_offset: 987 max_offset = func.offset 988 989 990 temp = [None for i in range(0, max_offset + 1)] 991 for func in self.functions_by_name.values(): 992 if func.offset != -1: 993 temp[ func.offset ] = func 994 995 996 list = [] 997 for i in range(0, max_offset + 1): 998 if temp[i]: 999 list.append(temp[i]) 1000 1001 return iter(list); 1002 1003 1004 def functionIterateAll(self): 1005 return self.functions_by_name.values() 1006 1007 1008 def enumIterateByName(self): 1009 keys = sorted(self.enums_by_name.keys()) 1010 1011 list = [] 1012 for enum in keys: 1013 list.append( self.enums_by_name[ enum ] ) 1014 1015 return iter(list) 1016 1017 1018 def categoryIterate(self): 1019 """Iterate over categories. 1020 1021 Iterate over all known categories in the order specified by 1022 classify_category. Each iterated value is a tuple of the 1023 name and number (which may be None) of the category. 1024 """ 1025 1026 list = [] 1027 for cat_type in range(0,4): 1028 keys = sorted(self.categories[cat_type].keys()) 1029 1030 for key in keys: 1031 list.append(self.categories[cat_type][key]) 1032 1033 return iter(list) 1034 1035 1036 def get_category_for_name( self, name ): 1037 if name in self.category_dict: 1038 return self.category_dict[name] 1039 else: 1040 return ["<unknown category>", None] 1041 1042 1043 def typeIterate(self): 1044 return self.types_by_name.values() 1045 1046 1047 def find_type( self, type_name ): 1048 if type_name in self.types_by_name: 1049 return self.types_by_name[ type_name ].type_expr 1050 else: 1051 print("Unable to find base type matching \"%s\"." % (type_name)) 1052 return None 1053