dawn.json: Add the "chain roots" data for chained structs.

This helps output in the headers information about which structure can
be used to extend which. In the future it could also be used to generate
helpers that validate that the chain for a root structure contains only
allowed extension structs.

Fixed: dawn:1486
Change-Id: I6134332d477503e242b3bec9f8e9bedeeb352351
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/96000
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
Reviewed-by: Austin Eng <enga@chromium.org>
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
diff --git a/dawn.json b/dawn.json
index e2e86c7..23d4c4a 100644
--- a/dawn.json
+++ b/dawn.json
@@ -162,6 +162,7 @@
         "tags": ["dawn", "native"],
         "category": "structure",
         "chained": "in",
+        "chain roots": ["device descriptor"],
         "members": [
             {"name": "force enabled toggles count", "type": "uint32_t", "default": 0},
             {"name": "force enabled toggles", "type": "char", "annotation": "const*const*", "length": "force enabled toggles count"},
@@ -173,6 +174,7 @@
         "tags": ["dawn", "native"],
         "category": "structure",
         "chained": "in",
+        "chain roots": ["device descriptor"],
         "members": [
             {"name": "isolation key", "type": "char", "annotation": "const*", "length": "strlen", "default": "\"\""}
         ]
@@ -306,6 +308,7 @@
     "external texture binding entry": {
         "category": "structure",
         "chained": "in",
+        "chain roots": ["bind group entry"],
         "tags": ["dawn"],
         "members": [
             {"name": "external texture", "type": "external texture"}
@@ -315,6 +318,7 @@
     "external texture binding layout": {
         "category": "structure",
         "chained": "in",
+        "chain roots": ["bind group layout entry"],
         "tags": ["dawn"],
         "members": []
     },
@@ -1445,6 +1449,7 @@
         "tags": ["dawn", "native"],
         "category": "structure",
         "chained": "in",
+        "chain roots": ["instance descriptor"],
         "members": [
             {"name": "additional runtime search paths count", "type": "uint32_t", "default": 0},
             {"name": "additional runtime search paths", "type": "char", "annotation": "const*const*", "length": "additional runtime search paths count"}
@@ -1891,6 +1896,7 @@
     "render pass descriptor max draw count": {
         "category": "structure",
         "chained": "in",
+        "chain roots": ["render pass descriptor"],
         "members": [
             {"name": "max draw count", "type": "uint64_t", "default": 50000000}
         ]
@@ -2147,6 +2153,7 @@
     "primitive depth clamping state": {
         "category": "structure",
         "chained": "in",
+        "chain roots": ["primitive state"],
         "tags": ["dawn", "emscripten"],
         "members": [
             {"name": "clamp depth", "type": "bool", "default": "false"}
@@ -2156,6 +2163,7 @@
     "primitive depth clip control": {
         "category": "structure",
         "chained": "in",
+        "chain roots": ["primitive state"],
         "members": [
             {"name": "unclipped depth", "type": "bool", "default": "false"}
         ]
@@ -2302,6 +2310,7 @@
     "shader module SPIRV descriptor": {
         "category": "structure",
         "chained": "in",
+        "chain roots": ["shader module descriptor"],
         "members": [
             {"name": "code size", "type": "uint32_t"},
             {"name": "code", "type": "uint32_t", "annotation": "const*", "length": "code size"}
@@ -2310,6 +2319,7 @@
     "shader module WGSL descriptor": {
         "category": "structure",
         "chained": "in",
+        "chain roots": ["shader module descriptor"],
         "members": [
             {"name": "source", "type": "char", "annotation": "const*", "length": "strlen", "tags": ["dawn", "emscripten"]},
             {"name": "code", "type": "char", "annotation": "const*", "length": "strlen", "tags": ["upstream"]}
@@ -2370,6 +2380,7 @@
     "surface descriptor from android native window": {
         "category": "structure",
         "chained": "in",
+        "chain roots": ["surface descriptor"],
         "tags": ["native"],
         "members": [
             {"name": "window", "type": "void", "annotation": "*"}
@@ -2378,6 +2389,7 @@
     "surface descriptor from canvas HTML selector": {
         "category": "structure",
         "chained": "in",
+        "chain roots": ["surface descriptor"],
         "members": [
             {"name": "selector", "type": "char", "annotation": "const*", "length": "strlen"}
         ]
@@ -2385,6 +2397,7 @@
     "surface descriptor from metal layer": {
         "category": "structure",
         "chained": "in",
+        "chain roots": ["surface descriptor"],
         "tags": ["native"],
         "members": [
             {"name": "layer", "type": "void", "annotation": "*"}
@@ -2393,6 +2406,7 @@
     "surface descriptor from windows HWND": {
         "category": "structure",
         "chained": "in",
+        "chain roots": ["surface descriptor"],
         "tags": ["native"],
         "members": [
             {"name": "hinstance", "type": "void", "annotation": "*"},
@@ -2402,6 +2416,7 @@
     "surface descriptor from xcb window": {
         "category": "structure",
         "chained": "in",
+        "chain roots": ["surface descriptor"],
         "tags": ["upstream"],
         "members": [
             {"name": "connection", "type": "void", "annotation": "*"},
@@ -2411,6 +2426,7 @@
     "surface descriptor from xlib window": {
         "category": "structure",
         "chained": "in",
+        "chain roots": ["surface descriptor"],
         "tags": ["native"],
         "members": [
             {"name": "display", "type": "void", "annotation": "*"},
@@ -2420,6 +2436,7 @@
     "surface descriptor from wayland surface": {
         "category": "structure",
         "chained": "in",
+        "chain roots": ["surface descriptor"],
         "tags": ["native"],
         "members": [
             {"name": "display", "type": "void", "annotation": "*"},
@@ -2429,6 +2446,7 @@
     "surface descriptor from windows core window": {
         "category": "structure",
         "chained": "in",
+        "chain roots": ["surface descriptor"],
         "tags": ["dawn"],
         "members": [
             {"name": "core window", "type": "void", "annotation": "*"}
@@ -2437,6 +2455,7 @@
     "surface descriptor from windows swap chain panel": {
         "category": "structure",
         "chained": "in",
+        "chain roots": ["surface descriptor"],
         "tags": ["dawn"],
         "members": [
             {"name": "swap chain panel", "type": "void", "annotation": "*"}
@@ -2886,6 +2905,7 @@
     "dawn texture internal usage descriptor": {
         "category": "structure",
         "chained": "in",
+        "chain roots": ["texture descriptor"],
         "tags": ["dawn"],
         "members": [
             {"name": "internal usage", "type": "texture usage", "default": "none"}
@@ -2894,6 +2914,7 @@
     "dawn encoder internal usage descriptor": {
         "category": "structure",
         "chained": "in",
+        "chain roots": ["command encoder descriptor"],
         "tags": ["dawn"],
         "members": [
             {"name": "use internal usages", "type": "bool", "default": "false"}
diff --git a/docs/dawn/codegen.md b/docs/dawn/codegen.md
index 315364c..d6b9ee2 100644
--- a/docs/dawn/codegen.md
+++ b/docs/dawn/codegen.md
@@ -68,7 +68,8 @@
 **`"structure"`**
  - `"members"` a **record**, so an array of **record members**
  - `"extensible"` (defaults to false) a boolean defining if this is an "extensible" WebGPU structure (i.e. has `nextInChain`). "descriptor" structures should usually have this set to true.
- - `"chained"` (defaults to false) a boolean defining if this is a structure that can be "chained" in a WebGPU structure (i.e. has `nextInChain` and `sType`)
+ - `"chained"` (defaults to None) a string defining if this is a structure that can be "chained" in a WebGPU structure (i.e. has `nextInChain` and `sType`) and in which direction ('in' for inputs to WebGPU, 'out' for outputs)
+ - `"chain roots"` (defaults to []) a list of strings that are the canonical names of structures that can be extended by this structure.
 
 **`"object"`**
  - `**methods**` an array of methods for this object. Note that "release" and "reference" don't need to be specified. Each method is a dictionary containing:
diff --git a/generator/dawn_json_generator.py b/generator/dawn_json_generator.py
index d02213d..cf8f3e8 100644
--- a/generator/dawn_json_generator.py
+++ b/generator/dawn_json_generator.py
@@ -237,12 +237,13 @@
                 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", None)
-        self.extensible = json_data.get("extensible", None)
+        self.chained = json_data.get('chained', None)
+        self.extensible = json_data.get('extensible', None)
         if self.chained:
-            assert (self.chained == "in" or self.chained == "out")
+            assert self.chained == 'in' or self.chained == 'out'
+            assert 'chain roots' in json_data
         if self.extensible:
-            assert (self.extensible == "in" or self.extensible == "out")
+            assert self.extensible == 'in' or self.extensible == 'out'
         # Chained structs inherit from wgpu::ChainedStruct, which has
         # nextInChain, so setting both extensible and chained would result in
         # two nextInChain members.
@@ -348,6 +349,8 @@
 
 def link_structure(struct, types):
     struct.members = linked_record_members(struct.json_data['members'], types)
+    struct.chain_roots = [types[root] for root in struct.json_data.get('chain roots', [])]
+    assert all((root.category == 'structure' for root in struct.chain_roots))
 
 
 def link_function_pointer(function_pointer, types):
diff --git a/generator/templates/api.h b/generator/templates/api.h
index 2694456..c4def22 100644
--- a/generator/templates/api.h
+++ b/generator/templates/api.h
@@ -89,6 +89,9 @@
 } {{c_prefix}}ChainedStructOut;
 
 {% for type in by_category["structure"] %}
+    {% for root in type.chain_roots %}
+        // Can be chained in {{as_cType(root.name)}}
+    {% endfor %}
     typedef struct {{as_cType(type.name)}} {
         {% set Out = "Out" if type.output else "" %}
         {% set const = "const " if not type.output else "" %}
diff --git a/generator/templates/api_cpp.h b/generator/templates/api_cpp.h
index 6ef3316..94acde2 100644
--- a/generator/templates/api_cpp.h
+++ b/generator/templates/api_cpp.h
@@ -225,6 +225,9 @@
         {% set Out = "Out" if type.output else "" %}
         {% set const = "const" if not type.output else "" %}
         {% if type.chained %}
+            {% for root in type.chain_roots %}
+                // Can be chained in {{as_cppType(root.name)}}
+            {% endfor %}
             struct {{as_cppType(type.name)}} : ChainedStruct{{Out}} {
                 {{as_cppType(type.name)}}() {
                     sType = SType::{{type.name.CamelCase()}};