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