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