1#!/usr/bin/env python 2 3# Mesa 3-D graphics library 4# 5# Copyright (C) 2010 LunarG Inc. 6# 7# Permission is hereby granted, free of charge, to any person obtaining a 8# copy of this software and associated documentation files (the "Software"), 9# to deal in the Software without restriction, including without limitation 10# the rights to use, copy, modify, merge, publish, distribute, sublicense, 11# and/or sell copies of the Software, and to permit persons to whom the 12# Software is furnished to do so, subject to the following conditions: 13# 14# The above copyright notice and this permission notice shall be included 15# in all copies or substantial portions of the 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 NONINFRINGEMENT. IN NO EVENT SHALL 20# THE AUTHORS OR COPYRIGHT HOLDERS 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 23# DEALINGS IN THE SOFTWARE. 24# 25# Authors: 26# Chia-I Wu <olv@lunarg.com> 27 28import sys 29# make it possible to import glapi 30import os 31GLAPI = os.path.join(".", os.path.dirname(sys.argv[0]), "glapi/gen") 32sys.path.append(GLAPI) 33 34import re 35from optparse import OptionParser 36import gl_XML 37import glX_XML 38 39 40# number of dynamic entries 41ABI_NUM_DYNAMIC_ENTRIES = 256 42 43class ABIEntry(object): 44 """Represent an ABI entry.""" 45 46 _match_c_param = re.compile( 47 '^(?P<type>[\w\s*]+?)(?P<name>\w+)(\[(?P<array>\d+)\])?$') 48 49 def __init__(self, cols, attrs, xml_data = None): 50 self._parse(cols) 51 52 self.slot = attrs['slot'] 53 self.hidden = attrs['hidden'] 54 self.alias = attrs['alias'] 55 self.handcode = attrs['handcode'] 56 self.xml_data = xml_data 57 58 def c_prototype(self): 59 return '%s %s(%s)' % (self.c_return(), self.name, self.c_params()) 60 61 def c_return(self): 62 ret = self.ret 63 if not ret: 64 ret = 'void' 65 66 return ret 67 68 def c_params(self): 69 """Return the parameter list used in the entry prototype.""" 70 c_params = [] 71 for t, n, a in self.params: 72 sep = '' if t.endswith('*') else ' ' 73 arr = '[%d]' % a if a else '' 74 c_params.append(t + sep + n + arr) 75 if not c_params: 76 c_params.append('void') 77 78 return ", ".join(c_params) 79 80 def c_args(self): 81 """Return the argument list used in the entry invocation.""" 82 c_args = [] 83 for t, n, a in self.params: 84 c_args.append(n) 85 86 return ", ".join(c_args) 87 88 def _parse(self, cols): 89 ret = cols.pop(0) 90 if ret == 'void': 91 ret = None 92 93 name = cols.pop(0) 94 95 params = [] 96 if not cols: 97 raise Exception(cols) 98 elif len(cols) == 1 and cols[0] == 'void': 99 pass 100 else: 101 for val in cols: 102 params.append(self._parse_param(val)) 103 104 self.ret = ret 105 self.name = name 106 self.params = params 107 108 def _parse_param(self, c_param): 109 m = self._match_c_param.match(c_param) 110 if not m: 111 raise Exception('unrecognized param ' + c_param) 112 113 c_type = m.group('type').strip() 114 c_name = m.group('name') 115 c_array = m.group('array') 116 c_array = int(c_array) if c_array else 0 117 118 return (c_type, c_name, c_array) 119 120 def __str__(self): 121 return self.c_prototype() 122 123 def __cmp__(self, other): 124 # compare slot, alias, and then name 125 res = cmp(self.slot, other.slot) 126 if not res: 127 if not self.alias: 128 res = -1 129 elif not other.alias: 130 res = 1 131 132 if not res: 133 res = cmp(self.name, other.name) 134 135 return res 136 137def abi_parse_xml(xml): 138 """Parse a GLAPI XML file for ABI entries.""" 139 api = gl_XML.parse_GL_API(xml, glX_XML.glx_item_factory()) 140 141 entry_dict = {} 142 for func in api.functionIterateByOffset(): 143 # make sure func.name appear first 144 entry_points = func.entry_points[:] 145 entry_points.remove(func.name) 146 entry_points.insert(0, func.name) 147 148 for name in entry_points: 149 attrs = { 150 'slot': func.offset, 151 'hidden': not func.is_static_entry_point(name), 152 'alias': None if name == func.name else func.name, 153 'handcode': bool(func.has_different_protocol(name)), 154 } 155 156 # post-process attrs 157 if attrs['alias']: 158 try: 159 alias = entry_dict[attrs['alias']] 160 except KeyError: 161 raise Exception('failed to alias %s' % attrs['alias']) 162 if alias.alias: 163 raise Exception('recursive alias %s' % ent.name) 164 attrs['alias'] = alias 165 if attrs['handcode']: 166 attrs['handcode'] = func.static_glx_name(name) 167 else: 168 attrs['handcode'] = None 169 170 if entry_dict.has_key(name): 171 raise Exception('%s is duplicated' % (name)) 172 173 cols = [] 174 cols.append(func.return_type) 175 cols.append(name) 176 params = func.get_parameter_string(name) 177 cols.extend([p.strip() for p in params.split(',')]) 178 179 ent = ABIEntry(cols, attrs, func) 180 entry_dict[ent.name] = ent 181 182 entries = entry_dict.values() 183 entries.sort() 184 185 return entries 186 187def abi_parse_line(line): 188 cols = [col.strip() for col in line.split(',')] 189 190 attrs = { 191 'slot': -1, 192 'hidden': False, 193 'alias': None, 194 'handcode': None, 195 } 196 197 # extract attributes from the first column 198 vals = cols[0].split(':') 199 while len(vals) > 1: 200 val = vals.pop(0) 201 if val.startswith('slot='): 202 attrs['slot'] = int(val[5:]) 203 elif val == 'hidden': 204 attrs['hidden'] = True 205 elif val.startswith('alias='): 206 attrs['alias'] = val[6:] 207 elif val.startswith('handcode='): 208 attrs['handcode'] = val[9:] 209 elif not val: 210 pass 211 else: 212 raise Exception('unknown attribute %s' % val) 213 cols[0] = vals[0] 214 215 return (attrs, cols) 216 217def abi_parse(filename): 218 """Parse a CSV file for ABI entries.""" 219 fp = open(filename) if filename != '-' else sys.stdin 220 lines = [line.strip() for line in fp.readlines() 221 if not line.startswith('#') and line.strip()] 222 223 entry_dict = {} 224 next_slot = 0 225 for line in lines: 226 attrs, cols = abi_parse_line(line) 227 228 # post-process attributes 229 if attrs['alias']: 230 try: 231 alias = entry_dict[attrs['alias']] 232 except KeyError: 233 raise Exception('failed to alias %s' % attrs['alias']) 234 if alias.alias: 235 raise Exception('recursive alias %s' % ent.name) 236 slot = alias.slot 237 attrs['alias'] = alias 238 else: 239 slot = next_slot 240 next_slot += 1 241 242 if attrs['slot'] < 0: 243 attrs['slot'] = slot 244 elif attrs['slot'] != slot: 245 raise Exception('invalid slot in %s' % (line)) 246 247 ent = ABIEntry(cols, attrs) 248 if entry_dict.has_key(ent.name): 249 raise Exception('%s is duplicated' % (ent.name)) 250 entry_dict[ent.name] = ent 251 252 entries = entry_dict.values() 253 entries.sort() 254 255 return entries 256 257def abi_sanity_check(entries): 258 if not entries: 259 return 260 261 all_names = [] 262 last_slot = entries[-1].slot 263 i = 0 264 for slot in xrange(last_slot + 1): 265 if entries[i].slot != slot: 266 raise Exception('entries are not ordered by slots') 267 if entries[i].alias: 268 raise Exception('first entry of slot %d aliases %s' 269 % (slot, entries[i].alias.name)) 270 handcode = None 271 while i < len(entries) and entries[i].slot == slot: 272 ent = entries[i] 273 if not handcode and ent.handcode: 274 handcode = ent.handcode 275 elif ent.handcode != handcode: 276 raise Exception('two aliases with handcode %s != %s', 277 ent.handcode, handcode) 278 279 if ent.name in all_names: 280 raise Exception('%s is duplicated' % (ent.name)) 281 if ent.alias and ent.alias.name not in all_names: 282 raise Exception('failed to alias %s' % (ent.alias.name)) 283 all_names.append(ent.name) 284 i += 1 285 if i < len(entries): 286 raise Exception('there are %d invalid entries' % (len(entries) - 1)) 287 288class ABIPrinter(object): 289 """MAPI Printer""" 290 291 def __init__(self, entries): 292 self.entries = entries 293 294 # sort entries by their names 295 self.entries_sorted_by_names = self.entries[:] 296 self.entries_sorted_by_names.sort(lambda x, y: cmp(x.name, y.name)) 297 298 self.indent = ' ' * 3 299 self.noop_warn = 'noop_warn' 300 self.noop_generic = 'noop_generic' 301 self.current_get = 'entry_current_get' 302 303 self.api_defines = [] 304 self.api_headers = ['"KHR/khrplatform.h"'] 305 self.api_call = 'KHRONOS_APICALL' 306 self.api_entry = 'KHRONOS_APIENTRY' 307 self.api_attrs = 'KHRONOS_APIATTRIBUTES' 308 309 self.c_header = '' 310 311 self.lib_need_table_size = True 312 self.lib_need_noop_array = True 313 self.lib_need_stubs = True 314 self.lib_need_all_entries = True 315 self.lib_need_non_hidden_entries = False 316 317 def c_notice(self): 318 return '/* This file is automatically generated by mapi_abi.py. Do not modify. */' 319 320 def c_public_includes(self): 321 """Return includes of the client API headers.""" 322 defines = ['#define ' + d for d in self.api_defines] 323 includes = ['#include ' + h for h in self.api_headers] 324 return "\n".join(defines + includes) 325 326 def need_entry_point(self, ent): 327 """Return True if an entry point is needed for the entry.""" 328 # non-handcode hidden aliases may share the entry they alias 329 use_alias = (ent.hidden and ent.alias and not ent.handcode) 330 return not use_alias 331 332 def c_public_declarations(self, prefix): 333 """Return the declarations of public entry points.""" 334 decls = [] 335 for ent in self.entries: 336 if not self.need_entry_point(ent): 337 continue 338 export = self.api_call if not ent.hidden else '' 339 decls.append(self._c_decl(ent, prefix, True, export) + ';') 340 341 return "\n".join(decls) 342 343 def c_mapi_table(self): 344 """Return defines of the dispatch table size.""" 345 num_static_entries = self.entries[-1].slot + 1 346 return ('#define MAPI_TABLE_NUM_STATIC %d\n' + \ 347 '#define MAPI_TABLE_NUM_DYNAMIC %d') % ( 348 num_static_entries, ABI_NUM_DYNAMIC_ENTRIES) 349 350 def c_mapi_table_initializer(self, prefix): 351 """Return the array initializer for mapi_table_fill.""" 352 entries = [self._c_function(ent, prefix) 353 for ent in self.entries if not ent.alias] 354 pre = self.indent + '(mapi_proc) ' 355 return pre + (',\n' + pre).join(entries) 356 357 def c_mapi_table_spec(self): 358 """Return the spec for mapi_init.""" 359 specv1 = [] 360 line = '"1' 361 for ent in self.entries: 362 if not ent.alias: 363 line += '\\0"\n' 364 specv1.append(line) 365 line = '"' 366 line += '%s\\0' % ent.name 367 line += '";' 368 specv1.append(line) 369 370 return self.indent + self.indent.join(specv1) 371 372 def _c_function(self, ent, prefix, mangle=False, stringify=False): 373 """Return the function name of an entry.""" 374 formats = { 375 True: { True: '%s_STR(%s)', False: '%s(%s)' }, 376 False: { True: '"%s%s"', False: '%s%s' }, 377 } 378 fmt = formats[prefix.isupper()][stringify] 379 name = ent.name 380 if mangle and ent.hidden: 381 name = '_dispatch_stub_' + str(ent.slot) 382 return fmt % (prefix, name) 383 384 def _c_function_call(self, ent, prefix): 385 """Return the function name used for calling.""" 386 if ent.handcode: 387 # _c_function does not handle this case 388 formats = { True: '%s(%s)', False: '%s%s' } 389 fmt = formats[prefix.isupper()] 390 name = fmt % (prefix, ent.handcode) 391 elif self.need_entry_point(ent): 392 name = self._c_function(ent, prefix, True) 393 else: 394 name = self._c_function(ent.alias, prefix, True) 395 return name 396 397 def _c_decl(self, ent, prefix, mangle=False, export=''): 398 """Return the C declaration for the entry.""" 399 decl = '%s %s %s(%s)' % (ent.c_return(), self.api_entry, 400 self._c_function(ent, prefix, mangle), ent.c_params()) 401 if export: 402 decl = export + ' ' + decl 403 if self.api_attrs: 404 decl += ' ' + self.api_attrs 405 406 return decl 407 408 def _c_cast(self, ent): 409 """Return the C cast for the entry.""" 410 cast = '%s (%s *)(%s)' % ( 411 ent.c_return(), self.api_entry, ent.c_params()) 412 413 return cast 414 415 def c_private_declarations(self, prefix): 416 """Return the declarations of private functions.""" 417 decls = [self._c_decl(ent, prefix) + ';' 418 for ent in self.entries if not ent.alias] 419 420 return "\n".join(decls) 421 422 def c_public_dispatches(self, prefix, no_hidden): 423 """Return the public dispatch functions.""" 424 dispatches = [] 425 for ent in self.entries: 426 if ent.hidden and no_hidden: 427 continue 428 429 if not self.need_entry_point(ent): 430 continue 431 432 export = self.api_call if not ent.hidden else '' 433 434 proto = self._c_decl(ent, prefix, True, export) 435 cast = self._c_cast(ent) 436 437 ret = '' 438 if ent.ret: 439 ret = 'return ' 440 stmt1 = self.indent 441 stmt1 += 'const struct mapi_table *_tbl = %s();' % ( 442 self.current_get) 443 stmt2 = self.indent 444 stmt2 += 'mapi_func _func = ((const mapi_func *) _tbl)[%d];' % ( 445 ent.slot) 446 stmt3 = self.indent 447 stmt3 += '%s((%s) _func)(%s);' % (ret, cast, ent.c_args()) 448 449 disp = '%s\n{\n%s\n%s\n%s\n}' % (proto, stmt1, stmt2, stmt3) 450 451 if ent.handcode: 452 disp = '#if 0\n' + disp + '\n#endif' 453 454 dispatches.append(disp) 455 456 return '\n\n'.join(dispatches) 457 458 def c_public_initializer(self, prefix): 459 """Return the initializer for public dispatch functions.""" 460 names = [] 461 for ent in self.entries: 462 if ent.alias: 463 continue 464 465 name = '%s(mapi_func) %s' % (self.indent, 466 self._c_function_call(ent, prefix)) 467 names.append(name) 468 469 return ',\n'.join(names) 470 471 def c_stub_string_pool(self): 472 """Return the string pool for use by stubs.""" 473 # sort entries by their names 474 sorted_entries = self.entries[:] 475 sorted_entries.sort(lambda x, y: cmp(x.name, y.name)) 476 477 pool = [] 478 offsets = {} 479 count = 0 480 for ent in sorted_entries: 481 offsets[ent] = count 482 pool.append('%s' % (ent.name)) 483 count += len(ent.name) + 1 484 485 pool_str = self.indent + '"' + \ 486 ('\\0"\n' + self.indent + '"').join(pool) + '";' 487 return (pool_str, offsets) 488 489 def c_stub_initializer(self, prefix, pool_offsets): 490 """Return the initializer for struct mapi_stub array.""" 491 stubs = [] 492 for ent in self.entries_sorted_by_names: 493 stubs.append('%s{ (void *) %d, %d, NULL }' % ( 494 self.indent, pool_offsets[ent], ent.slot)) 495 496 return ',\n'.join(stubs) 497 498 def c_noop_functions(self, prefix, warn_prefix): 499 """Return the noop functions.""" 500 noops = [] 501 for ent in self.entries: 502 if ent.alias: 503 continue 504 505 proto = self._c_decl(ent, prefix, False, 'static') 506 507 stmt1 = self.indent; 508 space = '' 509 for t, n, a in ent.params: 510 stmt1 += "%s(void) %s;" % (space, n) 511 space = ' ' 512 513 if ent.params: 514 stmt1 += '\n'; 515 516 stmt1 += self.indent + '%s(%s);' % (self.noop_warn, 517 self._c_function(ent, warn_prefix, False, True)) 518 519 if ent.ret: 520 stmt2 = self.indent + 'return (%s) 0;' % (ent.ret) 521 noop = '%s\n{\n%s\n%s\n}' % (proto, stmt1, stmt2) 522 else: 523 noop = '%s\n{\n%s\n}' % (proto, stmt1) 524 525 noops.append(noop) 526 527 return '\n\n'.join(noops) 528 529 def c_noop_initializer(self, prefix, use_generic): 530 """Return an initializer for the noop dispatch table.""" 531 entries = [self._c_function(ent, prefix) 532 for ent in self.entries if not ent.alias] 533 if use_generic: 534 entries = [self.noop_generic] * len(entries) 535 536 entries.extend([self.noop_generic] * ABI_NUM_DYNAMIC_ENTRIES) 537 538 pre = self.indent + '(mapi_func) ' 539 return pre + (',\n' + pre).join(entries) 540 541 def c_asm_gcc(self, prefix, no_hidden): 542 asm = [] 543 544 for ent in self.entries: 545 if ent.hidden and no_hidden: 546 continue 547 548 if not self.need_entry_point(ent): 549 continue 550 551 name = self._c_function(ent, prefix, True, True) 552 553 if ent.handcode: 554 asm.append('#if 0') 555 556 if ent.hidden: 557 asm.append('".hidden "%s"\\n"' % (name)) 558 559 if ent.alias and not (ent.alias.hidden and no_hidden): 560 asm.append('".globl "%s"\\n"' % (name)) 561 asm.append('".set "%s", "%s"\\n"' % (name, 562 self._c_function(ent.alias, prefix, True, True))) 563 else: 564 asm.append('STUB_ASM_ENTRY(%s)"\\n"' % (name)) 565 asm.append('"\\t"STUB_ASM_CODE("%d")"\\n"' % (ent.slot)) 566 567 if ent.handcode: 568 asm.append('#endif') 569 asm.append('') 570 571 return "\n".join(asm) 572 573 def output_for_lib(self): 574 print self.c_notice() 575 576 if self.c_header: 577 print 578 print self.c_header 579 580 print 581 print '#ifdef MAPI_TMP_DEFINES' 582 print self.c_public_includes() 583 print 584 print self.c_public_declarations(self.prefix_lib) 585 print '#undef MAPI_TMP_DEFINES' 586 print '#endif /* MAPI_TMP_DEFINES */' 587 588 if self.lib_need_table_size: 589 print 590 print '#ifdef MAPI_TMP_TABLE' 591 print self.c_mapi_table() 592 print '#undef MAPI_TMP_TABLE' 593 print '#endif /* MAPI_TMP_TABLE */' 594 595 if self.lib_need_noop_array: 596 print 597 print '#ifdef MAPI_TMP_NOOP_ARRAY' 598 print '#ifdef DEBUG' 599 print 600 print self.c_noop_functions(self.prefix_noop, self.prefix_warn) 601 print 602 print 'const mapi_func table_%s_array[] = {' % (self.prefix_noop) 603 print self.c_noop_initializer(self.prefix_noop, False) 604 print '};' 605 print 606 print '#else /* DEBUG */' 607 print 608 print 'const mapi_func table_%s_array[] = {' % (self.prefix_noop) 609 print self.c_noop_initializer(self.prefix_noop, True) 610 print '};' 611 print 612 print '#endif /* DEBUG */' 613 print '#undef MAPI_TMP_NOOP_ARRAY' 614 print '#endif /* MAPI_TMP_NOOP_ARRAY */' 615 616 if self.lib_need_stubs: 617 pool, pool_offsets = self.c_stub_string_pool() 618 print 619 print '#ifdef MAPI_TMP_PUBLIC_STUBS' 620 print 'static const char public_string_pool[] =' 621 print pool 622 print 623 print 'static const struct mapi_stub public_stubs[] = {' 624 print self.c_stub_initializer(self.prefix_lib, pool_offsets) 625 print '};' 626 print '#undef MAPI_TMP_PUBLIC_STUBS' 627 print '#endif /* MAPI_TMP_PUBLIC_STUBS */' 628 629 if self.lib_need_all_entries: 630 print 631 print '#ifdef MAPI_TMP_PUBLIC_ENTRIES' 632 print self.c_public_dispatches(self.prefix_lib, False) 633 print 634 print 'static const mapi_func public_entries[] = {' 635 print self.c_public_initializer(self.prefix_lib) 636 print '};' 637 print '#undef MAPI_TMP_PUBLIC_ENTRIES' 638 print '#endif /* MAPI_TMP_PUBLIC_ENTRIES */' 639 640 print 641 print '#ifdef MAPI_TMP_STUB_ASM_GCC' 642 print '__asm__(' 643 print self.c_asm_gcc(self.prefix_lib, False) 644 print ');' 645 print '#undef MAPI_TMP_STUB_ASM_GCC' 646 print '#endif /* MAPI_TMP_STUB_ASM_GCC */' 647 648 if self.lib_need_non_hidden_entries: 649 all_hidden = True 650 for ent in self.entries: 651 if not ent.hidden: 652 all_hidden = False 653 break 654 if not all_hidden: 655 print 656 print '#ifdef MAPI_TMP_PUBLIC_ENTRIES_NO_HIDDEN' 657 print self.c_public_dispatches(self.prefix_lib, True) 658 print 659 print '/* does not need public_entries */' 660 print '#undef MAPI_TMP_PUBLIC_ENTRIES_NO_HIDDEN' 661 print '#endif /* MAPI_TMP_PUBLIC_ENTRIES_NO_HIDDEN */' 662 663 print 664 print '#ifdef MAPI_TMP_STUB_ASM_GCC_NO_HIDDEN' 665 print '__asm__(' 666 print self.c_asm_gcc(self.prefix_lib, True) 667 print ');' 668 print '#undef MAPI_TMP_STUB_ASM_GCC_NO_HIDDEN' 669 print '#endif /* MAPI_TMP_STUB_ASM_GCC_NO_HIDDEN */' 670 671 def output_for_app(self): 672 print self.c_notice() 673 print 674 print self.c_private_declarations(self.prefix_app) 675 print 676 print '#ifdef API_TMP_DEFINE_SPEC' 677 print 678 print 'static const char %s_spec[] =' % (self.prefix_app) 679 print self.c_mapi_table_spec() 680 print 681 print 'static const mapi_proc %s_procs[] = {' % (self.prefix_app) 682 print self.c_mapi_table_initializer(self.prefix_app) 683 print '};' 684 print 685 print '#endif /* API_TMP_DEFINE_SPEC */' 686 687class GLAPIPrinter(ABIPrinter): 688 """OpenGL API Printer""" 689 690 def __init__(self, entries): 691 for ent in entries: 692 self._override_for_api(ent) 693 super(GLAPIPrinter, self).__init__(entries) 694 695 self.api_defines = ['GL_GLEXT_PROTOTYPES'] 696 self.api_headers = ['"GL/gl.h"', '"GL/glext.h"'] 697 self.api_call = 'GLAPI' 698 self.api_entry = 'APIENTRY' 699 self.api_attrs = '' 700 701 self.lib_need_table_size = False 702 self.lib_need_noop_array = False 703 self.lib_need_stubs = False 704 self.lib_need_all_entries = False 705 self.lib_need_non_hidden_entries = True 706 707 self.prefix_lib = 'GLAPI_PREFIX' 708 self.prefix_app = '_mesa_' 709 self.prefix_noop = 'noop' 710 self.prefix_warn = self.prefix_lib 711 712 self.c_header = self._get_c_header() 713 714 def _override_for_api(self, ent): 715 """Override attributes of an entry if necessary for this 716 printer.""" 717 # By default, no override is necessary. 718 pass 719 720 def _get_c_header(self): 721 header = """#ifndef _GLAPI_TMP_H_ 722#define _GLAPI_TMP_H_ 723#ifdef USE_MGL_NAMESPACE 724#define GLAPI_PREFIX(func) mgl##func 725#define GLAPI_PREFIX_STR(func) "mgl"#func 726#else 727#define GLAPI_PREFIX(func) gl##func 728#define GLAPI_PREFIX_STR(func) "gl"#func 729#endif /* USE_MGL_NAMESPACE */ 730 731typedef int GLclampx; 732#endif /* _GLAPI_TMP_H_ */""" 733 734 return header 735 736class ES1APIPrinter(GLAPIPrinter): 737 """OpenGL ES 1.x API Printer""" 738 739 def __init__(self, entries): 740 super(ES1APIPrinter, self).__init__(entries) 741 self.prefix_lib = 'gl' 742 self.prefix_warn = 'gl' 743 744 def _override_for_api(self, ent): 745 if ent.xml_data is None: 746 raise Exception('ES2 API printer requires XML input') 747 ent.hidden = (ent.name not in \ 748 ent.xml_data.entry_points_for_api_version('es1')) \ 749 or ent.hidden 750 ent.handcode = False 751 752 def _get_c_header(self): 753 header = """#ifndef _GLAPI_TMP_H_ 754#define _GLAPI_TMP_H_ 755typedef int GLclampx; 756#endif /* _GLAPI_TMP_H_ */""" 757 758 return header 759 760class ES2APIPrinter(GLAPIPrinter): 761 """OpenGL ES 2.x API Printer""" 762 763 def __init__(self, entries): 764 super(ES2APIPrinter, self).__init__(entries) 765 self.prefix_lib = 'gl' 766 self.prefix_warn = 'gl' 767 768 def _override_for_api(self, ent): 769 if ent.xml_data is None: 770 raise Exception('ES2 API printer requires XML input') 771 ent.hidden = (ent.name not in \ 772 ent.xml_data.entry_points_for_api_version('es2')) \ 773 or ent.hidden 774 775 # This is hella ugly. The same-named function in desktop OpenGL is 776 # hidden, but it needs to be exposed by libGLESv2 for OpenGL ES 3.0. 777 # There's no way to express in the XML that a function should be be 778 # hidden in one API but exposed in another. 779 if ent.name == 'GetInternalformativ': 780 ent.hidden = False 781 782 ent.handcode = False 783 784 def _get_c_header(self): 785 header = """#ifndef _GLAPI_TMP_H_ 786#define _GLAPI_TMP_H_ 787typedef int GLclampx; 788#endif /* _GLAPI_TMP_H_ */""" 789 790 return header 791 792class SharedGLAPIPrinter(GLAPIPrinter): 793 """Shared GLAPI API Printer""" 794 795 def __init__(self, entries): 796 super(SharedGLAPIPrinter, self).__init__(entries) 797 798 self.lib_need_table_size = True 799 self.lib_need_noop_array = True 800 self.lib_need_stubs = True 801 self.lib_need_all_entries = True 802 self.lib_need_non_hidden_entries = False 803 804 self.prefix_lib = 'shared' 805 self.prefix_warn = 'gl' 806 807 def _override_for_api(self, ent): 808 ent.hidden = True 809 ent.handcode = False 810 811 def _get_c_header(self): 812 header = """#ifndef _GLAPI_TMP_H_ 813#define _GLAPI_TMP_H_ 814typedef int GLclampx; 815#endif /* _GLAPI_TMP_H_ */""" 816 817 return header 818 819def parse_args(): 820 printers = ['glapi', 'es1api', 'es2api', 'shared-glapi'] 821 modes = ['lib', 'app'] 822 823 parser = OptionParser(usage='usage: %prog [options] <filename>') 824 parser.add_option('-p', '--printer', dest='printer', 825 help='printer to use: %s' % (", ".join(printers))) 826 parser.add_option('-m', '--mode', dest='mode', 827 help='target user: %s' % (", ".join(modes))) 828 829 options, args = parser.parse_args() 830 if not args or options.printer not in printers or \ 831 options.mode not in modes: 832 parser.print_help() 833 sys.exit(1) 834 835 return (args[0], options) 836 837def main(): 838 printers = { 839 'glapi': GLAPIPrinter, 840 'es1api': ES1APIPrinter, 841 'es2api': ES2APIPrinter, 842 'shared-glapi': SharedGLAPIPrinter, 843 } 844 845 filename, options = parse_args() 846 847 if filename.endswith('.xml'): 848 entries = abi_parse_xml(filename) 849 else: 850 entries = abi_parse(filename) 851 abi_sanity_check(entries) 852 853 printer = printers[options.printer](entries) 854 if options.mode == 'lib': 855 printer.output_for_lib() 856 else: 857 printer.output_for_app() 858 859if __name__ == '__main__': 860 main() 861