1#!/usr/bin/env python3 2# Copyright 2017 The Dawn Authors 3# 4# Licensed under the Apache License, Version 2.0 (the "License"); 5# you may not use this file except in compliance with the License. 6# You may obtain a copy of the License at 7# 8# http://www.apache.org/licenses/LICENSE-2.0 9# 10# Unless required by applicable law or agreed to in writing, software 11# distributed under the License is distributed on an "AS IS" BASIS, 12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13# See the License for the specific language governing permissions and 14# limitations under the License. 15 16import json, os, sys 17from collections import namedtuple 18 19from generator_lib import Generator, run_generator, FileRender 20 21############################################################ 22# OBJECT MODEL 23############################################################ 24 25 26class Metadata: 27 def __init__(self, metadata): 28 self.api = metadata['api'] 29 self.namespace = metadata['namespace'] 30 self.c_prefix = metadata.get('c_prefix', self.namespace.upper()) 31 self.proc_table_prefix = metadata['proc_table_prefix'] 32 self.copyright_year = metadata.get('copyright_year', None) 33 34 35class Name: 36 def __init__(self, name, native=False): 37 self.native = native 38 self.name = name 39 if native: 40 self.chunks = [name] 41 else: 42 self.chunks = name.split(' ') 43 44 def get(self): 45 return self.name 46 47 def CamelChunk(self, chunk): 48 return chunk[0].upper() + chunk[1:] 49 50 def canonical_case(self): 51 return (' '.join(self.chunks)).lower() 52 53 def concatcase(self): 54 return ''.join(self.chunks) 55 56 def camelCase(self): 57 return self.chunks[0] + ''.join( 58 [self.CamelChunk(chunk) for chunk in self.chunks[1:]]) 59 60 def CamelCase(self): 61 return ''.join([self.CamelChunk(chunk) for chunk in self.chunks]) 62 63 def SNAKE_CASE(self): 64 return '_'.join([chunk.upper() for chunk in self.chunks]) 65 66 def snake_case(self): 67 return '_'.join(self.chunks) 68 69 def js_enum_case(self): 70 result = self.chunks[0].lower() 71 for chunk in self.chunks[1:]: 72 if not result[-1].isdigit(): 73 result += '-' 74 result += chunk.lower() 75 return result 76 77 78def concat_names(*names): 79 return ' '.join([name.canonical_case() for name in names]) 80 81 82class Type: 83 def __init__(self, name, json_data, native=False): 84 self.json_data = json_data 85 self.dict_name = name 86 self.name = Name(name, native=native) 87 self.category = json_data['category'] 88 self.is_wire_transparent = False 89 90 91EnumValue = namedtuple('EnumValue', ['name', 'value', 'valid', 'json_data']) 92 93 94class EnumType(Type): 95 def __init__(self, is_enabled, name, json_data): 96 Type.__init__(self, name, json_data) 97 98 self.values = [] 99 self.contiguousFromZero = True 100 lastValue = -1 101 for m in self.json_data['values']: 102 if not is_enabled(m): 103 continue 104 value = m['value'] 105 if value != lastValue + 1: 106 self.contiguousFromZero = False 107 lastValue = value 108 self.values.append( 109 EnumValue(Name(m['name']), value, m.get('valid', True), m)) 110 111 # Assert that all values are unique in enums 112 all_values = set() 113 for value in self.values: 114 if value.value in all_values: 115 raise Exception("Duplicate value {} in enum {}".format( 116 value.value, name)) 117 all_values.add(value.value) 118 self.is_wire_transparent = True 119 120 121BitmaskValue = namedtuple('BitmaskValue', ['name', 'value', 'json_data']) 122 123 124class BitmaskType(Type): 125 def __init__(self, is_enabled, name, json_data): 126 Type.__init__(self, name, json_data) 127 self.values = [ 128 BitmaskValue(Name(m['name']), m['value'], m) 129 for m in self.json_data['values'] if is_enabled(m) 130 ] 131 self.full_mask = 0 132 for value in self.values: 133 self.full_mask = self.full_mask | value.value 134 self.is_wire_transparent = True 135 136 137class FunctionPointerType(Type): 138 def __init__(self, is_enabled, name, json_data): 139 Type.__init__(self, name, json_data) 140 self.return_type = None 141 self.arguments = [] 142 143 144class TypedefType(Type): 145 def __init__(self, is_enabled, name, json_data): 146 Type.__init__(self, name, json_data) 147 self.type = None 148 149 150class NativeType(Type): 151 def __init__(self, is_enabled, name, json_data): 152 Type.__init__(self, name, json_data, native=True) 153 self.is_wire_transparent = True 154 155 156# Methods and structures are both "records", so record members correspond to 157# method arguments or structure members. 158class RecordMember: 159 def __init__(self, 160 name, 161 typ, 162 annotation, 163 json_data, 164 optional=False, 165 is_return_value=False, 166 default_value=None, 167 skip_serialize=False): 168 self.name = name 169 self.type = typ 170 self.annotation = annotation 171 self.json_data = json_data 172 self.length = None 173 self.optional = optional 174 self.is_return_value = is_return_value 175 self.handle_type = None 176 self.default_value = default_value 177 self.skip_serialize = skip_serialize 178 179 def set_handle_type(self, handle_type): 180 assert self.type.dict_name == "ObjectHandle" 181 self.handle_type = handle_type 182 183 184Method = namedtuple('Method', 185 ['name', 'return_type', 'arguments', 'json_data']) 186 187 188class ObjectType(Type): 189 def __init__(self, is_enabled, name, json_data): 190 json_data_override = {'methods': []} 191 if 'methods' in json_data: 192 json_data_override['methods'] = [ 193 m for m in json_data['methods'] if is_enabled(m) 194 ] 195 Type.__init__(self, name, dict(json_data, **json_data_override)) 196 197 198class Record: 199 def __init__(self, name): 200 self.name = Name(name) 201 self.members = [] 202 self.may_have_dawn_object = False 203 204 def update_metadata(self): 205 def may_have_dawn_object(member): 206 if isinstance(member.type, ObjectType): 207 return True 208 elif isinstance(member.type, StructureType): 209 return member.type.may_have_dawn_object 210 else: 211 return False 212 213 self.may_have_dawn_object = any( 214 may_have_dawn_object(member) for member in self.members) 215 216 # Set may_have_dawn_object to true if the type is chained or 217 # extensible. Chained structs may contain a Dawn object. 218 if isinstance(self, StructureType): 219 self.may_have_dawn_object = (self.may_have_dawn_object 220 or self.chained or self.extensible) 221 222 223class StructureType(Record, Type): 224 def __init__(self, is_enabled, name, json_data): 225 Record.__init__(self, name) 226 json_data_override = {} 227 if 'members' in json_data: 228 json_data_override['members'] = [ 229 m for m in json_data['members'] if is_enabled(m) 230 ] 231 Type.__init__(self, name, dict(json_data, **json_data_override)) 232 self.chained = json_data.get("chained", None) 233 self.extensible = json_data.get("extensible", None) 234 if self.chained: 235 assert (self.chained == "in" or self.chained == "out") 236 if self.extensible: 237 assert (self.extensible == "in" or self.extensible == "out") 238 # Chained structs inherit from wgpu::ChainedStruct, which has 239 # nextInChain, so setting both extensible and chained would result in 240 # two nextInChain members. 241 assert not (self.extensible and self.chained) 242 243 @property 244 def output(self): 245 return self.chained == "out" or self.extensible == "out" 246 247 248class ConstantDefinition(): 249 def __init__(self, is_enabled, name, json_data): 250 self.type = None 251 self.value = json_data['value'] 252 self.json_data = json_data 253 self.name = Name(name) 254 255 256class FunctionDeclaration(): 257 def __init__(self, is_enabled, name, json_data): 258 self.return_type = None 259 self.arguments = [] 260 self.json_data = json_data 261 self.name = Name(name) 262 263 264class Command(Record): 265 def __init__(self, name, members=None): 266 Record.__init__(self, name) 267 self.members = members or [] 268 self.derived_object = None 269 self.derived_method = None 270 271 272def linked_record_members(json_data, types): 273 members = [] 274 members_by_name = {} 275 for m in json_data: 276 member = RecordMember(Name(m['name']), 277 types[m['type']], 278 m.get('annotation', 'value'), 279 m, 280 optional=m.get('optional', False), 281 is_return_value=m.get('is_return_value', False), 282 default_value=m.get('default', None), 283 skip_serialize=m.get('skip_serialize', False)) 284 handle_type = m.get('handle_type') 285 if handle_type: 286 member.set_handle_type(types[handle_type]) 287 members.append(member) 288 members_by_name[member.name.canonical_case()] = member 289 290 for (member, m) in zip(members, json_data): 291 if member.annotation != 'value': 292 if not 'length' in m: 293 if member.type.category != 'object': 294 member.length = "constant" 295 member.constant_length = 1 296 else: 297 assert False 298 elif m['length'] == 'strlen': 299 member.length = 'strlen' 300 else: 301 member.length = members_by_name[m['length']] 302 303 return members 304 305 306############################################################ 307# PARSE 308############################################################ 309 310 311def link_object(obj, types): 312 def make_method(json_data): 313 arguments = linked_record_members(json_data.get('args', []), types) 314 return Method(Name(json_data['name']), 315 types[json_data.get('returns', 316 'void')], arguments, json_data) 317 318 obj.methods = [make_method(m) for m in obj.json_data.get('methods', [])] 319 obj.methods.sort(key=lambda method: method.name.canonical_case()) 320 321 322def link_structure(struct, types): 323 struct.members = linked_record_members(struct.json_data['members'], types) 324 325 326def link_function_pointer(function_pointer, types): 327 link_function(function_pointer, types) 328 329 330def link_typedef(typedef, types): 331 typedef.type = types[typedef.json_data['type']] 332 333 334def link_constant(constant, types): 335 constant.type = types[constant.json_data['type']] 336 assert constant.type.name.native 337 338 339def link_function(function, types): 340 function.return_type = types[function.json_data.get('returns', 'void')] 341 function.arguments = linked_record_members(function.json_data['args'], 342 types) 343 344 345# Sort structures so that if struct A has struct B as a member, then B is 346# listed before A. 347# 348# This is a form of topological sort where we try to keep the order reasonably 349# similar to the original order (though the sort isn't technically stable). 350# 351# It works by computing for each struct type what is the depth of its DAG of 352# dependents, then re-sorting based on that depth using Python's stable sort. 353# This makes a toposort because if A depends on B then its depth will be bigger 354# than B's. It is also nice because all nodes with the same depth are kept in 355# the input order. 356def topo_sort_structure(structs): 357 for struct in structs: 358 struct.visited = False 359 struct.subdag_depth = 0 360 361 def compute_depth(struct): 362 if struct.visited: 363 return struct.subdag_depth 364 365 max_dependent_depth = 0 366 for member in struct.members: 367 if member.type.category == 'structure': 368 max_dependent_depth = max(max_dependent_depth, 369 compute_depth(member.type) + 1) 370 371 struct.subdag_depth = max_dependent_depth 372 struct.visited = True 373 return struct.subdag_depth 374 375 for struct in structs: 376 compute_depth(struct) 377 378 result = sorted(structs, key=lambda struct: struct.subdag_depth) 379 380 for struct in structs: 381 del struct.visited 382 del struct.subdag_depth 383 384 return result 385 386 387def parse_json(json, enabled_tags): 388 is_enabled = lambda json_data: item_is_enabled(enabled_tags, json_data) 389 category_to_parser = { 390 'bitmask': BitmaskType, 391 'enum': EnumType, 392 'native': NativeType, 393 'function pointer': FunctionPointerType, 394 'object': ObjectType, 395 'structure': StructureType, 396 'typedef': TypedefType, 397 'constant': ConstantDefinition, 398 'function': FunctionDeclaration 399 } 400 401 types = {} 402 403 by_category = {} 404 for name in category_to_parser.keys(): 405 by_category[name] = [] 406 407 for (name, json_data) in json.items(): 408 if name[0] == '_' or not item_is_enabled(enabled_tags, json_data): 409 continue 410 category = json_data['category'] 411 parsed = category_to_parser[category](is_enabled, name, json_data) 412 by_category[category].append(parsed) 413 types[name] = parsed 414 415 for obj in by_category['object']: 416 link_object(obj, types) 417 418 for struct in by_category['structure']: 419 link_structure(struct, types) 420 421 for function_pointer in by_category['function pointer']: 422 link_function_pointer(function_pointer, types) 423 424 for typedef in by_category['typedef']: 425 link_typedef(typedef, types) 426 427 for constant in by_category['constant']: 428 link_constant(constant, types) 429 430 for function in by_category['function']: 431 link_function(function, types) 432 433 for category in by_category.keys(): 434 by_category[category] = sorted( 435 by_category[category], key=lambda typ: typ.name.canonical_case()) 436 437 by_category['structure'] = topo_sort_structure(by_category['structure']) 438 439 for struct in by_category['structure']: 440 struct.update_metadata() 441 442 api_params = { 443 'types': types, 444 'by_category': by_category, 445 'enabled_tags': enabled_tags, 446 } 447 return { 448 'metadata': Metadata(json['_metadata']), 449 'types': types, 450 'by_category': by_category, 451 'enabled_tags': enabled_tags, 452 'c_methods': lambda typ: c_methods(api_params, typ), 453 'c_methods_sorted_by_name': get_c_methods_sorted_by_name(api_params), 454 } 455 456 457############################################################ 458# WIRE STUFF 459############################################################ 460 461 462# Create wire commands from api methods 463def compute_wire_params(api_params, wire_json): 464 wire_params = api_params.copy() 465 types = wire_params['types'] 466 467 commands = [] 468 return_commands = [] 469 470 wire_json['special items']['client_handwritten_commands'] += wire_json[ 471 'special items']['client_side_commands'] 472 473 # Generate commands from object methods 474 for api_object in wire_params['by_category']['object']: 475 for method in api_object.methods: 476 command_name = concat_names(api_object.name, method.name) 477 command_suffix = Name(command_name).CamelCase() 478 479 # Only object return values or void are supported. 480 # Other methods must be handwritten. 481 is_object = method.return_type.category == 'object' 482 is_void = method.return_type.name.canonical_case() == 'void' 483 if not (is_object or is_void): 484 assert command_suffix in ( 485 wire_json['special items']['client_handwritten_commands']) 486 continue 487 488 if command_suffix in ( 489 wire_json['special items']['client_side_commands']): 490 continue 491 492 # Create object method commands by prepending "self" 493 members = [ 494 RecordMember(Name('self'), types[api_object.dict_name], 495 'value', {}) 496 ] 497 members += method.arguments 498 499 # Client->Server commands that return an object return the 500 # result object handle 501 if method.return_type.category == 'object': 502 result = RecordMember(Name('result'), 503 types['ObjectHandle'], 504 'value', {}, 505 is_return_value=True) 506 result.set_handle_type(method.return_type) 507 members.append(result) 508 509 command = Command(command_name, members) 510 command.derived_object = api_object 511 command.derived_method = method 512 commands.append(command) 513 514 for (name, json_data) in wire_json['commands'].items(): 515 commands.append(Command(name, linked_record_members(json_data, types))) 516 517 for (name, json_data) in wire_json['return commands'].items(): 518 return_commands.append( 519 Command(name, linked_record_members(json_data, types))) 520 521 wire_params['cmd_records'] = { 522 'command': commands, 523 'return command': return_commands 524 } 525 526 for commands in wire_params['cmd_records'].values(): 527 for command in commands: 528 command.update_metadata() 529 commands.sort(key=lambda c: c.name.canonical_case()) 530 531 wire_params.update(wire_json.get('special items', {})) 532 533 return wire_params 534 535 536############################################################# 537# Generator 538############################################################# 539 540 541def as_varName(*names): 542 return names[0].camelCase() + ''.join( 543 [name.CamelCase() for name in names[1:]]) 544 545 546def as_cType(c_prefix, name): 547 if name.native: 548 return name.concatcase() 549 else: 550 return c_prefix + name.CamelCase() 551 552 553def as_cppType(name): 554 if name.native: 555 return name.concatcase() 556 else: 557 return name.CamelCase() 558 559 560def as_jsEnumValue(value): 561 if 'jsrepr' in value.json_data: return value.json_data['jsrepr'] 562 return "'" + value.name.js_enum_case() + "'" 563 564 565def convert_cType_to_cppType(typ, annotation, arg, indent=0): 566 if typ.category == 'native': 567 return arg 568 if annotation == 'value': 569 if typ.category == 'object': 570 return '{}::Acquire({})'.format(as_cppType(typ.name), arg) 571 elif typ.category == 'structure': 572 converted_members = [ 573 convert_cType_to_cppType( 574 member.type, member.annotation, 575 '{}.{}'.format(arg, as_varName(member.name)), indent + 1) 576 for member in typ.members 577 ] 578 579 converted_members = [(' ' * 4) + m for m in converted_members] 580 converted_members = ',\n'.join(converted_members) 581 582 return as_cppType(typ.name) + ' {\n' + converted_members + '\n}' 583 else: 584 return 'static_cast<{}>({})'.format(as_cppType(typ.name), arg) 585 else: 586 return 'reinterpret_cast<{} {}>({})'.format(as_cppType(typ.name), 587 annotation, arg) 588 589 590def decorate(name, typ, arg): 591 if arg.annotation == 'value': 592 return typ + ' ' + name 593 elif arg.annotation == '*': 594 return typ + ' * ' + name 595 elif arg.annotation == 'const*': 596 return typ + ' const * ' + name 597 else: 598 assert False 599 600 601def annotated(typ, arg): 602 name = as_varName(arg.name) 603 return decorate(name, typ, arg) 604 605 606def item_is_enabled(enabled_tags, json_data): 607 tags = json_data.get('tags') 608 if tags is None: return True 609 return any(tag in enabled_tags for tag in tags) 610 611 612def as_cppEnum(value_name): 613 assert not value_name.native 614 if value_name.concatcase()[0].isdigit(): 615 return "e" + value_name.CamelCase() 616 return value_name.CamelCase() 617 618 619def as_MethodSuffix(type_name, method_name): 620 assert not type_name.native and not method_name.native 621 return type_name.CamelCase() + method_name.CamelCase() 622 623 624def as_frontendType(metadata, typ): 625 if typ.category == 'object': 626 return typ.name.CamelCase() + 'Base*' 627 elif typ.category in ['bitmask', 'enum']: 628 return metadata.namespace + '::' + typ.name.CamelCase() 629 elif typ.category == 'structure': 630 return as_cppType(typ.name) 631 else: 632 return as_cType(metadata.c_prefix, typ.name) 633 634 635def as_wireType(metadata, typ): 636 if typ.category == 'object': 637 return typ.name.CamelCase() + '*' 638 elif typ.category in ['bitmask', 'enum', 'structure']: 639 return metadata.c_prefix + typ.name.CamelCase() 640 else: 641 return as_cppType(typ.name) 642 643 644def c_methods(params, typ): 645 return typ.methods + [ 646 x for x in [ 647 Method(Name('reference'), params['types']['void'], [], 648 {'tags': ['dawn', 'emscripten']}), 649 Method(Name('release'), params['types']['void'], [], 650 {'tags': ['dawn', 'emscripten']}), 651 ] if item_is_enabled(params['enabled_tags'], x.json_data) 652 ] 653 654 655def get_c_methods_sorted_by_name(api_params): 656 unsorted = [(as_MethodSuffix(typ.name, method.name), typ, method) \ 657 for typ in api_params['by_category']['object'] \ 658 for method in c_methods(api_params, typ) ] 659 return [(typ, method) for (_, typ, method) in sorted(unsorted)] 660 661 662def has_callback_arguments(method): 663 return any(arg.type.category == 'function pointer' for arg in method.arguments) 664 665 666def make_base_render_params(metadata): 667 c_prefix = metadata.c_prefix 668 669 def as_cTypeEnumSpecialCase(typ): 670 if typ.category == 'bitmask': 671 return as_cType(c_prefix, typ.name) + 'Flags' 672 return as_cType(c_prefix, typ.name) 673 674 def as_cEnum(type_name, value_name): 675 assert not type_name.native and not value_name.native 676 return c_prefix + type_name.CamelCase() + '_' + value_name.CamelCase() 677 678 def as_cMethod(type_name, method_name): 679 c_method = c_prefix.lower() 680 if type_name != None: 681 assert not type_name.native 682 c_method += type_name.CamelCase() 683 assert not method_name.native 684 c_method += method_name.CamelCase() 685 return c_method 686 687 def as_cProc(type_name, method_name): 688 c_proc = c_prefix + 'Proc' 689 if type_name != None: 690 assert not type_name.native 691 c_proc += type_name.CamelCase() 692 assert not method_name.native 693 c_proc += method_name.CamelCase() 694 return c_proc 695 696 return { 697 'Name': lambda name: Name(name), 698 'as_annotated_cType': \ 699 lambda arg: annotated(as_cTypeEnumSpecialCase(arg.type), arg), 700 'as_annotated_cppType': \ 701 lambda arg: annotated(as_cppType(arg.type.name), arg), 702 'as_cEnum': as_cEnum, 703 'as_cppEnum': as_cppEnum, 704 'as_cMethod': as_cMethod, 705 'as_MethodSuffix': as_MethodSuffix, 706 'as_cProc': as_cProc, 707 'as_cType': lambda name: as_cType(c_prefix, name), 708 'as_cppType': as_cppType, 709 'as_jsEnumValue': as_jsEnumValue, 710 'convert_cType_to_cppType': convert_cType_to_cppType, 711 'as_varName': as_varName, 712 'decorate': decorate 713 } 714 715 716class MultiGeneratorFromDawnJSON(Generator): 717 def get_description(self): 718 return 'Generates code for various target from Dawn.json.' 719 720 def add_commandline_arguments(self, parser): 721 allowed_targets = [ 722 'dawn_headers', 'dawncpp_headers', 'dawncpp', 'dawn_proc', 723 'mock_webgpu', 'dawn_wire', "dawn_native_utils" 724 ] 725 726 parser.add_argument('--dawn-json', 727 required=True, 728 type=str, 729 help='The DAWN JSON definition to use.') 730 parser.add_argument('--wire-json', 731 default=None, 732 type=str, 733 help='The DAWN WIRE JSON definition to use.') 734 parser.add_argument( 735 '--targets', 736 required=True, 737 type=str, 738 help= 739 'Comma-separated subset of targets to output. Available targets: ' 740 + ', '.join(allowed_targets)) 741 def get_file_renders(self, args): 742 with open(args.dawn_json) as f: 743 loaded_json = json.loads(f.read()) 744 745 targets = args.targets.split(',') 746 747 wire_json = None 748 if args.wire_json: 749 with open(args.wire_json) as f: 750 wire_json = json.loads(f.read()) 751 752 renders = [] 753 754 params_dawn = parse_json(loaded_json, 755 enabled_tags=['dawn', 'native', 'deprecated']) 756 metadata = params_dawn['metadata'] 757 RENDER_PARAMS_BASE = make_base_render_params(metadata) 758 759 api = metadata.api.lower() 760 prefix = metadata.proc_table_prefix.lower() 761 if 'dawn_headers' in targets: 762 renders.append( 763 FileRender('api.h', 'src/include/dawn/' + api + '.h', 764 [RENDER_PARAMS_BASE, params_dawn])) 765 renders.append( 766 FileRender('dawn_proc_table.h', 767 'src/include/dawn/' + prefix + '_proc_table.h', 768 [RENDER_PARAMS_BASE, params_dawn])) 769 770 if 'dawncpp_headers' in targets: 771 renders.append( 772 FileRender('api_cpp.h', 'src/include/dawn/' + api + '_cpp.h', 773 [RENDER_PARAMS_BASE, params_dawn])) 774 775 renders.append( 776 FileRender('api_cpp_print.h', 777 'src/include/dawn/' + api + '_cpp_print.h', 778 [RENDER_PARAMS_BASE, params_dawn])) 779 780 if 'dawn_proc' in targets: 781 renders.append( 782 FileRender('dawn_proc.c', 'src/dawn/' + prefix + '_proc.c', 783 [RENDER_PARAMS_BASE, params_dawn])) 784 renders.append( 785 FileRender('dawn_thread_dispatch_proc.cpp', 786 'src/dawn/' + prefix + '_thread_dispatch_proc.cpp', 787 [RENDER_PARAMS_BASE, params_dawn])) 788 789 if 'webgpu_dawn_native_proc' in targets: 790 renders.append( 791 FileRender('dawn_native/api_dawn_native_proc.cpp', 792 'src/dawn_native/webgpu_dawn_native_proc.cpp', 793 [RENDER_PARAMS_BASE, params_dawn])) 794 795 if 'dawncpp' in targets: 796 renders.append( 797 FileRender('webgpu_cpp.cpp', 'src/dawn/webgpu_cpp.cpp', 798 [RENDER_PARAMS_BASE, params_dawn])) 799 800 if 'webgpu_headers' in targets: 801 params_upstream = parse_json(loaded_json, 802 enabled_tags=['upstream', 'native']) 803 renders.append( 804 FileRender('api.h', 'webgpu-headers/' + api + '.h', 805 [RENDER_PARAMS_BASE, params_upstream])) 806 807 if 'emscripten_bits' in targets: 808 params_emscripten = parse_json( 809 loaded_json, enabled_tags=['upstream', 'emscripten']) 810 renders.append( 811 FileRender('api.h', 'emscripten-bits/' + api + '.h', 812 [RENDER_PARAMS_BASE, params_emscripten])) 813 renders.append( 814 FileRender('api_cpp.h', 'emscripten-bits/' + api + '_cpp.h', 815 [RENDER_PARAMS_BASE, params_emscripten])) 816 renders.append( 817 FileRender('webgpu_cpp.cpp', 'emscripten-bits/webgpu_cpp.cpp', 818 [RENDER_PARAMS_BASE, params_emscripten])) 819 renders.append( 820 FileRender('webgpu_struct_info.json', 821 'emscripten-bits/webgpu_struct_info.json', 822 [RENDER_PARAMS_BASE, params_emscripten])) 823 renders.append( 824 FileRender('library_webgpu_enum_tables.js', 825 'emscripten-bits/library_webgpu_enum_tables.js', 826 [RENDER_PARAMS_BASE, params_emscripten])) 827 828 if 'mock_webgpu' in targets: 829 mock_params = [ 830 RENDER_PARAMS_BASE, params_dawn, { 831 'has_callback_arguments': has_callback_arguments 832 } 833 ] 834 renders.append( 835 FileRender('mock_webgpu.h', 'src/dawn/mock_webgpu.h', 836 mock_params)) 837 renders.append( 838 FileRender('mock_webgpu.cpp', 'src/dawn/mock_webgpu.cpp', 839 mock_params)) 840 841 if 'dawn_native_utils' in targets: 842 frontend_params = [ 843 RENDER_PARAMS_BASE, 844 params_dawn, 845 { 846 # TODO: as_frontendType and co. take a Type, not a Name :( 847 'as_frontendType': lambda typ: as_frontendType(metadata, typ), 848 'as_annotated_frontendType': \ 849 lambda arg: annotated(as_frontendType(metadata, arg.type), arg), 850 } 851 ] 852 853 renders.append( 854 FileRender('dawn_native/ValidationUtils.h', 855 'src/dawn_native/ValidationUtils_autogen.h', 856 frontend_params)) 857 renders.append( 858 FileRender('dawn_native/ValidationUtils.cpp', 859 'src/dawn_native/ValidationUtils_autogen.cpp', 860 frontend_params)) 861 renders.append( 862 FileRender('dawn_native/dawn_platform.h', 863 'src/dawn_native/dawn_platform_autogen.h', 864 frontend_params)) 865 renders.append( 866 FileRender('dawn_native/wgpu_structs.h', 867 'src/dawn_native/wgpu_structs_autogen.h', 868 frontend_params)) 869 renders.append( 870 FileRender('dawn_native/wgpu_structs.cpp', 871 'src/dawn_native/wgpu_structs_autogen.cpp', 872 frontend_params)) 873 renders.append( 874 FileRender('dawn_native/ProcTable.cpp', 875 'src/dawn_native/ProcTable.cpp', frontend_params)) 876 renders.append( 877 FileRender('dawn_native/ChainUtils.h', 878 'src/dawn_native/ChainUtils_autogen.h', 879 frontend_params)) 880 renders.append( 881 FileRender('dawn_native/ChainUtils.cpp', 882 'src/dawn_native/ChainUtils_autogen.cpp', 883 frontend_params)) 884 renders.append( 885 FileRender('dawn_native/webgpu_absl_format.h', 886 'src/dawn_native/webgpu_absl_format_autogen.h', 887 frontend_params)) 888 renders.append( 889 FileRender('dawn_native/webgpu_absl_format.cpp', 890 'src/dawn_native/webgpu_absl_format_autogen.cpp', 891 frontend_params)) 892 renders.append( 893 FileRender('dawn_native/ObjectType.h', 894 'src/dawn_native/ObjectType_autogen.h', 895 frontend_params)) 896 renders.append( 897 FileRender('dawn_native/ObjectType.cpp', 898 'src/dawn_native/ObjectType_autogen.cpp', 899 frontend_params)) 900 901 if 'dawn_wire' in targets: 902 additional_params = compute_wire_params(params_dawn, wire_json) 903 904 wire_params = [ 905 RENDER_PARAMS_BASE, params_dawn, { 906 'as_wireType': lambda type : as_wireType(metadata, type), 907 'as_annotated_wireType': \ 908 lambda arg: annotated(as_wireType(metadata, arg.type), arg), 909 }, additional_params 910 ] 911 renders.append( 912 FileRender('dawn_wire/ObjectType.h', 913 'src/dawn_wire/ObjectType_autogen.h', wire_params)) 914 renders.append( 915 FileRender('dawn_wire/WireCmd.h', 916 'src/dawn_wire/WireCmd_autogen.h', wire_params)) 917 renders.append( 918 FileRender('dawn_wire/WireCmd.cpp', 919 'src/dawn_wire/WireCmd_autogen.cpp', wire_params)) 920 renders.append( 921 FileRender('dawn_wire/client/ApiObjects.h', 922 'src/dawn_wire/client/ApiObjects_autogen.h', 923 wire_params)) 924 renders.append( 925 FileRender('dawn_wire/client/ApiProcs.cpp', 926 'src/dawn_wire/client/ApiProcs_autogen.cpp', 927 wire_params)) 928 renders.append( 929 FileRender('dawn_wire/client/ClientBase.h', 930 'src/dawn_wire/client/ClientBase_autogen.h', 931 wire_params)) 932 renders.append( 933 FileRender('dawn_wire/client/ClientHandlers.cpp', 934 'src/dawn_wire/client/ClientHandlers_autogen.cpp', 935 wire_params)) 936 renders.append( 937 FileRender( 938 'dawn_wire/client/ClientPrototypes.inc', 939 'src/dawn_wire/client/ClientPrototypes_autogen.inc', 940 wire_params)) 941 renders.append( 942 FileRender('dawn_wire/server/ServerBase.h', 943 'src/dawn_wire/server/ServerBase_autogen.h', 944 wire_params)) 945 renders.append( 946 FileRender('dawn_wire/server/ServerDoers.cpp', 947 'src/dawn_wire/server/ServerDoers_autogen.cpp', 948 wire_params)) 949 renders.append( 950 FileRender('dawn_wire/server/ServerHandlers.cpp', 951 'src/dawn_wire/server/ServerHandlers_autogen.cpp', 952 wire_params)) 953 renders.append( 954 FileRender( 955 'dawn_wire/server/ServerPrototypes.inc', 956 'src/dawn_wire/server/ServerPrototypes_autogen.inc', 957 wire_params)) 958 959 return renders 960 961 def get_dependencies(self, args): 962 deps = [os.path.abspath(args.dawn_json)] 963 if args.wire_json != None: 964 deps += [os.path.abspath(args.wire_json)] 965 return deps 966 967 968if __name__ == '__main__': 969 sys.exit(run_generator(MultiGeneratorFromDawnJSON())) 970