Generate multiple variants of webgpu.h header

Adds a "tag" system so that entries of dawn.json can be conditionally
emitted in different configurations. With a few more dawn.json changes,
this will enable generating the exact upstream header.

Bug: dawn:1080
Change-Id: I3506dadd485e31786578a3a64c3603c964c5354f
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/62580
Commit-Queue: Kai Ninomiya <kainino@chromium.org>
Reviewed-by: Austin Eng <enga@chromium.org>
diff --git a/dawn.json b/dawn.json
index f6c237b..363d6aa 100644
--- a/dawn.json
+++ b/dawn.json
@@ -22,8 +22,8 @@
         "extensible": true,
         "output": true,
         "members": [
-            {"name": "device ID", "type": "uint32_t"},
             {"name": "vendor ID", "type": "uint32_t"},
+            {"name": "device ID", "type": "uint32_t"},
             {"name": "name", "type": "char", "annotation": "const*"},
             {"name": "driver description", "type": "char", "annotation": "const*"},
             {"name": "adapter type", "type": "adapter type"},
@@ -32,7 +32,7 @@
     },
     "adapter type": {
         "category": "enum",
-        "javascript": false,
+        "emscripten_no_enum_table": true,
         "values": [
             {"value": 0, "name": "discrete GPU"},
             {"value": 1, "name": "integrated GPU"},
@@ -50,7 +50,7 @@
     },
     "backend type": {
         "category": "enum",
-        "javascript": false,
+        "emscripten_no_enum_table": true,
         "values": [
             {"value": 0, "name": "null"},
             {"value": 1, "name": "D3D11"},
@@ -150,6 +150,7 @@
     "external texture binding entry": {
         "category": "structure",
         "chained": true,
+        "tags": ["dawn"],
         "members": [
             {"name": "external texture", "type": "external texture"}
         ]
@@ -158,6 +159,7 @@
     "external texture binding layout": {
         "category": "structure",
         "chained": true,
+        "tags": ["dawn"],
         "members": []
     },
 
@@ -165,7 +167,7 @@
         "category": "enum",
         "values": [
             {"value": 0, "name": "undefined", "jsrepr": "undefined", "valid": false},
-            {"value": 1, "name": "write only", "jsrepr": "writeonly"}
+            {"value": 1, "name": "write only"}
         ]
     },
     "storage texture binding layout": {
@@ -271,6 +273,8 @@
             {
                 "name": "set label",
                 "returns": "void",
+                "tags": ["dawn"],
+                "_TODO": "needs an upstream equivalent",
                 "args": [
                     {"name": "label", "type": "char", "annotation": "const*", "length": "strlen"}
                 ]
@@ -302,6 +306,7 @@
     },
     "buffer map async status": {
         "category": "enum",
+        "emscripten_no_enum_table": true,
         "values": [
             {"value": 0, "name": "success"},
             {"value": 1, "name": "error"},
@@ -420,6 +425,7 @@
             },
             {
                 "name": "copy texture to texture internal",
+                "tags": ["dawn"],
                 "args": [
                     {"name": "source", "type": "image copy texture", "annotation": "const*"},
                     {"name": "destination", "type": "image copy texture", "annotation": "const*"},
@@ -428,10 +434,10 @@
             },
             {
                 "name": "inject validation error",
+                "tags": ["dawn"],
                 "args": [
                     {"name": "message", "type": "char", "annotation": "const*", "length": "strlen"}
-                ],
-                "TODO": "enga@: Make this a Dawn extension"
+                ]
             },
             {
                 "name": "insert debug marker",
@@ -499,6 +505,7 @@
     },
     "compilation info callback": {
         "category": "callback",
+        "tags": ["dawn"],
         "args": [
             {"name": "status", "type": "compilation info request status"},
             {"name": "compilation info", "type": "compilation info", "annotation": "const*"},
@@ -507,6 +514,7 @@
     },
     "compilation info request status": {
         "category": "enum",
+        "tags": ["dawn"],
         "values": [
             {"value": 0, "name": "success"},
             {"value": 1, "name": "error"},
@@ -528,6 +536,7 @@
     },
     "compilation message type": {
         "category": "enum",
+        "emscripten_no_enum_table": true,
         "values": [
             {"value": 0, "name": "error"},
             {"value": 1, "name": "warning"},
@@ -632,6 +641,7 @@
     },
     "alpha op": {
         "category": "enum",
+        "tags": ["dawn"],
         "values": [
             {"value": 0, "name": "dont change"},
             {"value": 1, "name": "premultiply"},
@@ -641,6 +651,7 @@
     "copy texture for browser options": {
         "category": "structure",
         "extensible": true,
+        "tags": ["dawn"],
         "members": [
             {"name": "flipY", "type": "bool", "default": "false"},
             {"name": "alphaOp", "type": "alpha op", "default": "dont change"}
@@ -657,6 +668,7 @@
     },
     "create pipeline async status": {
         "category": "enum",
+        "emscripten_no_enum_table": true,
         "values": [
             {"value": 0, "name": "success"},
             {"value": 1, "name": "error"},
@@ -709,7 +721,7 @@
             {
                 "name": "create error buffer",
                 "returns": "buffer",
-                "TODO": "enga@: Make this part of a dawn_wire extension"
+                "tags": ["dawn"]
             },
             {
                 "name": "create command encoder",
@@ -737,6 +749,7 @@
             {
                 "name": "create external texture",
                 "returns": "external texture",
+                "tags": ["dawn"],
                 "args": [
                     {"name": "external texture descriptor", "type": "external texture descriptor", "annotation": "const*"}
                 ]
@@ -824,13 +837,15 @@
                     {"name": "type", "type": "error type"},
                     {"name": "message", "type": "char", "annotation": "const*", "length": "strlen"}
                 ],
-                "TODO": "enga@: Make this a Dawn extension"
+                "tags": ["dawn"]
             },
             {
-                "name": "lose for testing"
+                "name": "lose for testing",
+                "tags": ["dawn"]
             },
             {
-                "name": "tick"
+                "name": "tick",
+                "tags": ["dawn"]
             },
             {
                 "name": "set uncaptured error callback",
@@ -841,6 +856,7 @@
             },
             {
                 "name": "set logging callback",
+                "tags": ["dawn"],
                 "args": [
                     {"name": "callback", "type": "logging callback"},
                     {"name": "userdata", "type": "void", "annotation": "*"}
@@ -879,6 +895,7 @@
     "device properties": {
         "category": "structure",
         "extensible": false,
+        "tags": ["dawn"],
         "members": [
             {"name": "device ID", "type": "uint32_t"},
             {"name": "vendor ID", "type": "uint32_t"},
@@ -954,6 +971,7 @@
     },
     "logging callback": {
         "category": "callback",
+        "tags": ["dawn"],
         "args": [
             {"name": "type", "type": "logging type"},
             {"name": "message", "type": "char", "annotation": "const*"},
@@ -970,6 +988,7 @@
     },
     "error type": {
         "category": "enum",
+        "emscripten_no_enum_table": true,
         "values": [
             {"value": 0, "name": "no error"},
             {"value": 1, "name": "validation"},
@@ -980,6 +999,7 @@
     },
     "logging type": {
         "category": "enum",
+        "tags": ["dawn"],
         "values": [
             {"value": 0, "name": "verbose"},
             {"value": 1, "name": "info"},
@@ -997,6 +1017,7 @@
     },
     "external texture": {
         "category": "object",
+        "tags": ["dawn"],
         "methods": [
             {
                 "name": "destroy",
@@ -1007,6 +1028,7 @@
     "external texture descriptor": {
         "category": "structure",
         "extensible": true,
+        "tags": ["dawn"],
         "members": [
             {"name": "plane 0", "type": "texture view"},
             {"name": "format", "type": "texture format"}
@@ -1100,6 +1122,7 @@
     },
     "load op": {
         "category": "enum",
+        "emscripten_no_enum_table": true,
         "values": [
             {"value": 0, "name": "clear"},
             {"value": 1, "name": "load"}
@@ -1152,6 +1175,7 @@
     },
     "present mode": {
         "category": "enum",
+        "emscripten_no_enum_table": true,
         "values": [
             {"value": 0, "name": "immediate"},
             {"value": 1, "name": "mailbox"},
@@ -1243,6 +1267,7 @@
             {
                 "name": "copy texture for browser",
                 "extensible": true,
+                "tags": ["dawn"],
                 "args": [
                     {"name": "source", "type": "image copy texture", "annotation": "const*"},
                     {"name": "destination", "type": "image copy texture", "annotation": "const*"},
@@ -1261,6 +1286,7 @@
     },
     "queue work done status": {
         "category": "enum",
+        "emscripten_no_enum_table": true,
         "values": [
             {"value": 0, "name": "success"},
             {"value": 1, "name": "error"},
@@ -1603,6 +1629,7 @@
 
     "request device status": {
         "category": "enum",
+        "emscripten_no_enum_table": true,
         "values": [
             {"value": 0, "name": "success"},
             {"value": 1, "name": "error"},
@@ -1734,6 +1761,7 @@
         "methods": [
             {
                 "name": "get compilation info",
+                "tags": ["dawn"],
                 "args": [
                     {"name": "callback", "type": "compilation info callback"},
                     {"name": "userdata", "type": "void", "annotation": "*"}
@@ -1822,7 +1850,7 @@
     "surface descriptor from metal layer": {
         "category": "structure",
         "chained": true,
-        "javascript": false,
+        "tags": ["native"],
         "members": [
             {"name": "layer", "type": "void", "annotation": "*"}
         ]
@@ -1830,7 +1858,7 @@
     "surface descriptor from windows HWND": {
         "category": "structure",
         "chained": true,
-        "javascript": false,
+        "tags": ["native"],
         "members": [
             {"name": "hinstance", "type": "void", "annotation": "*"},
             {"name": "hwnd", "type": "void", "annotation": "*"}
@@ -1839,7 +1867,7 @@
     "surface descriptor from xlib": {
         "category": "structure",
         "chained": true,
-        "javascript": false,
+        "tags": ["native"],
         "members": [
             {"name": "display", "type": "void", "annotation": "*"},
             {"name": "window", "type": "uint32_t"}
@@ -1848,7 +1876,7 @@
     "surface descriptor from windows core window": {
         "category": "structure",
         "chained": true,
-        "javascript": false,
+        "tags": ["dawn"],
         "members": [
             {"name": "core window", "type": "void", "annotation": "*"}
         ]
@@ -1856,7 +1884,7 @@
     "surface descriptor from windows swap chain panel": {
         "category": "structure",
         "chained": true,
-        "javascript": false,
+        "tags": ["dawn"],
         "members": [
             {"name": "swap chain panel", "type": "void", "annotation": "*"}
         ]
@@ -1866,6 +1894,7 @@
         "methods": [
             {
                 "name": "configure",
+                "tags": ["dawn"],
                 "args": [
                     {"name": "format", "type": "texture format"},
                     {"name": "allowed usage", "type": "texture usage"},
@@ -1887,26 +1916,26 @@
             {"name": "width", "type": "uint32_t"},
             {"name": "height", "type": "uint32_t"},
             {"name": "present mode", "type": "present mode"},
-            {"name": "implementation", "type": "uint64_t", "default": 0}
+            {"name": "implementation", "type": "uint64_t", "default": 0, "tags": ["deprecated"]}
         ]
     },
     "s type": {
         "category": "enum",
-        "javascript": false,
+        "emscripten_no_enum_table": true,
         "values": [
             {"value": 0, "name": "invalid", "valid": false},
-            {"value": 1, "name": "surface descriptor from metal layer"},
-            {"value": 2, "name": "surface descriptor from windows HWND"},
-            {"value": 3, "name": "surface descriptor from xlib"},
+            {"value": 1, "name": "surface descriptor from metal layer", "tags": ["native"]},
+            {"value": 2, "name": "surface descriptor from windows HWND", "tags": ["native"]},
+            {"value": 3, "name": "surface descriptor from xlib", "tags": ["native"]},
             {"value": 4, "name": "surface descriptor from canvas HTML selector"},
             {"value": 5, "name": "shader module SPIRV descriptor"},
             {"value": 6, "name": "shader module WGSL descriptor"},
             {"value": 7, "name": "primitive depth clamping state"},
-            {"value": 8, "name": "surface descriptor from windows core window"},
-            {"value": 9, "name": "external texture binding entry"},
-            {"value": 10, "name": "external texture binding layout"},
-            {"value": 11, "name": "surface descriptor from windows swap chain panel"},
-            {"value": 1000, "name": "dawn texture internal usage descriptor"}
+            {"value": 8, "name": "surface descriptor from windows core window", "tags": ["dawn"]},
+            {"value": 9, "name": "external texture binding entry", "tags": ["dawn"]},
+            {"value": 10, "name": "external texture binding layout", "tags": ["dawn"]},
+            {"value": 11, "name": "surface descriptor from windows swap chain panel", "tags": ["dawn"]},
+            {"value": 1000, "name": "dawn texture internal usage descriptor", "tags": ["dawn"]}
         ]
     },
     "texture": {
@@ -1922,6 +1951,8 @@
             {
                 "name": "set label",
                 "returns": "void",
+                "tags": ["dawn"],
+                "_TODO": "needs an upstream equivalent",
                 "args": [
                     {"name": "label", "type": "char", "annotation": "const*", "length": "strlen"}
                 ]
@@ -1937,8 +1968,8 @@
             {"value": 0, "name": "all"},
             {"value": 1, "name": "stencil only"},
             {"value": 2, "name": "depth only"},
-            {"value": 3, "name": "plane 0 only"},
-            {"value": 4, "name": "plane 1 only"}
+            {"value": 3, "name": "plane 0 only", "tags": ["dawn"]},
+            {"value": 4, "name": "plane 1 only", "tags": ["dawn"]}
         ]
     },
     "texture component type": {
@@ -1984,6 +2015,7 @@
         "category": "enum",
         "values": [
             {"value": 0, "name": "undefined", "valid": false, "jsrepr": "undefined"},
+
             {"value": 1, "name": "R8 unorm"},
             {"value": 2, "name": "R8 snorm"},
             {"value": 3, "name": "R8 uint"},
@@ -2086,7 +2118,7 @@
             {"value": 92, "name": "ASTC 12x12 unorm"},
             {"value": 93, "name": "ASTC 12x12 unorm srgb"},
 
-            {"value": 94, "name": "R8 BG8 Biplanar 420 unorm"}
+            {"value": 94, "name": "R8 BG8 Biplanar 420 unorm", "tags": ["dawn"]}
         ]
     },
     "texture usage": {
@@ -2098,7 +2130,7 @@
             {"value": 4, "name": "texture binding"},
             {"value": 8, "name": "storage binding"},
             {"value": 16, "name": "render attachment"},
-            {"value": 32, "name": "present"}
+            {"value": 32, "name": "present", "tags": ["dawn"]}
         ]
     },
     "texture view descriptor": {
@@ -2208,6 +2240,7 @@
     "dawn texture internal usage descriptor": {
         "category": "structure",
         "chained": true,
+        "tags": ["dawn"],
         "members": [
             {"name": "internal usage", "type": "texture usage", "default": "none"}
         ]
diff --git a/docs/codegen.md b/docs/codegen.md
index d79c0e9..036305c 100644
--- a/docs/codegen.md
+++ b/docs/codegen.md
@@ -10,10 +10,10 @@
 
 At this time it is used to generate:
 
- - the `webgpu.h` C header
- - the `webgpu_cpp.cpp/h` C++ wrapper over the C header
+ - the Dawn, Emscripten, and upstream webgpu-native `webgpu.h` C header
+ - the Dawn and Emscripten `webgpu_cpp.cpp/h` C++ wrapper over the C header
  - libraries that implements `webgpu.h` by calling in a static or `thread_local` proc table
- - parts of the [Emscripten](https://emscripten.org/) WebGPU implementation
+ - other parts of the [Emscripten](https://emscripten.org/) WebGPU implementation
  - a GMock version of the API with its proc table for testing
  - validation helper functions for dawn_native
  - the definition of dawn_native's proc table
@@ -25,6 +25,8 @@
 
 The basic schema is that every entry is a thing with a `"category"` key what determines the sub-schema to apply to that thing. Categories and their sub-shema are defined below. Several parts of the schema use the concept of "record" which is a list of "record members" which are a combination of a type, a name and other metadata. For example the list of arguments of a function is a record. The list of structure members is a record. This combined concept is useful for the dawn_wire generator to generate code for structure and function calls in a very similar way.
 
+Most items and sub-items can include a list of `"tags"`, which, if specified, conditionally includes the item if any of its tags appears in the `enabled_tags` configuration passed to `parse_json`. This is used to include and exclude various items for Dawn, Emscripten, or upstream header variants. Tags are applied in the "parse_json" step ([rather than later](https://docs.google.com/document/d/1fBniVOxx3-hQbxHMugEPcQsaXaKBZYVO8yG9iXJp-fU/edit?usp=sharing)): this has the benefit of automatically catching when, for a particular tag configuration, an included item references an excluded item.
+
 A **record** is a list of **record members**, each of which is a dictionary with the following schema:
  - `"name"` a string
  - `"type"` a string, the name of the base type for this member
@@ -44,6 +46,7 @@
    - `"value"` a number that can be decimal or hexadecimal
    - `"jsrepr"` (optional) a string to allow overriding how this value map to Javascript for the Emscripten bits
    - `"valid"` (defaults to true) a boolean that controls whether the dawn_native validation utilities will consider this enum value valid.
+ - `"emscripten_no_enum_table"` (optional) if true, skips generating an enum table in `library_webgpu_enum_tables.js`
 
 **`"bitmask"`** an `uint32_t`-based bitmask. It is similar to **`"enum"`** but can be output differently.
 
diff --git a/generator/dawn_generator.gni b/generator/dawn_generator.gni
index 370fc2c..b92b19d 100644
--- a/generator/dawn_generator.gni
+++ b/generator/dawn_generator.gni
@@ -45,6 +45,8 @@
   "src/dawn_wire/server/",
   "src/dawn_wire/",
   "src/include/dawn/",
+  "emscripten-bits/",
+  "webgpu-headers/",
 ]
 
 # Template to help invoking Dawn code generators based on generator_lib
diff --git a/generator/dawn_json_generator.py b/generator/dawn_json_generator.py
index 23558e6..684be3f 100644
--- a/generator/dawn_json_generator.py
+++ b/generator/dawn_json_generator.py
@@ -76,27 +76,27 @@
         self.dict_name = name
         self.name = Name(name, native=native)
         self.category = json_data['category']
-        self.javascript = self.json_data.get('javascript', True)
 
 
-EnumValue = namedtuple('EnumValue', ['name', 'value', 'valid', 'jsrepr'])
+EnumValue = namedtuple('EnumValue', ['name', 'value', 'valid', 'json_data'])
 
 
 class EnumType(Type):
-    def __init__(self, name, json_data):
+    def __init__(self, is_enabled, name, json_data):
         Type.__init__(self, name, json_data)
 
         self.values = []
         self.contiguousFromZero = True
         lastValue = -1
         for m in self.json_data['values']:
+            if not is_enabled(m):
+                continue
             value = m['value']
             if value != lastValue + 1:
                 self.contiguousFromZero = False
             lastValue = value
             self.values.append(
-                EnumValue(Name(m['name']), value, m.get('valid', True),
-                          m.get('jsrepr', None)))
+                EnumValue(Name(m['name']), value, m.get('valid', True), m))
 
         # Assert that all values are unique in enums
         all_values = set()
@@ -107,15 +107,15 @@
             all_values.add(value.value)
 
 
-BitmaskValue = namedtuple('BitmaskValue', ['name', 'value'])
+BitmaskValue = namedtuple('BitmaskValue', ['name', 'value', 'json_data'])
 
 
 class BitmaskType(Type):
-    def __init__(self, name, json_data):
+    def __init__(self, is_enabled, name, json_data):
         Type.__init__(self, name, json_data)
         self.values = [
-            BitmaskValue(Name(m['name']), m['value'])
-            for m in self.json_data['values']
+            BitmaskValue(Name(m['name']), m['value'], m)
+            for m in self.json_data['values'] if is_enabled(m)
         ]
         self.full_mask = 0
         for value in self.values:
@@ -123,19 +123,19 @@
 
 
 class CallbackType(Type):
-    def __init__(self, name, json_data):
+    def __init__(self, is_enabled, name, json_data):
         Type.__init__(self, name, json_data)
         self.arguments = []
 
 
 class TypedefType(Type):
-    def __init__(self, name, json_data):
+    def __init__(self, is_enabled, name, json_data):
         Type.__init__(self, name, json_data)
         self.type = None
 
 
 class NativeType(Type):
-    def __init__(self, name, json_data):
+    def __init__(self, is_enabled, name, json_data):
         Type.__init__(self, name, json_data, native=True)
 
 
@@ -146,6 +146,7 @@
                  name,
                  typ,
                  annotation,
+                 json_data,
                  optional=False,
                  is_return_value=False,
                  default_value=None,
@@ -153,6 +154,7 @@
         self.name = name
         self.type = typ
         self.annotation = annotation
+        self.json_data = json_data
         self.length = None
         self.optional = optional
         self.is_return_value = is_return_value
@@ -165,14 +167,18 @@
         self.handle_type = handle_type
 
 
-Method = namedtuple('Method', ['name', 'return_type', 'arguments'])
+Method = namedtuple('Method',
+                    ['name', 'return_type', 'arguments', 'json_data'])
 
 
 class ObjectType(Type):
-    def __init__(self, name, json_data):
-        Type.__init__(self, name, json_data)
-        self.methods = []
-        self.built_type = None
+    def __init__(self, is_enabled, name, json_data):
+        json_data_override = {'methods': []}
+        if 'methods' in json_data:
+            json_data_override['methods'] = [
+                m for m in json_data['methods'] if is_enabled(m)
+            ]
+        Type.__init__(self, name, dict(json_data, **json_data_override))
 
 
 class Record:
@@ -201,9 +207,14 @@
 
 
 class StructureType(Record, Type):
-    def __init__(self, name, json_data):
+    def __init__(self, is_enabled, name, json_data):
         Record.__init__(self, name)
-        Type.__init__(self, name, json_data)
+        json_data_override = {}
+        if 'members' in json_data:
+            json_data_override['members'] = [
+                m for m in json_data['members'] if is_enabled(m)
+            ]
+        Type.__init__(self, name, dict(json_data, **json_data_override))
         self.chained = json_data.get("chained", False)
         self.extensible = json_data.get("extensible", False)
         self.output = json_data.get("output", False)
@@ -228,6 +239,7 @@
         member = RecordMember(Name(m['name']),
                               types[m['type']],
                               m.get('annotation', 'value'),
+                              m,
                               optional=m.get('optional', False),
                               is_return_value=m.get('is_return_value', False),
                               default_value=m.get('default', None),
@@ -263,7 +275,8 @@
     def make_method(json_data):
         arguments = linked_record_members(json_data.get('args', []), types)
         return Method(Name(json_data['name']),
-                      types[json_data.get('returns', 'void')], arguments)
+                      types[json_data.get('returns',
+                                          'void')], arguments, json_data)
 
     obj.methods = [make_method(m) for m in obj.json_data.get('methods', [])]
     obj.methods.sort(key=lambda method: method.name.canonical_case())
@@ -324,7 +337,8 @@
     return result
 
 
-def parse_json(json):
+def parse_json(json, enabled_tags):
+    is_enabled = lambda json_data: item_is_enabled(enabled_tags, json_data)
     category_to_parser = {
         'bitmask': BitmaskType,
         'enum': EnumType,
@@ -342,10 +356,10 @@
         by_category[name] = []
 
     for (name, json_data) in json.items():
-        if name[0] == '_':
+        if name[0] == '_' or not item_is_enabled(enabled_tags, json_data):
             continue
         category = json_data['category']
-        parsed = category_to_parser[category](name, json_data)
+        parsed = category_to_parser[category](is_enabled, name, json_data)
         by_category[category].append(parsed)
         types[name] = parsed
 
@@ -370,7 +384,18 @@
     for struct in by_category['structure']:
         struct.update_metadata()
 
-    return {'types': types, 'by_category': by_category}
+    api_params = {
+        'types': types,
+        'by_category': by_category,
+        'enabled_tags': enabled_tags,
+    }
+    return {
+        'types': types,
+        'by_category': by_category,
+        'enabled_tags': enabled_tags,
+        'c_methods': lambda typ: c_methods(api_params, typ),
+        'c_methods_sorted_by_name': get_c_methods_sorted_by_name(api_params),
+    }
 
 
 ############################################################
@@ -411,7 +436,7 @@
             # Create object method commands by prepending "self"
             members = [
                 RecordMember(Name('self'), types[api_object.dict_name],
-                             'value')
+                             'value', {})
             ]
             members += method.arguments
 
@@ -420,7 +445,7 @@
             if method.return_type.category == 'object':
                 result = RecordMember(Name('result'),
                                       types['ObjectHandle'],
-                                      'value',
+                                      'value', {},
                                       is_return_value=True)
                 result.set_handle_type(method.return_type)
                 members.append(result)
@@ -490,7 +515,7 @@
 
 
 def as_jsEnumValue(value):
-    if value.jsrepr: return value.jsrepr
+    if 'jsrepr' in value.json_data: return value.json_data['jsrepr']
     return "'" + value.name.js_enum_case() + "'"
 
 
@@ -537,6 +562,12 @@
     return decorate(name, typ, arg)
 
 
+def item_is_enabled(enabled_tags, json_data):
+    tags = json_data.get('tags')
+    if tags is None: return True
+    return any(tag in enabled_tags for tag in tags)
+
+
 def as_cEnum(type_name, value_name):
     assert not type_name.native and not value_name.native
     return 'WGPU' + type_name.CamelCase() + '_' + value_name.CamelCase()
@@ -600,17 +631,21 @@
         return as_cppType(typ.name)
 
 
-def c_methods(types, typ):
+def c_methods(params, typ):
     return typ.methods + [
-        Method(Name('reference'), types['void'], []),
-        Method(Name('release'), types['void'], []),
+        x for x in [
+            Method(Name('reference'), params['types']['void'], [],
+                   {'tags': ['dawn', 'emscripten']}),
+            Method(Name('release'), params['types']['void'], [],
+                   {'tags': ['dawn', 'emscripten']}),
+        ] if item_is_enabled(params['enabled_tags'], x.json_data)
     ]
 
 
 def get_c_methods_sorted_by_name(api_params):
     unsorted = [(as_MethodSuffix(typ.name, method.name), typ, method) \
             for typ in api_params['by_category']['object'] \
-            for method in c_methods(api_params['types'], typ) ]
+            for method in c_methods(api_params, typ) ]
     return [(typ, method) for (_, typ, method) in sorted(unsorted)]
 
 
@@ -643,11 +678,9 @@
             help=
             'Comma-separated subset of targets to output. Available targets: '
             + ', '.join(allowed_targets))
-
     def get_file_renders(self, args):
         with open(args.dawn_json) as f:
             loaded_json = json.loads(f.read())
-        api_params = parse_json(loaded_json)
 
         targets = args.targets.split(',')
 
@@ -656,7 +689,9 @@
             with open(args.wire_json) as f:
                 wire_json = json.loads(f.read())
 
-        base_params = {
+        renders = []
+
+        RENDER_PARAMS_BASE = {
             'Name': lambda name: Name(name),
             'as_annotated_cType': \
                 lambda arg: annotated(as_cTypeEnumSpecialCase(arg.type), arg),
@@ -677,59 +712,75 @@
             'convert_cType_to_cppType': convert_cType_to_cppType,
             'as_varName': as_varName,
             'decorate': decorate,
-            'c_methods': lambda typ: c_methods(api_params['types'], typ),
-            'c_methods_sorted_by_name': \
-                get_c_methods_sorted_by_name(api_params),
         }
 
-        renders = []
+        params_dawn = parse_json(loaded_json,
+                                 enabled_tags=['dawn', 'native', 'deprecated'])
 
         if 'dawn_headers' in targets:
             renders.append(
                 FileRender('webgpu.h', 'src/include/dawn/webgpu.h',
-                           [base_params, api_params]))
+                           [RENDER_PARAMS_BASE, params_dawn]))
             renders.append(
                 FileRender('dawn_proc_table.h',
                            'src/include/dawn/dawn_proc_table.h',
-                           [base_params, api_params]))
+                           [RENDER_PARAMS_BASE, params_dawn]))
 
         if 'dawncpp_headers' in targets:
             renders.append(
                 FileRender('webgpu_cpp.h', 'src/include/dawn/webgpu_cpp.h',
-                           [base_params, api_params]))
+                           [RENDER_PARAMS_BASE, params_dawn]))
 
             renders.append(
                 FileRender('webgpu_cpp_print.h',
                            'src/include/dawn/webgpu_cpp_print.h',
-                           [base_params, api_params]))
+                           [RENDER_PARAMS_BASE, params_dawn]))
 
         if 'dawn_proc' in targets:
             renders.append(
                 FileRender('dawn_proc.c', 'src/dawn/dawn_proc.c',
-                           [base_params, api_params]))
+                           [RENDER_PARAMS_BASE, params_dawn]))
             renders.append(
                 FileRender('dawn_thread_dispatch_proc.cpp',
                            'src/dawn/dawn_thread_dispatch_proc.cpp',
-                           [base_params, api_params]))
+                           [RENDER_PARAMS_BASE, params_dawn]))
 
         if 'dawncpp' in targets:
             renders.append(
                 FileRender('webgpu_cpp.cpp', 'src/dawn/webgpu_cpp.cpp',
-                           [base_params, api_params]))
+                           [RENDER_PARAMS_BASE, params_dawn]))
+
+        if 'webgpu_headers' in targets:
+            params_upstream = parse_json(loaded_json,
+                                         enabled_tags=['upstream', 'native'])
+            renders.append(
+                FileRender('webgpu.h', 'webgpu-headers/webgpu.h',
+                           [RENDER_PARAMS_BASE, params_upstream]))
 
         if 'emscripten_bits' in targets:
+            params_emscripten = parse_json(
+                loaded_json, enabled_tags=['upstream', 'emscripten'])
+            renders.append(
+                FileRender('webgpu.h', 'emscripten-bits/webgpu.h',
+                           [RENDER_PARAMS_BASE, params_emscripten]))
+            renders.append(
+                FileRender('webgpu_cpp.h', 'emscripten-bits/webgpu_cpp.h',
+                           [RENDER_PARAMS_BASE, params_emscripten]))
+            renders.append(
+                FileRender('webgpu_cpp.cpp', 'emscripten-bits/webgpu_cpp.cpp',
+                           [RENDER_PARAMS_BASE, params_emscripten]))
             renders.append(
                 FileRender('webgpu_struct_info.json',
-                           'src/dawn/webgpu_struct_info.json',
-                           [base_params, api_params]))
+                           'emscripten-bits/webgpu_struct_info.json',
+                           [RENDER_PARAMS_BASE, params_emscripten]))
             renders.append(
                 FileRender('library_webgpu_enum_tables.js',
-                           'src/dawn/library_webgpu_enum_tables.js',
-                           [base_params, api_params]))
+                           'emscripten-bits/library_webgpu_enum_tables.js',
+                           [RENDER_PARAMS_BASE, params_emscripten]))
 
         if 'mock_webgpu' in targets:
             mock_params = [
-                base_params, api_params, {
+                RENDER_PARAMS_BASE, params_dawn, {
                     'has_callback_arguments': has_callback_arguments
                 }
             ]
@@ -742,8 +793,8 @@
 
         if 'dawn_native_utils' in targets:
             frontend_params = [
-                base_params,
-                api_params,
+                RENDER_PARAMS_BASE,
+                params_dawn,
                 {
                     # TODO: as_frontendType and co. take a Type, not a Name :(
                     'as_frontendType': lambda typ: as_frontendType(typ),
@@ -781,10 +832,10 @@
                            frontend_params))
 
         if 'dawn_wire' in targets:
-            additional_params = compute_wire_params(api_params, wire_json)
+            additional_params = compute_wire_params(params_dawn, wire_json)
 
             wire_params = [
-                base_params, api_params, {
+                RENDER_PARAMS_BASE, params_dawn, {
                     'as_wireType': as_wireType,
                     'as_annotated_wireType': \
                         lambda arg: annotated(as_wireType(arg.type), arg),
diff --git a/generator/templates/library_webgpu_enum_tables.js b/generator/templates/library_webgpu_enum_tables.js
index 44048ad..2ec4eb6 100644
--- a/generator/templates/library_webgpu_enum_tables.js
+++ b/generator/templates/library_webgpu_enum_tables.js
@@ -17,7 +17,7 @@
 //* Emscripten's library_webgpu.js.
 //* https://github.com/emscripten-core/emscripten/blob/master/src/library_webgpu.js
 //*
-    {% for type in by_category["enum"] if type.javascript %}
+    {% for type in by_category["enum"] if not type.json_data.get("emscripten_no_enum_table") %}
         {{type.name.CamelCase()}}: {% if type.contiguousFromZero -%}
             [
                 {% for value in type.values %}
diff --git a/generator/templates/webgpu.h b/generator/templates/webgpu.h
index e42c7ac..a0a6e3e 100644
--- a/generator/templates/webgpu.h
+++ b/generator/templates/webgpu.h
@@ -74,8 +74,10 @@
 #include <stdbool.h>
 
 #define WGPU_WHOLE_SIZE (0xffffffffffffffffULL)
-// TODO(crbug.com/dawn/520): Remove WGPU_STRIDE_UNDEFINED in favor of WGPU_COPY_STRIDE_UNDEFINED.
-#define WGPU_STRIDE_UNDEFINED (0xffffffffUL)
+{% if 'deprecated' in enabled_tags %}
+    // TODO(crbug.com/dawn/520): Remove WGPU_STRIDE_UNDEFINED in favor of WGPU_COPY_STRIDE_UNDEFINED.
+    #define WGPU_STRIDE_UNDEFINED (0xffffffffUL)
+{% endif %}
 #define WGPU_COPY_STRIDE_UNDEFINED (0xffffffffUL)
 #define WGPU_LIMIT_U32_UNDEFINED (0xffffffffUL)
 #define WGPU_LIMIT_U64_UNDEFINED (0xffffffffffffffffULL)
@@ -99,7 +101,7 @@
         typedef WGPUFlags {{as_cType(type.name)}}Flags;
     {% endif %}
 
-{% endfor %}
+{% endfor -%}
 
 typedef struct WGPUChainedStruct {
     struct WGPUChainedStruct const * next;
@@ -127,19 +129,19 @@
     } {{as_cType(type.name)}};
 
 {% endfor %}
-
 {% for typeDef in by_category["typedef"] %}
     // {{as_cType(typeDef.name)}} is deprecated.
     // Use {{as_cType(typeDef.type.name)}} instead.
     typedef {{as_cType(typeDef.type.name)}} {{as_cType(typeDef.name)}};
 
 {% endfor %}
+{% if 'deprecated' in enabled_tags %}
+    // TODO(crbug.com/dawn/1023): Remove after the deprecation period.
+    #define WGPUInputStepMode_Vertex WGPUVertexStepMode_Vertex
+    #define WGPUInputStepMode_Instance WGPUVertexStepMode_Instance
+    #define WGPUInputStepMode_Force32 WGPUVertexStepMode_Force32
 
-// TODO(crbug.com/dawn/1023): Remove after the deprecation period.
-#define WGPUInputStepMode_Vertex WGPUVertexStepMode_Vertex
-#define WGPUInputStepMode_Instance WGPUVertexStepMode_Instance
-#define WGPUInputStepMode_Force32 WGPUVertexStepMode_Force32
-
+{% endif %}
 #ifdef __cplusplus
 extern "C" {
 #endif
diff --git a/generator/templates/webgpu_cpp.cpp b/generator/templates/webgpu_cpp.cpp
index be17a5d..7f5dd59 100644
--- a/generator/templates/webgpu_cpp.cpp
+++ b/generator/templates/webgpu_cpp.cpp
@@ -11,7 +11,11 @@
 //* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 //* See the License for the specific language governing permissions and
 //* limitations under the License.
-#include "dawn/webgpu_cpp.h"
+{% if 'dawn' in enabled_tags %}
+    #include "dawn/webgpu_cpp.h"
+{% else %}
+    #include "webgpu/webgpu_cpp.h"
+{% endif %}
 
 namespace wgpu {
     {% for type in by_category["enum"] %}
diff --git a/generator/templates/webgpu_cpp.h b/generator/templates/webgpu_cpp.h
index fbb386d..951f6ad 100644
--- a/generator/templates/webgpu_cpp.h
+++ b/generator/templates/webgpu_cpp.h
@@ -20,8 +20,10 @@
 namespace wgpu {
 
     static constexpr uint64_t kWholeSize = WGPU_WHOLE_SIZE;
-    // TODO(crbug.com/520): Remove kStrideUndefined in favor of kCopyStrideUndefined.
-    static constexpr uint32_t kStrideUndefined = WGPU_STRIDE_UNDEFINED;
+    {% if 'deprecated' in enabled_tags %}
+        // TODO(crbug.com/520): Remove kStrideUndefined in favor of kCopyStrideUndefined.
+        static constexpr uint32_t kStrideUndefined = WGPU_STRIDE_UNDEFINED;
+    {% endif %}
     static constexpr uint32_t kCopyStrideUndefined = WGPU_COPY_STRIDE_UNDEFINED;
     static constexpr uint32_t kLimitU32Undefined = WGPU_LIMIT_U32_UNDEFINED;
     static constexpr uint64_t kLimitU64Undefined = WGPU_LIMIT_U64_UNDEFINED;
@@ -73,7 +75,6 @@
         using {{as_cppType(typeDef.name)}} = {{as_cppType(typeDef.type.name)}};
 
     {% endfor %}
-
     template<typename Derived, typename CType>
     class ObjectBase {
       public:
@@ -237,7 +238,6 @@
         };
 
     {% endfor %}
-
 }  // namespace wgpu
 
 #endif // WEBGPU_CPP_H_
diff --git a/generator/templates/webgpu_struct_info.json b/generator/templates/webgpu_struct_info.json
index c4b4000..6dd38af 100644
--- a/generator/templates/webgpu_struct_info.json
+++ b/generator/templates/webgpu_struct_info.json
@@ -26,7 +26,7 @@
                 "next",
                 "sType"
             ],
-            {% for type in by_category["structure"] if type.javascript %}
+            {% for type in by_category["structure"] %}
                 "{{as_cType(type.name)}}": [
                     {% if type.chained %}
                         "chain"
diff --git a/src/dawn/BUILD.gn b/src/dawn/BUILD.gn
index 543c51e..feddfee 100644
--- a/src/dawn/BUILD.gn
+++ b/src/dawn/BUILD.gn
@@ -29,14 +29,6 @@
   ]
 }
 
-dawn_json_generator("emscripten_bits_gen") {
-  target = "emscripten_bits"
-  outputs = [
-    "src/dawn/webgpu_struct_info.json",
-    "src/dawn/library_webgpu_enum_tables.js",
-  ]
-}
-
 source_set("dawn_headers") {
   all_dependent_configs = [ "${dawn_root}/src/common:dawn_public_include_dirs" ]
   public_deps = [ ":dawn_headers_gen" ]
@@ -107,3 +99,23 @@
     "${dawn_root}/src/include/dawn/dawn_thread_dispatch_proc.h",
   ]
 }
+
+###############################################################################
+# Other generated files (upstream header, emscripten header, emscripten bits)
+###############################################################################
+
+dawn_json_generator("webgpu_headers_gen") {
+  target = "webgpu_headers"
+  outputs = [ "webgpu-headers/webgpu.h" ]
+}
+
+dawn_json_generator("emscripten_bits_gen") {
+  target = "emscripten_bits"
+  outputs = [
+    "emscripten-bits/webgpu.h",
+    "emscripten-bits/webgpu_cpp.h",
+    "emscripten-bits/webgpu_cpp.cpp",
+    "emscripten-bits/webgpu_struct_info.json",
+    "emscripten-bits/library_webgpu_enum_tables.js",
+  ]
+}
diff --git a/src/dawn/CMakeLists.txt b/src/dawn/CMakeLists.txt
index ff7d278..389b6b0 100644
--- a/src/dawn/CMakeLists.txt
+++ b/src/dawn/CMakeLists.txt
@@ -87,3 +87,29 @@
 endif()
 target_sources(dawn_proc PRIVATE ${DAWNPROC_GEN_SOURCES})
 target_link_libraries(dawn_proc PUBLIC dawn_headers)
+
+###############################################################################
+# Other generated files (upstream header, emscripten header, emscripten bits)
+###############################################################################
+
+DawnJSONGenerator(
+    TARGET "webgpu_headers"
+    PRINT_NAME "WebGPU headers"
+    RESULT_VARIABLE "WEBGPU_HEADERS_GEN_SOURCES"
+)
+
+add_library(webgpu_headers STATIC ${DAWN_DUMMY_FILE})
+target_sources(webgpu_headers PRIVATE
+    ${WEBGPU_HEADERS_GEN_SOURCES}
+)
+
+DawnJSONGenerator(
+    TARGET "emscripten_bits"
+    PRINT_NAME "Emscripten WebGPU bits"
+    RESULT_VARIABLE "EMSCRIPTEN_BITS_GEN_SOURCES"
+)
+
+add_library(emscripten_bits STATIC ${DAWN_DUMMY_FILE})
+target_sources(emscripten_bits PRIVATE
+    ${EMSCRIPTEN_BITS_GEN_SOURCES}
+)