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 <idr@us.ibm.com> 26 27import argparse 28import sys, string 29 30import gl_XML, glX_XML 31import license 32 33 34class glx_enum_function(object): 35 def __init__(self, func_name, enum_dict): 36 self.name = func_name 37 self.mode = 1 38 self.sig = None 39 40 # "enums" is a set of lists. The element in the set is the 41 # value of the enum. The list is the list of names for that 42 # value. For example, [0x8126] = {"POINT_SIZE_MIN", 43 # "POINT_SIZE_MIN_ARB", "POINT_SIZE_MIN_EXT", 44 # "POINT_SIZE_MIN_SGIS"}. 45 46 self.enums = {} 47 48 # "count" is indexed by count values. Each element of count 49 # is a list of index to "enums" that have that number of 50 # associated data elements. For example, [4] = 51 # {GL_AMBIENT, GL_DIFFUSE, GL_SPECULAR, GL_EMISSION, 52 # GL_AMBIENT_AND_DIFFUSE} (the enum names are used here, 53 # but the actual hexadecimal values would be in the array). 54 55 self.count = {} 56 57 58 # Fill self.count and self.enums using the dictionary of enums 59 # that was passed in. The generic Get functions (e.g., 60 # GetBooleanv and friends) are handled specially here. In 61 # the data the generic Get functions are referred to as "Get". 62 63 if func_name in ["GetIntegerv", "GetBooleanv", "GetFloatv", "GetDoublev"]: 64 match_name = "Get" 65 else: 66 match_name = func_name 67 68 mode_set = 0 69 for enum_name in enum_dict: 70 e = enum_dict[ enum_name ] 71 72 if match_name in e.functions: 73 [count, mode] = e.functions[ match_name ] 74 75 if mode_set and mode != self.mode: 76 raise RuntimeError("Not all enums for %s have the same mode." % (func_name)) 77 78 self.mode = mode 79 80 if e.value in self.enums: 81 if e.name not in self.enums[ e.value ]: 82 self.enums[ e.value ].append( e ) 83 else: 84 if count not in self.count: 85 self.count[ count ] = [] 86 87 self.enums[ e.value ] = [ e ] 88 self.count[ count ].append( e.value ) 89 90 91 return 92 93 94 def signature( self ): 95 if self.sig == None: 96 self.sig = "" 97 for i in self.count: 98 if i == None: 99 raise RuntimeError("i is None. WTF?") 100 101 self.count[i].sort() 102 for e in self.count[i]: 103 self.sig += "%04x,%d," % (e, i) 104 105 return self.sig 106 107 108 def is_set( self ): 109 return self.mode 110 111 112 def PrintUsingTable(self): 113 """Emit the body of the __gl*_size function using a pair 114 of look-up tables and a mask. The mask is calculated such 115 that (e & mask) is unique for all the valid values of e for 116 this function. The result of (e & mask) is used as an index 117 into the first look-up table. If it matches e, then the 118 same entry of the second table is returned. Otherwise zero 119 is returned. 120 121 It seems like this should cause better code to be generated. 122 However, on x86 at least, the resulting .o file is about 20% 123 larger then the switch-statment version. I am leaving this 124 code in because the results may be different on other 125 platforms (e.g., PowerPC or x86-64).""" 126 127 return 0 128 count = 0 129 for a in self.enums: 130 count += 1 131 132 if -1 in self.count: 133 return 0 134 135 # Determine if there is some mask M, such that M = (2^N) - 1, 136 # that will generate unique values for all of the enums. 137 138 mask = 0 139 for i in [1, 2, 3, 4, 5, 6, 7, 8]: 140 mask = (1 << i) - 1 141 142 fail = 0; 143 for a in self.enums: 144 for b in self.enums: 145 if a != b: 146 if (a & mask) == (b & mask): 147 fail = 1; 148 149 if not fail: 150 break; 151 else: 152 mask = 0 153 154 if (mask != 0) and (mask < (2 * count)): 155 masked_enums = {} 156 masked_count = {} 157 158 for i in range(0, mask + 1): 159 masked_enums[i] = "0"; 160 masked_count[i] = 0; 161 162 for c in self.count: 163 for e in self.count[c]: 164 i = e & mask 165 enum_obj = self.enums[e][0] 166 masked_enums[i] = '0x%04x /* %s */' % (e, enum_obj.name ) 167 masked_count[i] = c 168 169 170 print(' static const GLushort a[%u] = {' % (mask + 1)) 171 for e in masked_enums: 172 print(' %s, ' % (masked_enums[e])) 173 print(' };') 174 175 print(' static const GLubyte b[%u] = {' % (mask + 1)) 176 for c in masked_count: 177 print(' %u, ' % (masked_count[c])) 178 print(' };') 179 180 print(' const unsigned idx = (e & 0x%02xU);' % (mask)) 181 print('') 182 print(' return (e == a[idx]) ? (GLint) b[idx] : 0;') 183 return 1; 184 else: 185 return 0; 186 187 188 def PrintUsingSwitch(self, name): 189 """Emit the body of the __gl*_size function using a 190 switch-statement.""" 191 192 print(' switch( e ) {') 193 194 for c in sorted(self.count): 195 for e in self.count[c]: 196 first = 1 197 198 # There may be multiple enums with the same 199 # value. This happens has extensions are 200 # promoted from vendor-specific or EXT to 201 # ARB and to the core. Emit the first one as 202 # a case label, and emit the others as 203 # commented-out case labels. 204 205 list = {} 206 for enum_obj in self.enums[e]: 207 list[ enum_obj.priority() ] = enum_obj.name 208 209 keys = sorted(list.keys()) 210 for k in keys: 211 j = list[k] 212 if first: 213 print(' case GL_%s:' % (j)) 214 first = 0 215 else: 216 print('/* case GL_%s:*/' % (j)) 217 218 if c == -1: 219 print(' return __gl%s_variable_size( e );' % (name)) 220 else: 221 print(' return %u;' % (c)) 222 223 print(' default: return 0;') 224 print(' }') 225 226 227 def Print(self, name): 228 print('_X_INTERNAL PURE FASTCALL GLint') 229 print('__gl%s_size( GLenum e )' % (name)) 230 print('{') 231 232 if not self.PrintUsingTable(): 233 self.PrintUsingSwitch(name) 234 235 print('}') 236 print('') 237 238 239class glx_server_enum_function(glx_enum_function): 240 def __init__(self, func, enum_dict): 241 glx_enum_function.__init__(self, func.name, enum_dict) 242 243 self.function = func 244 return 245 246 247 def signature( self ): 248 if self.sig == None: 249 sig = glx_enum_function.signature(self) 250 251 p = self.function.variable_length_parameter() 252 if p: 253 sig += "%u" % (p.size()) 254 255 self.sig = sig 256 257 return self.sig; 258 259 260 def Print(self, name, printer): 261 f = self.function 262 printer.common_func_print_just_header( f ) 263 264 fixup = [] 265 266 foo = {} 267 for param_name in f.count_parameter_list: 268 o = f.offset_of( param_name ) 269 foo[o] = param_name 270 271 for param_name in f.counter_list: 272 o = f.offset_of( param_name ) 273 foo[o] = param_name 274 275 keys = sorted(foo.keys()) 276 for o in keys: 277 p = f.parameters_by_name[ foo[o] ] 278 279 printer.common_emit_one_arg(p, "pc", 0) 280 fixup.append( p.name ) 281 282 283 print(' GLsizei compsize;') 284 print('') 285 286 printer.common_emit_fixups(fixup) 287 288 print('') 289 print(' compsize = __gl%s_size(%s);' % (f.name, string.join(f.count_parameter_list, ","))) 290 p = f.variable_length_parameter() 291 print(' return safe_pad(%s);' % (p.size_string())) 292 293 print('}') 294 print('') 295 296 297class PrintGlxSizeStubs_common(gl_XML.gl_print_base): 298 do_get = (1 << 0) 299 do_set = (1 << 1) 300 301 def __init__(self, which_functions): 302 gl_XML.gl_print_base.__init__(self) 303 304 self.name = "glX_proto_size.py (from Mesa)" 305 self.license = license.bsd_license_template % ( "(C) Copyright IBM Corporation 2004", "IBM") 306 307 self.emit_set = ((which_functions & PrintGlxSizeStubs_common.do_set) != 0) 308 self.emit_get = ((which_functions & PrintGlxSizeStubs_common.do_get) != 0) 309 return 310 311 312class PrintGlxSizeStubs_c(PrintGlxSizeStubs_common): 313 def printRealHeader(self): 314 print('') 315 print('#include <X11/Xfuncproto.h>') 316 print('#include <GL/gl.h>') 317 if self.emit_get: 318 print('#include "indirect_size_get.h"') 319 print('#include "glxserver.h"') 320 print('#include "indirect_util.h"') 321 322 print('#include "indirect_size.h"') 323 324 print('') 325 self.printPure() 326 print('') 327 self.printFastcall() 328 print('') 329 print('') 330 print('#ifdef HAVE_FUNC_ATTRIBUTE_ALIAS') 331 print('# define ALIAS2(from,to) \\') 332 print(' _X_INTERNAL PURE FASTCALL GLint __gl ## from ## _size( GLenum e ) \\') 333 print(' __attribute__ ((alias( # to )));') 334 print('# define ALIAS(from,to) ALIAS2( from, __gl ## to ## _size )') 335 print('#else') 336 print('# define ALIAS(from,to) \\') 337 print(' _X_INTERNAL PURE FASTCALL GLint __gl ## from ## _size( GLenum e ) \\') 338 print(' { return __gl ## to ## _size( e ); }') 339 print('#endif') 340 print('') 341 print('') 342 343 344 def printBody(self, api): 345 enum_sigs = {} 346 aliases = [] 347 348 for func in api.functionIterateGlx(): 349 ef = glx_enum_function( func.name, api.enums_by_name ) 350 if len(ef.enums) == 0: 351 continue 352 353 if (ef.is_set() and self.emit_set) or (not ef.is_set() and self.emit_get): 354 sig = ef.signature() 355 if sig in enum_sigs: 356 aliases.append( [func.name, enum_sigs[ sig ]] ) 357 else: 358 enum_sigs[ sig ] = func.name 359 ef.Print( func.name ) 360 361 362 for [alias_name, real_name] in aliases: 363 print('ALIAS( %s, %s )' % (alias_name, real_name)) 364 365 366 367class PrintGlxSizeStubs_h(PrintGlxSizeStubs_common): 368 def printRealHeader(self): 369 print("""/** 370 * \\file 371 * Prototypes for functions used to determine the number of data elements in 372 * various GLX protocol messages. 373 * 374 * \\author Ian Romanick <idr@us.ibm.com> 375 */ 376""") 377 print('#include <X11/Xfuncproto.h>') 378 print('') 379 self.printPure(); 380 print('') 381 self.printFastcall(); 382 print('') 383 384 385 def printBody(self, api): 386 for func in api.functionIterateGlx(): 387 ef = glx_enum_function( func.name, api.enums_by_name ) 388 if len(ef.enums) == 0: 389 continue 390 391 if (ef.is_set() and self.emit_set) or (not ef.is_set() and self.emit_get): 392 print('extern _X_INTERNAL PURE FASTCALL GLint __gl%s_size(GLenum);' % (func.name)) 393 394 395class PrintGlxReqSize_common(gl_XML.gl_print_base): 396 """Common base class for PrintGlxSizeReq_h and PrintGlxSizeReq_h. 397 398 The main purpose of this common base class is to provide the infrastructure 399 for the derrived classes to iterate over the same set of functions. 400 """ 401 402 def __init__(self): 403 gl_XML.gl_print_base.__init__(self) 404 405 self.name = "glX_proto_size.py (from Mesa)" 406 self.license = license.bsd_license_template % ( "(C) Copyright IBM Corporation 2005", "IBM") 407 408 409class PrintGlxReqSize_h(PrintGlxReqSize_common): 410 def __init__(self): 411 PrintGlxReqSize_common.__init__(self) 412 self.header_tag = "_INDIRECT_REQSIZE_H_" 413 414 415 def printRealHeader(self): 416 print('#include <X11/Xfuncproto.h>') 417 print('') 418 self.printPure() 419 print('') 420 421 422 def printBody(self, api): 423 for func in api.functionIterateGlx(): 424 if not func.ignore and func.has_variable_size_request(): 425 print('extern PURE _X_HIDDEN int __glX%sReqSize(const GLbyte *pc, Bool swap, int reqlen);' % (func.name)) 426 427 428class PrintGlxReqSize_c(PrintGlxReqSize_common): 429 """Create the server-side 'request size' functions. 430 431 Create the server-side functions that are used to determine what the 432 size of a varible length command should be. The server then uses 433 this value to determine if the incoming command packed it malformed. 434 """ 435 436 def __init__(self): 437 PrintGlxReqSize_common.__init__(self) 438 self.counter_sigs = {} 439 440 441 def printRealHeader(self): 442 print('') 443 print('#include <GL/gl.h>') 444 print('#include "glxserver.h"') 445 print('#include "glxbyteorder.h"') 446 print('#include "indirect_size.h"') 447 print('#include "indirect_reqsize.h"') 448 print('') 449 print('#ifdef HAVE_FUNC_ATTRIBUTE_ALIAS') 450 print('# define ALIAS2(from,to) \\') 451 print(' GLint __glX ## from ## ReqSize( const GLbyte * pc, Bool swap, int reqlen ) \\') 452 print(' __attribute__ ((alias( # to )));') 453 print('# define ALIAS(from,to) ALIAS2( from, __glX ## to ## ReqSize )') 454 print('#else') 455 print('# define ALIAS(from,to) \\') 456 print(' GLint __glX ## from ## ReqSize( const GLbyte * pc, Bool swap, int reqlen ) \\') 457 print(' { return __glX ## to ## ReqSize( pc, swap, reqlen ); }') 458 print('#endif') 459 print('') 460 print('') 461 462 463 def printBody(self, api): 464 aliases = [] 465 enum_functions = {} 466 enum_sigs = {} 467 468 for func in api.functionIterateGlx(): 469 if not func.has_variable_size_request(): continue 470 471 ef = glx_server_enum_function( func, api.enums_by_name ) 472 if len(ef.enums) == 0: continue 473 474 sig = ef.signature() 475 476 if func.name not in enum_functions: 477 enum_functions[ func.name ] = sig 478 479 if sig not in enum_sigs: 480 enum_sigs[ sig ] = ef 481 482 483 484 for func in api.functionIterateGlx(): 485 # Even though server-handcode fuctions are on "the 486 # list", and prototypes are generated for them, there 487 # isn't enough information to generate a size 488 # function. If there was enough information, they 489 # probably wouldn't need to be handcoded in the first 490 # place! 491 492 if func.server_handcode: continue 493 if not func.has_variable_size_request(): continue 494 495 if func.name in enum_functions: 496 sig = enum_functions[func.name] 497 ef = enum_sigs[ sig ] 498 499 if ef.name != func.name: 500 aliases.append( [func.name, ef.name] ) 501 else: 502 ef.Print( func.name, self ) 503 504 elif func.images: 505 self.printPixelFunction(func) 506 elif func.has_variable_size_request(): 507 a = self.printCountedFunction(func) 508 if a: aliases.append(a) 509 510 511 for [alias_name, real_name] in aliases: 512 print('ALIAS( %s, %s )' % (alias_name, real_name)) 513 514 return 515 516 517 def common_emit_fixups(self, fixup): 518 """Utility function to emit conditional byte-swaps.""" 519 520 if fixup: 521 print(' if (swap) {') 522 for name in fixup: 523 print(' %s = bswap_32(%s);' % (name, name)) 524 print(' }') 525 526 return 527 528 529 def common_emit_one_arg(self, p, pc, adjust): 530 offset = p.offset 531 dst = p.string() 532 src = '(%s *)' % (p.type_string()) 533 print('%-18s = *%11s(%s + %u);' % (dst, src, pc, offset + adjust)); 534 return 535 536 537 def common_func_print_just_header(self, f): 538 print('int') 539 print('__glX%sReqSize( const GLbyte * pc, Bool swap, int reqlen )' % (f.name)) 540 print('{') 541 542 543 def printPixelFunction(self, f): 544 self.common_func_print_just_header(f) 545 546 f.offset_of( f.parameters[0].name ) 547 [dim, w, h, d, junk] = f.get_images()[0].get_dimensions() 548 549 print(' GLint row_length = * (GLint *)(pc + 4);') 550 551 if dim < 3: 552 fixup = ['row_length', 'skip_rows', 'alignment'] 553 print(' GLint image_height = 0;') 554 print(' GLint skip_images = 0;') 555 print(' GLint skip_rows = * (GLint *)(pc + 8);') 556 print(' GLint alignment = * (GLint *)(pc + 16);') 557 else: 558 fixup = ['row_length', 'image_height', 'skip_rows', 'skip_images', 'alignment'] 559 print(' GLint image_height = * (GLint *)(pc + 8);') 560 print(' GLint skip_rows = * (GLint *)(pc + 16);') 561 print(' GLint skip_images = * (GLint *)(pc + 20);') 562 print(' GLint alignment = * (GLint *)(pc + 32);') 563 564 img = f.images[0] 565 for p in f.parameterIterateGlxSend(): 566 if p.name in [w, h, d, img.img_format, img.img_type, img.img_target]: 567 self.common_emit_one_arg(p, "pc", 0) 568 fixup.append( p.name ) 569 570 print('') 571 572 self.common_emit_fixups(fixup) 573 574 if img.img_null_flag: 575 print('') 576 print(' if (*(CARD32 *) (pc + %s))' % (img.offset - 4)) 577 print(' return 0;') 578 579 print('') 580 print(' return __glXImageSize(%s, %s, %s, %s, %s, %s,' % (img.img_format, img.img_type, img.img_target, w, h, d )) 581 print(' image_height, row_length, skip_images,') 582 print(' skip_rows, alignment);') 583 print('}') 584 print('') 585 return 586 587 588 def printCountedFunction(self, f): 589 590 sig = "" 591 offset = 0 592 fixup = [] 593 params = [] 594 size = '' 595 param_offsets = {} 596 597 # Calculate the offset of each counter parameter and the 598 # size string for the variable length parameter(s). While 599 # that is being done, calculate a unique signature for this 600 # function. 601 602 for p in f.parameterIterateGlxSend(): 603 if p.is_counter: 604 fixup.append( p.name ) 605 params.append( p ) 606 elif p.counter: 607 s = p.size() 608 if s == 0: s = 1 609 610 sig += "(%u,%u)" % (f.offset_of(p.counter), s) 611 if size == '': 612 size = p.size_string() 613 else: 614 size = "safe_add(%s, %s)" % (size, p.size_string()) 615 616 # If the calculated signature matches a function that has 617 # already be emitted, don't emit this function. Instead, add 618 # it to the list of function aliases. 619 620 if sig in self.counter_sigs: 621 n = self.counter_sigs[sig]; 622 alias = [f.name, n] 623 else: 624 alias = None 625 self.counter_sigs[sig] = f.name 626 627 self.common_func_print_just_header(f) 628 629 for p in params: 630 self.common_emit_one_arg(p, "pc", 0) 631 632 633 print('') 634 self.common_emit_fixups(fixup) 635 print('') 636 637 print(' return safe_pad(%s);' % (size)) 638 print('}') 639 print('') 640 641 return alias 642 643 644def _parser(): 645 """Parse arguments and return a namespace.""" 646 parser = argparse.ArgumentParser() 647 parser.set_defaults(which_functions=(PrintGlxSizeStubs_common.do_get | 648 PrintGlxSizeStubs_common.do_set)) 649 parser.add_argument('-f', 650 dest='filename', 651 default='gl_API.xml', 652 help='an XML file describing an OpenGL API.') 653 parser.add_argument('-m', 654 dest='mode', 655 choices=['size_c', 'size_h', 'reqsize_c', 'reqsize_h'], 656 help='Which file to generate') 657 getset = parser.add_mutually_exclusive_group() 658 getset.add_argument('--only-get', 659 dest='which_functions', 660 action='store_const', 661 const=PrintGlxSizeStubs_common.do_get, 662 help='only emit "get-type" functions') 663 getset.add_argument('--only-set', 664 dest='which_functions', 665 action='store_const', 666 const=PrintGlxSizeStubs_common.do_set, 667 help='only emit "set-type" functions') 668 parser.add_argument('--header-tag', 669 dest='header_tag', 670 action='store', 671 default=None, 672 help='set header tag value') 673 return parser.parse_args() 674 675 676def main(): 677 """Main function.""" 678 args = _parser() 679 680 if args.mode == "size_c": 681 printer = PrintGlxSizeStubs_c(args.which_functions) 682 elif args.mode == "size_h": 683 printer = PrintGlxSizeStubs_h(args.which_functions) 684 if args.header_tag is not None: 685 printer.header_tag = args.header_tag 686 elif args.mode == "reqsize_c": 687 printer = PrintGlxReqSize_c() 688 elif args.mode == "reqsize_h": 689 printer = PrintGlxReqSize_h() 690 691 api = gl_XML.parse_GL_API(args.filename, glX_XML.glx_item_factory()) 692 693 printer.Print(api) 694 695 696if __name__ == '__main__': 697 main() 698