• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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