webgpu.h: Re-number enums, with defaulting: SamplerDescriptor

Trivial defaulting (matching what's defined in the upstream WebIDL) is
done via a new method .ApplyTrivialFrontendDefaults() called in various
places in the frontend as needed.

Part 1 implements the following, which occur directly in CreateSampler:

- SamplerDescriptor.addressMode[UVW]: AddressMode = ClampToEdge
- SamplerDescriptor.{min,mag}Filter: FilterMode = Nearest
- SamplerDescriptor.mipmapFilter: MipmapFilterMode = Nearest

Spot tests are added for all of these. They won't necessarily catch if
the defaulting is _wrong_, but should crash if it is _missing_.

Bug: dawn:2224
Change-Id: Ib325274c2e29cf822a6e3664412495b0c49ad7f0
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/165340
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Auto-Submit: Kai Ninomiya <kainino@chromium.org>
diff --git a/generator/dawn_json_generator.py b/generator/dawn_json_generator.py
index f9c900c..0fedc0a 100644
--- a/generator/dawn_json_generator.py
+++ b/generator/dawn_json_generator.py
@@ -117,17 +117,22 @@
         Type.__init__(self, name, json_data)
 
         self.values = []
+        self.hasUndefined = False
         self.contiguousFromZero = True
         lastValue = -1
         for m in self.json_data['values']:
             if not is_enabled(m):
                 continue
             value = m['value']
+            name = m['name']
+            if name == "undefined":
+                assert value == 0
+                self.hasUndefined = True
             if value != lastValue + 1:
                 self.contiguousFromZero = False
             lastValue = value
             self.values.append(
-                EnumValue(Name(m['name']), value, m.get('valid', True), m))
+                EnumValue(Name(name), value, m.get('valid', True), m))
 
         # Assert that all values are unique in enums
         all_values = set()
@@ -198,6 +203,11 @@
         self.default_value = default_value
         self.skip_serialize = skip_serialize
 
+        self.requires_struct_defaulting = False
+        if self.default_value not in [None, "undefined"] and self.annotation == "value" and \
+                self.type.category == "enum" and self.type.hasUndefined:
+            self.requires_struct_defaulting = True
+
     def set_handle_type(self, handle_type):
         assert self.type.dict_name == "ObjectHandle"
         self.handle_type = handle_type
@@ -297,6 +307,11 @@
                 return True
         return False
 
+    @property
+    def any_member_requires_struct_defaulting(self):
+        return any(member.requires_struct_defaulting
+                   for member in self.members)
+
 
 class ConstantDefinition():
     def __init__(self, is_enabled, name, json_data):
diff --git a/generator/templates/api_cpp.h b/generator/templates/api_cpp.h
index 1f9ca0a..1335065 100644
--- a/generator/templates/api_cpp.h
+++ b/generator/templates/api_cpp.h
@@ -188,7 +188,7 @@
         CType mHandle = nullptr;
     };
 
-{% macro render_cpp_default_value(member, is_struct=True, force_default=False) -%}
+{% macro render_cpp_default_value(member, is_struct, force_default=False) -%}
     {%- if member.json_data.get("no_default", false) -%}
     {%- elif member.annotation in ["*", "const*"] and member.optional or member.default_value == "nullptr" -%}
         {{" "}}= nullptr
@@ -280,7 +280,7 @@
                 ChainedStruct{{Out}} {{const}} * nextInChain = nullptr;
             {% endif %}
             {% for member in type.members %}
-                {% set member_declaration = as_annotated_cppType(member, type.has_free_members_function) + render_cpp_default_value(member, False, type.has_free_members_function) %}
+                {% set member_declaration = as_annotated_cppType(member, type.has_free_members_function) + render_cpp_default_value(member, True, type.has_free_members_function) %}
                 {% if type.chained and loop.first %}
                     //* Align the first member after ChainedStruct to match the C struct layout.
                     //* It has to be aligned both to its natural and ChainedStruct's alignment.
diff --git a/generator/templates/dawn/native/api_structs.cpp b/generator/templates/dawn/native/api_structs.cpp
index bd0f3a3..5e11d83 100644
--- a/generator/templates/dawn/native/api_structs.cpp
+++ b/generator/templates/dawn/native/api_structs.cpp
@@ -68,6 +68,16 @@
                          "offsetof mismatch for {{CppType}}::{{memberName}}");
         {% endfor %}
 
+        {% if type.any_member_requires_struct_defaulting %}
+            void {{CppType}}::ApplyTrivialFrontendDefaults() {
+                {% for member in type.members if member.requires_struct_defaulting %}
+                    {% set memberName = member.name.camelCase() %}
+                    if ({{memberName}} == {{namespace}}::{{as_cppType(member.type.name)}}::Undefined) {
+                        {{memberName}} = {{namespace}}::{{as_cppType(member.type.name)}}::{{as_cppEnum(Name(member.default_value))}};
+                    }
+                {% endfor %}
+            }
+        {% endif %}
         bool {{CppType}}::operator==(const {{as_cppType(type.name)}}& rhs) const {
             return {% if type.extensible or type.chained -%}
                 (nextInChain == rhs.nextInChain) &&
diff --git a/generator/templates/dawn/native/api_structs.h b/generator/templates/dawn/native/api_structs.h
index f484bcd..481f9b9 100644
--- a/generator/templates/dawn/native/api_structs.h
+++ b/generator/templates/dawn/native/api_structs.h
@@ -96,6 +96,12 @@
                 {% endif %}
             {% endfor %}
 
+            {% if type.any_member_requires_struct_defaulting %}
+                // For any enum members with trivial defaulting (where something like
+                // "Undefined" is replaced with a default), this method applies all of the
+                // defaults for the struct. It must be called in an appropriate place in Dawn.
+                void ApplyTrivialFrontendDefaults();
+            {% endif %}
             // Equality operators, mostly for testing. Note that this tests
             // strict pointer-pointer equality if the struct contains member pointers.
             bool operator==(const {{as_cppType(type.name)}}& rhs) const;