[webgpu-headers] Define depthWriteEnabled as WGPUOptionalBool

The following CLs must be merged before:
- https://chromium-review.googlesource.com/c/chromium/src/+/5683307
- https://skia-review.googlesource.com/c/skia/+/874238

https://github.com/webgpu-native/webgpu-headers/pull/308

Bug: 42241167
Change-Id: Ib6266b6981fb8caf38b734977ceaeeeed2cf55f9
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/197214
Reviewed-by: Austin Eng <enga@chromium.org>
Commit-Queue: Fr <beaufort.francois@gmail.com>
diff --git a/generator/dawn_json_generator.py b/generator/dawn_json_generator.py
index 4a1d466..eee6c70 100644
--- a/generator/dawn_json_generator.py
+++ b/generator/dawn_json_generator.py
@@ -145,7 +145,8 @@
             value += prefix
 
             if value_name == "undefined":
-                assert value == 0
+                if name != "optional bool":
+                    assert value == 0
                 self.hasUndefined = True
             if value != lastValue + 1:
                 self.contiguousFromZero = False
diff --git a/generator/templates/api.h b/generator/templates/api.h
index 3322b6b..6106216 100644
--- a/generator/templates/api.h
+++ b/generator/templates/api.h
@@ -73,6 +73,7 @@
 #endif
 
 #define WGPU_BREAKING_CHANGE_DEPTH_CLIP_CONTROL
+#define WGPU_BREAKING_CHANGE_DEPTH_WRITE_ENABLED
 
 #include <stdint.h>
 #include <stddef.h>
diff --git a/generator/templates/api_cpp.h b/generator/templates/api_cpp.h
index e88d34a..49315cb 100644
--- a/generator/templates/api_cpp.h
+++ b/generator/templates/api_cpp.h
@@ -100,7 +100,9 @@
     )
 {%- endmacro -%}
 
-{% for type in by_category["enum"] %}
+//* Although 'optional bool' is defined as an enum value, in C++, we manually implement it to
+//* provide conversion utilities.
+{% for type in by_category["enum"] if type.name.get() != "optional bool" %}
     {% set CppType = as_cppType(type.name) %}
     {% set CType = as_cType(type.name) %}
     enum class {{CppType}} : uint32_t {
@@ -153,6 +155,67 @@
     {{BoolCType}} mValue = static_cast<{{BoolCType}}>(false);
 };
 
+// Special class for optional booleans in order to allow conversions.
+{% set OptionalBool = types["optional bool"] %}
+{% set OptionalBoolCppType = as_cppType(OptionalBool.name) %}
+{% set OptionalBoolCType = as_cType(OptionalBool.name) %}
+{% set OptionalBoolUndefined = as_cEnum(OptionalBool.name, find_by_name(OptionalBool.values, "undefined").name) %}
+class {{OptionalBoolCppType}} {
+  public:
+    constexpr {{OptionalBoolCppType}}() = default;
+    // NOLINTNEXTLINE(runtime/explicit) allow implicit construction
+    constexpr {{OptionalBoolCppType}}(bool value) : mValue(static_cast<{{OptionalBoolCType}}>(value)) {}
+    // NOLINTNEXTLINE(runtime/explicit) allow implicit construction
+    constexpr {{OptionalBoolCppType}}(std::optional<bool> value) :
+        mValue(value ? static_cast<{{OptionalBoolCType}}>(*value) : {{OptionalBoolUndefined}}) {}
+    // NOLINTNEXTLINE(runtime/explicit) allow implicit construction
+    constexpr {{OptionalBoolCppType}}({{OptionalBoolCType}} value): mValue(value) {}
+
+    // Define the values that are equivalent to the enums.
+    {% for value in OptionalBool.values %}
+        static const {{OptionalBoolCppType}} {{as_cppEnum(value.name)}};
+    {% endfor %}
+
+    // Assignment operators.
+    {{OptionalBoolCppType}}& operator=(const bool& value) {
+        mValue = static_cast<{{OptionalBoolCType}}>(value);
+        return *this;
+    }
+    {{OptionalBoolCppType}}& operator=(const std::optional<bool>& value) {
+        mValue = value ? static_cast<{{OptionalBoolCType}}>(*value) : {{OptionalBoolUndefined}};
+        return *this;
+    }
+    {{OptionalBoolCppType}}& operator=(const {{OptionalBoolCType}}& value) {
+        mValue = value;
+        return *this;
+    }
+
+    // Conversion functions.
+    operator {{OptionalBoolCType}}() const { return mValue; }
+    operator std::optional<bool>() const {
+        if (mValue == {{OptionalBoolUndefined}}) {
+            return std::nullopt;
+        }
+        return static_cast<bool>(mValue);
+    }
+
+    // Comparison functions.
+    bool operator==({{OptionalBoolCType}} rhs) const {
+        return mValue == rhs;
+    }
+    bool operator!=({{OptionalBoolCType}} rhs) const {
+        return mValue != rhs;
+    }
+
+  private:
+    friend struct std::hash<{{OptionalBoolCppType}}>;
+    // Default to undefined.
+    {{OptionalBoolCType}} mValue = {{OptionalBoolUndefined}};
+};
+{% for value in OptionalBool.values %}
+    inline const {{OptionalBoolCppType}} {{OptionalBoolCppType}}::{{as_cppEnum(value.name)}} = {{OptionalBoolCppType}}({{as_cEnum(OptionalBool.name, value.name)}});
+{% endfor %}
+
 // Helper class to wrap Status which allows implicit conversion to bool.
 // Used while callers switch to checking the Status enum instead of booleans.
 // TODO(crbug.com/42241199): Remove when all callers check the enum.
@@ -952,6 +1015,13 @@
         return hash<bool>()(v);
     }
 };
+template <>
+struct hash<{{metadata.namespace}}::{{OptionalBoolCppType}}> {
+  public:
+    size_t operator()(const {{metadata.namespace}}::{{OptionalBoolCppType}} &v) const {
+        return hash<{{OptionalBoolCType}}>()(v.mValue);
+    }
+};
 }  // namespace std
 
 #endif // {{PREFIX}}{{API}}_CPP_H_
diff --git a/generator/templates/api_cpp_print.h b/generator/templates/api_cpp_print.h
index 42d03a3..4c7c84a 100644
--- a/generator/templates/api_cpp_print.h
+++ b/generator/templates/api_cpp_print.h
@@ -39,7 +39,7 @@
 
 namespace {{metadata.namespace}} {
 
-  {% for type in by_category["enum"] %}
+  {% for type in by_category["enum"] if type.name.get() != "optional bool" %}
       template <typename CharT, typename Traits>
       std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& o, {{as_cppType(type.name)}} value) {
           switch (value) {
diff --git a/generator/templates/dawn/native/ValidationUtils.cpp b/generator/templates/dawn/native/ValidationUtils.cpp
index 95dcddd..a7cd252 100644
--- a/generator/templates/dawn/native/ValidationUtils.cpp
+++ b/generator/templates/dawn/native/ValidationUtils.cpp
@@ -36,9 +36,9 @@
     {% set namespace = metadata.namespace %}
     {% for type in by_category["enum"] %}
         MaybeError Validate{{type.name.CamelCase()}}({{namespace}}::{{as_cppType(type.name)}} value) {
-            switch (value) {
+            switch ({{as_cType(type.name)}}(value)) {
                 {% for value in type.values if value.valid %}
-                    case {{namespace}}::{{as_cppType(type.name)}}::{{as_cppEnum(value.name)}}:
+                    case {{as_cEnum(type.name, value.name)}}:
                         return {};
                 {% endfor %}
                 default:
diff --git a/generator/templates/dawn/native/api_absl_format.cpp b/generator/templates/dawn/native/api_absl_format.cpp
index f0fc789..bdac4ad 100644
--- a/generator/templates/dawn/native/api_absl_format.cpp
+++ b/generator/templates/dawn/native/api_absl_format.cpp
@@ -85,9 +85,9 @@
                       absl::FormatSink* s) {
         if (spec.conversion_char() == absl::FormatConversionChar::s) {
             s->Append("{{as_cppType(type.name)}}::");
-            switch (value) {
+            switch ({{as_cType(type.name)}}(value)) {
             {% for value in type.values %}
-                case {{as_cppType(type.name)}}::{{as_cppEnum(value.name)}}:
+                case {{as_cEnum(type.name, value.name)}}:
                     s->Append("{{as_cppEnum(value.name)}}");
                     return {true};
             {% endfor %}
@@ -95,7 +95,7 @@
                 break;
             }
         }
-        s->Append(absl::StrFormat("%u", static_cast<typename std::underlying_type<{{as_cppType(type.name)}}>::type>(value)));
+        s->Append(absl::StrFormat("%u", static_cast<{{as_cType(type.name)}}>(value)));
         return {true};
     }
     {% endfor %}
diff --git a/src/dawn/common/xlib_with_undefs.h b/src/dawn/common/xlib_with_undefs.h
index 6f419e8..9fc2242 100644
--- a/src/dawn/common/xlib_with_undefs.h
+++ b/src/dawn/common/xlib_with_undefs.h
@@ -48,6 +48,8 @@
 #undef Always
 #undef Bool
 #undef Status
+#undef False
+#undef True
 
 using XErrorHandler = int (*)(Display*, XErrorEvent*);
 
diff --git a/src/dawn/dawn.json b/src/dawn/dawn.json
index ad1b051..9ab4fbb 100644
--- a/src/dawn/dawn.json
+++ b/src/dawn/dawn.json
@@ -625,6 +625,14 @@
         "category": "native",
         "wasm type": "i"
     },
+    "optional bool": {
+        "category": "enum",
+        "values": [
+            {"value": 0, "name": "false"},
+            {"value": 1, "name": "true"},
+            {"value": 2, "name": "undefined", "jsrepr": "undefined"}
+        ]
+    },
     "string view": {
         "category": "structure",
         "members": [
@@ -3810,7 +3818,7 @@
         "extensible": "in",
         "members": [
             {"name": "format", "type": "texture format"},
-            {"name": "depth write enabled", "type": "bool", "default": "false"},
+            {"name": "depth write enabled", "type": "optional bool", "default": "undefined"},
             {"name": "depth compare", "type": "compare function", "default": "undefined"},
             {"name": "stencil front", "type": "stencil face state"},
             {"name": "stencil back", "type": "stencil face state"},
diff --git a/src/dawn/native/BlitBufferToDepthStencil.cpp b/src/dawn/native/BlitBufferToDepthStencil.cpp
index c6bf28a..0ecdc89 100644
--- a/src/dawn/native/BlitBufferToDepthStencil.cpp
+++ b/src/dawn/native/BlitBufferToDepthStencil.cpp
@@ -162,7 +162,7 @@
 
     DepthStencilState dsState = {};
     dsState.format = wgpu::TextureFormat::Depth16Unorm;
-    dsState.depthWriteEnabled = true;
+    dsState.depthWriteEnabled = wgpu::OptionalBool::True;
     dsState.depthCompare = wgpu::CompareFunction::Always;
 
     RenderPipelineDescriptor renderPipelineDesc = {};
@@ -226,7 +226,7 @@
 
     DepthStencilState dsState = {};
     dsState.format = format;
-    dsState.depthWriteEnabled = false;
+    dsState.depthWriteEnabled = wgpu::OptionalBool::False;
     dsState.depthCompare = wgpu::CompareFunction::Always;
     dsState.stencilFront.passOp = wgpu::StencilOperation::Replace;
 
diff --git a/src/dawn/native/BlitColorToColorWithDraw.cpp b/src/dawn/native/BlitColorToColorWithDraw.cpp
index 124607b..14566ce 100644
--- a/src/dawn/native/BlitColorToColorWithDraw.cpp
+++ b/src/dawn/native/BlitColorToColorWithDraw.cpp
@@ -171,7 +171,7 @@
     DepthStencilState depthStencilState = {};
     if (pipelineKey.depthStencilFormat != wgpu::TextureFormat::Undefined) {
         depthStencilState.format = pipelineKey.depthStencilFormat;
-        depthStencilState.depthWriteEnabled = false;
+        depthStencilState.depthWriteEnabled = wgpu::OptionalBool::False;
         depthStencilState.depthCompare = wgpu::CompareFunction::Always;
 
         renderPipelineDesc.depthStencil = &depthStencilState;
diff --git a/src/dawn/native/BlitDepthToDepth.cpp b/src/dawn/native/BlitDepthToDepth.cpp
index 79d3da8..c211576 100644
--- a/src/dawn/native/BlitDepthToDepth.cpp
+++ b/src/dawn/native/BlitDepthToDepth.cpp
@@ -87,7 +87,7 @@
 
     DepthStencilState dsState = {};
     dsState.format = format;
-    dsState.depthWriteEnabled = true;
+    dsState.depthWriteEnabled = wgpu::OptionalBool::True;
     dsState.depthCompare = wgpu::CompareFunction::Always;
 
     RenderPipelineDescriptor renderPipelineDesc = {};
diff --git a/src/dawn/native/RenderPipeline.cpp b/src/dawn/native/RenderPipeline.cpp
index 17c02d3..e93a627 100644
--- a/src/dawn/native/RenderPipeline.cpp
+++ b/src/dawn/native/RenderPipeline.cpp
@@ -334,23 +334,19 @@
 
     DAWN_INVALID_IF(
         format->HasDepth() && descriptor->depthCompare == wgpu::CompareFunction::Undefined &&
-            (descriptor->depthWriteEnabled ||
+            (descriptor->depthWriteEnabled == wgpu::OptionalBool::True ||
              descriptor->stencilFront.depthFailOp != wgpu::StencilOperation::Keep ||
              descriptor->stencilBack.depthFailOp != wgpu::StencilOperation::Keep),
         "Depth stencil format (%s) has a depth aspect and depthCompare is %s while it's actually "
-        "used by depthWriteEnabled (%u), or stencil front depth fail operation (%s), or "
+        "used by depthWriteEnabled (%s), or stencil front depth fail operation (%s), or "
         "stencil back depth fail operation (%s).",
         descriptor->format, wgpu::CompareFunction::Undefined, descriptor->depthWriteEnabled,
         descriptor->stencilFront.depthFailOp, descriptor->stencilBack.depthFailOp);
 
-    UnpackedPtr<DepthStencilState> unpacked;
-    DAWN_TRY_ASSIGN(unpacked, ValidateAndUnpack(descriptor));
-    if (const auto* depthWriteDefined = unpacked.Get<DepthStencilStateDepthWriteDefinedDawn>()) {
-        DAWN_INVALID_IF(
-            format->HasDepth() && !depthWriteDefined->depthWriteDefined,
-            "Depth stencil format (%s) has a depth aspect and depthWriteEnabled is undefined.",
-            descriptor->format);
-    }
+    DAWN_INVALID_IF(
+        format->HasDepth() && descriptor->depthWriteEnabled == wgpu::OptionalBool::Undefined,
+        "Depth stencil format (%s) has a depth aspect and depthWriteEnabled is undefined.",
+        descriptor->format);
 
     DAWN_INVALID_IF(
         !format->HasDepth() && descriptor->depthCompare != wgpu::CompareFunction::Always &&
@@ -361,8 +357,9 @@
         wgpu::CompareFunction::Undefined);
 
     DAWN_INVALID_IF(
-        !format->HasDepth() && descriptor->depthWriteEnabled,
-        "Depth stencil format (%s) doesn't have depth aspect while depthWriteEnabled (%u) is true.",
+        !format->HasDepth() && descriptor->depthWriteEnabled == wgpu::OptionalBool::True,
+        "Depth stencil format (%s) doesn't have depth aspect while depthWriteEnabled (%s) "
+        "is true.",
         descriptor->format, descriptor->depthWriteEnabled);
 
     if (!format->HasStencil()) {
@@ -975,16 +972,16 @@
         // Reify depth option for stencil-only formats
         const Format& format = device->GetValidInternalFormat(mDepthStencil.format);
         if (!format.HasDepth()) {
-            mDepthStencil.depthWriteEnabled = false;
+            mDepthStencil.depthWriteEnabled = wgpu::OptionalBool::False;
             mDepthStencil.depthCompare = wgpu::CompareFunction::Always;
         }
         if (format.HasDepth() && mDepthStencil.depthCompare == wgpu::CompareFunction::Undefined &&
-            !mDepthStencil.depthWriteEnabled &&
+            mDepthStencil.depthWriteEnabled != wgpu::OptionalBool::True &&
             mDepthStencil.stencilFront.depthFailOp == wgpu::StencilOperation::Keep &&
             mDepthStencil.stencilBack.depthFailOp == wgpu::StencilOperation::Keep) {
             mDepthStencil.depthCompare = wgpu::CompareFunction::Always;
         }
-        mWritesDepth = mDepthStencil.depthWriteEnabled;
+        mWritesDepth = mDepthStencil.depthWriteEnabled == wgpu::OptionalBool::True;
         if (mDepthStencil.stencilWriteMask) {
             if ((mPrimitive.cullMode != wgpu::CullMode::Front &&
                  (mDepthStencil.stencilFront.failOp != wgpu::StencilOperation::Keep ||
diff --git a/src/dawn/native/d3d11/RenderPipelineD3D11.cpp b/src/dawn/native/d3d11/RenderPipelineD3D11.cpp
index 91fc841..2c86c56 100644
--- a/src/dawn/native/d3d11/RenderPipelineD3D11.cpp
+++ b/src/dawn/native/d3d11/RenderPipelineD3D11.cpp
@@ -405,11 +405,13 @@
     const DepthStencilState* state = GetDepthStencilState();
 
     D3D11_DEPTH_STENCIL_DESC depthStencilDesc = {};
-    depthStencilDesc.DepthEnable =
-        (state->depthCompare == wgpu::CompareFunction::Always && !state->depthWriteEnabled) ? FALSE
-                                                                                            : TRUE;
-    depthStencilDesc.DepthWriteMask =
-        state->depthWriteEnabled ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO;
+    depthStencilDesc.DepthEnable = (state->depthCompare == wgpu::CompareFunction::Always &&
+                                    state->depthWriteEnabled != wgpu::OptionalBool::True)
+                                       ? FALSE
+                                       : TRUE;
+    depthStencilDesc.DepthWriteMask = state->depthWriteEnabled == wgpu::OptionalBool::True
+                                          ? D3D11_DEPTH_WRITE_MASK_ALL
+                                          : D3D11_DEPTH_WRITE_MASK_ZERO;
     depthStencilDesc.DepthFunc = ToD3D11ComparisonFunc(state->depthCompare);
 
     depthStencilDesc.StencilEnable = UsesStencil() ? TRUE : FALSE;
diff --git a/src/dawn/native/d3d12/RenderPipelineD3D12.cpp b/src/dawn/native/d3d12/RenderPipelineD3D12.cpp
index 0784d27..7d727d5 100644
--- a/src/dawn/native/d3d12/RenderPipelineD3D12.cpp
+++ b/src/dawn/native/d3d12/RenderPipelineD3D12.cpp
@@ -555,11 +555,12 @@
     D3D12_DEPTH_STENCIL_DESC depthStencilDescriptor = {};
     depthStencilDescriptor.DepthEnable =
         (descriptor->depthCompare == wgpu::CompareFunction::Always &&
-         !descriptor->depthWriteEnabled)
+         descriptor->depthWriteEnabled != wgpu::OptionalBool::True)
             ? FALSE
             : TRUE;
     depthStencilDescriptor.DepthWriteMask =
-        descriptor->depthWriteEnabled ? D3D12_DEPTH_WRITE_MASK_ALL : D3D12_DEPTH_WRITE_MASK_ZERO;
+        descriptor->depthWriteEnabled == wgpu::OptionalBool::True ? D3D12_DEPTH_WRITE_MASK_ALL
+                                                                  : D3D12_DEPTH_WRITE_MASK_ZERO;
     depthStencilDescriptor.DepthFunc = ToD3D12ComparisonFunc(descriptor->depthCompare);
 
     depthStencilDescriptor.StencilEnable = UsesStencil() ? TRUE : FALSE;
diff --git a/src/dawn/native/metal/RenderPipelineMTL.mm b/src/dawn/native/metal/RenderPipelineMTL.mm
index f0ddef5..51356d1 100644
--- a/src/dawn/native/metal/RenderPipelineMTL.mm
+++ b/src/dawn/native/metal/RenderPipelineMTL.mm
@@ -546,7 +546,8 @@
 
     mtlDepthStencilDescriptor.depthCompareFunction =
         ToMetalCompareFunction(descriptor->depthCompare);
-    mtlDepthStencilDescriptor.depthWriteEnabled = descriptor->depthWriteEnabled;
+    mtlDepthStencilDescriptor.depthWriteEnabled =
+        descriptor->depthWriteEnabled == wgpu::OptionalBool::True;
 
     if (UsesStencil()) {
         NSRef<MTLStencilDescriptor> backFaceStencilRef = AcquireNSRef([MTLStencilDescriptor new]);
diff --git a/src/dawn/native/opengl/RenderPipelineGL.cpp b/src/dawn/native/opengl/RenderPipelineGL.cpp
index 57991a0..cd0387c 100644
--- a/src/dawn/native/opengl/RenderPipelineGL.cpp
+++ b/src/dawn/native/opengl/RenderPipelineGL.cpp
@@ -345,13 +345,13 @@
 
     // Depth writes only occur if depth is enabled
     if (descriptor->depthCompare == wgpu::CompareFunction::Always &&
-        !descriptor->depthWriteEnabled) {
+        descriptor->depthWriteEnabled != wgpu::OptionalBool::True) {
         gl.Disable(GL_DEPTH_TEST);
     } else {
         gl.Enable(GL_DEPTH_TEST);
     }
 
-    if (descriptor->depthWriteEnabled) {
+    if (descriptor->depthWriteEnabled == wgpu::OptionalBool::True) {
         gl.DepthMask(GL_TRUE);
     } else {
         gl.DepthMask(GL_FALSE);
diff --git a/src/dawn/native/vulkan/RenderPipelineVk.cpp b/src/dawn/native/vulkan/RenderPipelineVk.cpp
index b88fbd8..55860c5 100644
--- a/src/dawn/native/vulkan/RenderPipelineVk.cpp
+++ b/src/dawn/native/vulkan/RenderPipelineVk.cpp
@@ -656,10 +656,11 @@
     // Depth writes only occur if depth is enabled
     depthStencilState.depthTestEnable =
         (descriptor->depthCompare == wgpu::CompareFunction::Always &&
-         !descriptor->depthWriteEnabled)
+         descriptor->depthWriteEnabled != wgpu::OptionalBool::True)
             ? VK_FALSE
             : VK_TRUE;
-    depthStencilState.depthWriteEnable = descriptor->depthWriteEnabled ? VK_TRUE : VK_FALSE;
+    depthStencilState.depthWriteEnable =
+        descriptor->depthWriteEnabled == wgpu::OptionalBool::True ? VK_TRUE : VK_FALSE;
     depthStencilState.depthCompareOp = ToVulkanCompareOp(descriptor->depthCompare);
     depthStencilState.depthBoundsTestEnable = false;
     depthStencilState.minDepthBounds = 0.0f;
diff --git a/src/dawn/native/vulkan/ResolveTextureLoadingUtilsVk.cpp b/src/dawn/native/vulkan/ResolveTextureLoadingUtilsVk.cpp
index 6f4cf7c..1bc34c7 100644
--- a/src/dawn/native/vulkan/ResolveTextureLoadingUtilsVk.cpp
+++ b/src/dawn/native/vulkan/ResolveTextureLoadingUtilsVk.cpp
@@ -155,6 +155,7 @@
     DepthStencilState depthStencilState = {};
     if (pipelineKey.depthStencilFormat != wgpu::TextureFormat::Undefined) {
         depthStencilState.format = pipelineKey.depthStencilFormat;
+        depthStencilState.depthWriteEnabled = wgpu::OptionalBool::False;
 
         renderPipelineDesc.depthStencil = &depthStencilState;
     }
diff --git a/src/dawn/node/binding/Converter.cpp b/src/dawn/node/binding/Converter.cpp
index 72e67f4..7234ffe 100644
--- a/src/dawn/node/binding/Converter.cpp
+++ b/src/dawn/node/binding/Converter.cpp
@@ -894,10 +894,6 @@
 bool Converter::Convert(wgpu::DepthStencilState& out, const interop::GPUDepthStencilState& in) {
     out = {};
 
-    auto depthWriteDefined = Allocate<wgpu::DepthStencilStateDepthWriteDefinedDawn>();
-    depthWriteDefined->depthWriteDefined = in.depthWriteEnabled.has_value();
-    out.nextInChain = depthWriteDefined;
-
     return Convert(out.format, in.format) && Convert(out.depthWriteEnabled, in.depthWriteEnabled) &&
            Convert(out.depthCompare, in.depthCompare) &&
            Convert(out.stencilFront, in.stencilFront) && Convert(out.stencilBack, in.stencilBack) &&
@@ -1700,6 +1696,11 @@
     return true;
 }
 
+bool Converter::Convert(wgpu::OptionalBool& out, const std::optional<bool>& in) {
+    out = in;
+    return true;
+}
+
 char* Converter::ConvertStringReplacingNull(std::string_view in) {
     char* out = Allocate<char>(in.size() + 1);
     out[in.size()] = '\0';
diff --git a/src/dawn/node/binding/Converter.h b/src/dawn/node/binding/Converter.h
index 363d076..7eeb76b 100644
--- a/src/dawn/node/binding/Converter.h
+++ b/src/dawn/node/binding/Converter.h
@@ -268,6 +268,7 @@
     [[nodiscard]] bool Convert(wgpu::PipelineLayout& out, const interop::GPUAutoLayoutMode& in);
 
     [[nodiscard]] bool Convert(wgpu::Bool& out, const bool& in);
+    [[nodiscard]] bool Convert(wgpu::OptionalBool& out, const std::optional<bool>& in);
 
     // Below are the various overloads of Convert() used to convert the Dawn types -> interop.
     [[nodiscard]] bool Convert(interop::GPUTextureDimension& out, wgpu::TextureDimension in);
diff --git a/src/dawn/tests/end2end/DepthBiasTests.cpp b/src/dawn/tests/end2end/DepthBiasTests.cpp
index 5966731..43f817b 100644
--- a/src/dawn/tests/end2end/DepthBiasTests.cpp
+++ b/src/dawn/tests/end2end/DepthBiasTests.cpp
@@ -125,7 +125,7 @@
         renderPipelineDesc.vertex.module = vertexModule;
         renderPipelineDesc.cFragment.module = fragmentModule;
         wgpu::DepthStencilState* depthStencil = renderPipelineDesc.EnableDepthStencil(depthFormat);
-        depthStencil->depthWriteEnabled = true;
+        depthStencil->depthWriteEnabled = wgpu::OptionalBool::True;
         depthStencil->depthBias = bias;
         depthStencil->depthBiasSlopeScale = biasSlopeScale;
         depthStencil->depthBiasClamp = biasClamp;
diff --git a/src/dawn/tests/end2end/DepthStencilCopyTests.cpp b/src/dawn/tests/end2end/DepthStencilCopyTests.cpp
index 0cae10b..1eb060e 100644
--- a/src/dawn/tests/end2end/DepthStencilCopyTests.cpp
+++ b/src/dawn/tests/end2end/DepthStencilCopyTests.cpp
@@ -216,7 +216,7 @@
                 @fragment fn main() {}
             )");
         } else {
-            depthStencil->depthWriteEnabled = true;
+            depthStencil->depthWriteEnabled = wgpu::OptionalBool::True;
             renderPipelineDesc.cFragment.module = utils::CreateShaderModule(device, std::string(R"(
                 @fragment fn main() -> @builtin(frag_depth) f32 {
                     return )" + std::to_string(regionDepth) + R"(;
@@ -1109,7 +1109,7 @@
                 renderPipelineDesc.EnableDepthStencil(GetParam().mTextureFormat);
             depthStencil->stencilFront.passOp = wgpu::StencilOperation::DecrementClamp;
             if (!hasDepth) {
-                depthStencil->depthWriteEnabled = false;
+                depthStencil->depthWriteEnabled = wgpu::OptionalBool::False;
                 depthStencil->depthCompare = wgpu::CompareFunction::Always;
             }
 
diff --git a/src/dawn/tests/end2end/DepthStencilSamplingTests.cpp b/src/dawn/tests/end2end/DepthStencilSamplingTests.cpp
index 0f7835d..edbe12f 100644
--- a/src/dawn/tests/end2end/DepthStencilSamplingTests.cpp
+++ b/src/dawn/tests/end2end/DepthStencilSamplingTests.cpp
@@ -690,7 +690,7 @@
     pDesc1.cTargets[0].format = wgpu::TextureFormat::R32Float;
     pDesc1.primitive.topology = wgpu::PrimitiveTopology::PointList;
     pDesc1.EnableDepthStencil(wgpu::TextureFormat::Depth24PlusStencil8);
-    pDesc1.cDepthStencil.depthWriteEnabled = true;
+    pDesc1.cDepthStencil.depthWriteEnabled = wgpu::OptionalBool::True;
     wgpu::RenderPipeline pipeline1 = device.CreateRenderPipeline(&pDesc1);
 
     // The second pipeline checks the depth texture and outputs 1 to a texel on success.
diff --git a/src/dawn/tests/end2end/DepthStencilStateTests.cpp b/src/dawn/tests/end2end/DepthStencilStateTests.cpp
index 2071920..bca6738 100644
--- a/src/dawn/tests/end2end/DepthStencilStateTests.cpp
+++ b/src/dawn/tests/end2end/DepthStencilStateTests.cpp
@@ -126,7 +126,7 @@
         stencilFace.passOp = wgpu::StencilOperation::Keep;
 
         wgpu::DepthStencilState baseState;
-        baseState.depthWriteEnabled = true;
+        baseState.depthWriteEnabled = wgpu::OptionalBool::True;
         baseState.depthCompare = wgpu::CompareFunction::Always;
         baseState.stencilBack = stencilFace;
         baseState.stencilFront = stencilFace;
@@ -134,7 +134,7 @@
         baseState.stencilWriteMask = 0xff;
 
         wgpu::DepthStencilState state;
-        state.depthWriteEnabled = true;
+        state.depthWriteEnabled = wgpu::OptionalBool::True;
         state.depthCompare = compareFunction;
         state.stencilBack = stencilFace;
         state.stencilFront = stencilFace;
@@ -175,7 +175,7 @@
         baseStencilFaceDescriptor.depthFailOp = wgpu::StencilOperation::Keep;
         baseStencilFaceDescriptor.passOp = wgpu::StencilOperation::Replace;
         wgpu::DepthStencilState baseState;
-        baseState.depthWriteEnabled = false;
+        baseState.depthWriteEnabled = wgpu::OptionalBool::False;
         baseState.depthCompare = wgpu::CompareFunction::Always;
         baseState.stencilBack = baseStencilFaceDescriptor;
         baseState.stencilFront = baseStencilFaceDescriptor;
@@ -188,7 +188,7 @@
         stencilFaceDescriptor.depthFailOp = wgpu::StencilOperation::Keep;
         stencilFaceDescriptor.passOp = wgpu::StencilOperation::Keep;
         wgpu::DepthStencilState state;
-        state.depthWriteEnabled = false;
+        state.depthWriteEnabled = wgpu::OptionalBool::False;
         state.depthCompare = wgpu::CompareFunction::Always;
         state.stencilBack = stencilFaceDescriptor;
         state.stencilFront = stencilFaceDescriptor;
@@ -228,7 +228,7 @@
         baseStencilFaceDescriptor.depthFailOp = wgpu::StencilOperation::Keep;
         baseStencilFaceDescriptor.passOp = wgpu::StencilOperation::Replace;
         wgpu::DepthStencilState baseState;
-        baseState.depthWriteEnabled = false;
+        baseState.depthWriteEnabled = wgpu::OptionalBool::False;
         baseState.depthCompare = wgpu::CompareFunction::Always;
         baseState.stencilBack = baseStencilFaceDescriptor;
         baseState.stencilFront = baseStencilFaceDescriptor;
@@ -241,7 +241,7 @@
         stencilFaceDescriptor.depthFailOp = wgpu::StencilOperation::Keep;
         stencilFaceDescriptor.passOp = stencilOperation;
         wgpu::DepthStencilState state;
-        state.depthWriteEnabled = false;
+        state.depthWriteEnabled = wgpu::OptionalBool::False;
         state.depthCompare = wgpu::CompareFunction::Always;
         state.stencilBack = stencilFaceDescriptor;
         state.stencilFront = stencilFaceDescriptor;
@@ -267,7 +267,7 @@
         stencilFaceDescriptor.depthFailOp = wgpu::StencilOperation::Keep;
         stencilFaceDescriptor.passOp = wgpu::StencilOperation::Keep;
         wgpu::DepthStencilState state;
-        state.depthWriteEnabled = false;
+        state.depthWriteEnabled = wgpu::OptionalBool::False;
         state.depthCompare = wgpu::CompareFunction::Always;
         state.stencilBack = stencilFaceDescriptor;
         state.stencilFront = stencilFaceDescriptor;
@@ -394,7 +394,7 @@
     stencilFace.passOp = wgpu::StencilOperation::Undefined;
 
     wgpu::DepthStencilState state;
-    state.depthWriteEnabled = false;
+    state.depthWriteEnabled = wgpu::OptionalBool::False;
     state.depthCompare = wgpu::CompareFunction::Always;
     state.stencilBack = stencilFace;
     state.stencilFront = stencilFace;
@@ -417,7 +417,7 @@
     stencilFace.passOp = wgpu::StencilOperation::Keep;
 
     wgpu::DepthStencilState state;
-    state.depthWriteEnabled = false;
+    state.depthWriteEnabled = wgpu::OptionalBool::False;
     state.depthCompare = wgpu::CompareFunction::Always;
     state.stencilBack = stencilFace;
     state.stencilFront = stencilFace;
@@ -482,7 +482,7 @@
     stencilFace.passOp = wgpu::StencilOperation::Keep;
 
     wgpu::DepthStencilState baseState;
-    baseState.depthWriteEnabled = true;
+    baseState.depthWriteEnabled = wgpu::OptionalBool::True;
     baseState.depthCompare = wgpu::CompareFunction::Always;
     baseState.stencilBack = stencilFace;
     baseState.stencilFront = stencilFace;
@@ -490,7 +490,7 @@
     baseState.stencilWriteMask = 0xff;
 
     wgpu::DepthStencilState noDepthWrite;
-    noDepthWrite.depthWriteEnabled = false;
+    noDepthWrite.depthWriteEnabled = wgpu::OptionalBool::False;
     noDepthWrite.depthCompare = wgpu::CompareFunction::Always;
     noDepthWrite.stencilBack = stencilFace;
     noDepthWrite.stencilFront = stencilFace;
@@ -498,7 +498,7 @@
     noDepthWrite.stencilWriteMask = 0xff;
 
     wgpu::DepthStencilState checkState;
-    checkState.depthWriteEnabled = false;
+    checkState.depthWriteEnabled = wgpu::OptionalBool::False;
     checkState.depthCompare = wgpu::CompareFunction::Equal;
     checkState.stencilBack = stencilFace;
     checkState.stencilFront = stencilFace;
@@ -596,7 +596,7 @@
     baseStencilFaceDescriptor.depthFailOp = wgpu::StencilOperation::Keep;
     baseStencilFaceDescriptor.passOp = wgpu::StencilOperation::Replace;
     wgpu::DepthStencilState baseState;
-    baseState.depthWriteEnabled = false;
+    baseState.depthWriteEnabled = wgpu::OptionalBool::False;
     baseState.depthCompare = wgpu::CompareFunction::Always;
     baseState.stencilBack = baseStencilFaceDescriptor;
     baseState.stencilFront = baseStencilFaceDescriptor;
@@ -609,7 +609,7 @@
     stencilFaceDescriptor.depthFailOp = wgpu::StencilOperation::Keep;
     stencilFaceDescriptor.passOp = wgpu::StencilOperation::Keep;
     wgpu::DepthStencilState state;
-    state.depthWriteEnabled = false;
+    state.depthWriteEnabled = wgpu::OptionalBool::False;
     state.depthCompare = wgpu::CompareFunction::Always;
     state.stencilBack = stencilFaceDescriptor;
     state.stencilFront = stencilFaceDescriptor;
@@ -635,7 +635,7 @@
     baseStencilFaceDescriptor.depthFailOp = wgpu::StencilOperation::Keep;
     baseStencilFaceDescriptor.passOp = wgpu::StencilOperation::Replace;
     wgpu::DepthStencilState baseState;
-    baseState.depthWriteEnabled = false;
+    baseState.depthWriteEnabled = wgpu::OptionalBool::False;
     baseState.depthCompare = wgpu::CompareFunction::Always;
     baseState.stencilBack = baseStencilFaceDescriptor;
     baseState.stencilFront = baseStencilFaceDescriptor;
@@ -648,7 +648,7 @@
     stencilFaceDescriptor.depthFailOp = wgpu::StencilOperation::Keep;
     stencilFaceDescriptor.passOp = wgpu::StencilOperation::Keep;
     wgpu::DepthStencilState state;
-    state.depthWriteEnabled = false;
+    state.depthWriteEnabled = wgpu::OptionalBool::False;
     state.depthCompare = wgpu::CompareFunction::Always;
     state.stencilBack = stencilFaceDescriptor;
     state.stencilFront = stencilFaceDescriptor;
@@ -674,7 +674,7 @@
     baseStencilFaceDescriptor.depthFailOp = wgpu::StencilOperation::Keep;
     baseStencilFaceDescriptor.passOp = wgpu::StencilOperation::Replace;
     wgpu::DepthStencilState baseState;
-    baseState.depthWriteEnabled = false;
+    baseState.depthWriteEnabled = wgpu::OptionalBool::False;
     baseState.depthCompare = wgpu::CompareFunction::Always;
     baseState.stencilBack = baseStencilFaceDescriptor;
     baseState.stencilFront = baseStencilFaceDescriptor;
@@ -687,7 +687,7 @@
     stencilFaceDescriptor.depthFailOp = wgpu::StencilOperation::Keep;
     stencilFaceDescriptor.passOp = wgpu::StencilOperation::Keep;
     wgpu::DepthStencilState state;
-    state.depthWriteEnabled = false;
+    state.depthWriteEnabled = wgpu::OptionalBool::False;
     state.depthCompare = wgpu::CompareFunction::Always;
     state.stencilBack = stencilFaceDescriptor;
     state.stencilFront = stencilFaceDescriptor;
@@ -712,7 +712,7 @@
     baseStencilFaceDescriptor.depthFailOp = wgpu::StencilOperation::Keep;
     baseStencilFaceDescriptor.passOp = wgpu::StencilOperation::Replace;
     wgpu::DepthStencilState baseState;
-    baseState.depthWriteEnabled = true;
+    baseState.depthWriteEnabled = wgpu::OptionalBool::True;
     baseState.depthCompare = wgpu::CompareFunction::Always;
     baseState.stencilBack = baseStencilFaceDescriptor;
     baseState.stencilFront = baseStencilFaceDescriptor;
@@ -725,7 +725,7 @@
     stencilFaceDescriptor.depthFailOp = wgpu::StencilOperation::Replace;
     stencilFaceDescriptor.passOp = wgpu::StencilOperation::Keep;
     wgpu::DepthStencilState state;
-    state.depthWriteEnabled = true;
+    state.depthWriteEnabled = wgpu::OptionalBool::True;
     state.depthCompare = wgpu::CompareFunction::Less;
     state.stencilBack = stencilFaceDescriptor;
     state.stencilFront = stencilFaceDescriptor;
@@ -748,7 +748,7 @@
     baseStencilFaceDescriptor.depthFailOp = wgpu::StencilOperation::Keep;
     baseStencilFaceDescriptor.passOp = wgpu::StencilOperation::Replace;
     wgpu::DepthStencilState baseState;
-    baseState.depthWriteEnabled = true;
+    baseState.depthWriteEnabled = wgpu::OptionalBool::True;
     baseState.depthCompare = wgpu::CompareFunction::Always;
     baseState.stencilBack = baseStencilFaceDescriptor;
     baseState.stencilFront = baseStencilFaceDescriptor;
@@ -761,7 +761,7 @@
     stencilFaceDescriptor.depthFailOp = wgpu::StencilOperation::Keep;
     stencilFaceDescriptor.passOp = wgpu::StencilOperation::Replace;
     wgpu::DepthStencilState state;
-    state.depthWriteEnabled = true;
+    state.depthWriteEnabled = wgpu::OptionalBool::True;
     state.depthCompare = wgpu::CompareFunction::Less;
     state.stencilBack = stencilFaceDescriptor;
     state.stencilFront = stencilFaceDescriptor;
@@ -798,7 +798,7 @@
 // Test that the front and back stencil states are set correctly (and take frontFace into account)
 TEST_P(DepthStencilStateTest, StencilFrontAndBackFace) {
     wgpu::DepthStencilState state;
-    state.depthWriteEnabled = false;
+    state.depthWriteEnabled = wgpu::OptionalBool::False;
     state.depthCompare = wgpu::CompareFunction::Always;
     state.stencilFront.compare = wgpu::CompareFunction::Always;
     state.stencilBack.compare = wgpu::CompareFunction::Never;
@@ -813,7 +813,7 @@
 // Test that the depth reference of a new render pass is initialized to default value 0
 TEST_P(DepthStencilStateTest, StencilReferenceInitialized) {
     wgpu::DepthStencilState stencilAlwaysReplaceState;
-    stencilAlwaysReplaceState.depthWriteEnabled = false;
+    stencilAlwaysReplaceState.depthWriteEnabled = wgpu::OptionalBool::False;
     stencilAlwaysReplaceState.depthCompare = wgpu::CompareFunction::Always;
     stencilAlwaysReplaceState.stencilFront.compare = wgpu::CompareFunction::Always;
     stencilAlwaysReplaceState.stencilFront.passOp = wgpu::StencilOperation::Replace;
@@ -821,7 +821,7 @@
     stencilAlwaysReplaceState.stencilBack.passOp = wgpu::StencilOperation::Replace;
 
     wgpu::DepthStencilState stencilEqualKeepState;
-    stencilEqualKeepState.depthWriteEnabled = false;
+    stencilEqualKeepState.depthWriteEnabled = wgpu::OptionalBool::False;
     stencilEqualKeepState.depthCompare = wgpu::CompareFunction::Always;
     stencilEqualKeepState.stencilFront.compare = wgpu::CompareFunction::Equal;
     stencilEqualKeepState.stencilFront.passOp = wgpu::StencilOperation::Keep;
diff --git a/src/dawn/tests/end2end/FragDepthTests.cpp b/src/dawn/tests/end2end/FragDepthTests.cpp
index 9af0533..fb490b9 100644
--- a/src/dawn/tests/end2end/FragDepthTests.cpp
+++ b/src/dawn/tests/end2end/FragDepthTests.cpp
@@ -56,7 +56,7 @@
     pDesc.cFragment.targetCount = 0;
 
     wgpu::DepthStencilState* pDescDS = pDesc.EnableDepthStencil(kDepthFormat);
-    pDescDS->depthWriteEnabled = true;
+    pDescDS->depthWriteEnabled = wgpu::OptionalBool::True;
     pDescDS->depthCompare = wgpu::CompareFunction::Always;
     wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&pDesc);
 
@@ -119,7 +119,7 @@
     upDesc.cFragment.targetCount = 0;
 
     wgpu::DepthStencilState* upDescDS = upDesc.EnableDepthStencil(kDepthFormat);
-    upDescDS->depthWriteEnabled = true;
+    upDescDS->depthWriteEnabled = wgpu::OptionalBool::True;
     upDescDS->depthCompare = wgpu::CompareFunction::Always;
     wgpu::RenderPipeline uniformPipeline = device.CreateRenderPipeline(&upDesc);
 
@@ -137,7 +137,7 @@
     spDesc.cFragment.targetCount = 0;
 
     wgpu::DepthStencilState* spDescDS = spDesc.EnableDepthStencil(kDepthFormat);
-    spDescDS->depthWriteEnabled = true;
+    spDescDS->depthWriteEnabled = wgpu::OptionalBool::True;
     spDescDS->depthCompare = wgpu::CompareFunction::Always;
     wgpu::RenderPipeline storagePipeline = device.CreateRenderPipeline(&spDesc);
 
@@ -203,7 +203,7 @@
     pDesc.cFragment.targetCount = 0;
 
     wgpu::DepthStencilState* pDescDS = pDesc.EnableDepthStencil(kDepthFormat);
-    pDescDS->depthWriteEnabled = true;
+    pDescDS->depthWriteEnabled = wgpu::OptionalBool::True;
     pDescDS->depthCompare = wgpu::CompareFunction::Always;
     wgpu::RenderPipeline uniformPipeline = device.CreateRenderPipeline(&pDesc);
 
diff --git a/src/dawn/tests/end2end/MultisampledRenderingTests.cpp b/src/dawn/tests/end2end/MultisampledRenderingTests.cpp
index 97ba108..9cdd67e 100644
--- a/src/dawn/tests/end2end/MultisampledRenderingTests.cpp
+++ b/src/dawn/tests/end2end/MultisampledRenderingTests.cpp
@@ -334,7 +334,7 @@
         if (hasDepthStencilAttachment) {
             wgpu::DepthStencilState* depthStencil =
                 pipelineDescriptor.EnableDepthStencil(kDepthStencilFormat);
-            depthStencil->depthWriteEnabled = true;
+            depthStencil->depthWriteEnabled = wgpu::OptionalBool::True;
             depthStencil->depthCompare = wgpu::CompareFunction::Less;
         }
 
diff --git a/src/dawn/tests/end2end/MultisampledSamplingTests.cpp b/src/dawn/tests/end2end/MultisampledSamplingTests.cpp
index 39b60b3..3c8ca16 100644
--- a/src/dawn/tests/end2end/MultisampledSamplingTests.cpp
+++ b/src/dawn/tests/end2end/MultisampledSamplingTests.cpp
@@ -93,7 +93,7 @@
             desc.cAttributes[0].format = wgpu::VertexFormat::Float32x2;
 
             wgpu::DepthStencilState* depthStencil = desc.EnableDepthStencil(kDepthFormat);
-            depthStencil->depthWriteEnabled = true;
+            depthStencil->depthWriteEnabled = wgpu::OptionalBool::True;
 
             desc.multisample.count = kSampleCount;
             desc.cFragment.targetCount = 1;
diff --git a/src/dawn/tests/end2end/PrimitiveStateTests.cpp b/src/dawn/tests/end2end/PrimitiveStateTests.cpp
index 154bcf2..284c9c1 100644
--- a/src/dawn/tests/end2end/PrimitiveStateTests.cpp
+++ b/src/dawn/tests/end2end/PrimitiveStateTests.cpp
@@ -132,7 +132,7 @@
             descriptor.vertex.module = vsModule;
             descriptor.cFragment.module = fsModule;
             wgpu::DepthStencilState* depthStencil = descriptor.EnableDepthStencil();
-            depthStencil->depthWriteEnabled = true;
+            depthStencil->depthWriteEnabled = wgpu::OptionalBool::True;
             depthStencil->format = wgpu::TextureFormat::Depth24PlusStencil8;
 
             wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&descriptor);
@@ -312,7 +312,7 @@
             return vec4f(frag_pos.z / 4.0, 0.0, 0.0, 1.0);
         })");
     wgpu::DepthStencilState* depthStencil = descriptor.EnableDepthStencil();
-    depthStencil->depthWriteEnabled = true;
+    depthStencil->depthWriteEnabled = wgpu::OptionalBool::True;
     depthStencil->format = wgpu::TextureFormat::Depth24PlusStencil8;
 
     wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&descriptor);
diff --git a/src/dawn/tests/end2end/ReadOnlyDepthStencilAttachmentTests.cpp b/src/dawn/tests/end2end/ReadOnlyDepthStencilAttachmentTests.cpp
index 6b7b535..1237c5b 100644
--- a/src/dawn/tests/end2end/ReadOnlyDepthStencilAttachmentTests.cpp
+++ b/src/dawn/tests/end2end/ReadOnlyDepthStencilAttachmentTests.cpp
@@ -70,7 +70,7 @@
 
         wgpu::CompareFunction depthCompare = wgpu::CompareFunction::Always;
         wgpu::CompareFunction stencilCompare = wgpu::CompareFunction::Always;
-        bool depthWriteEnabled = false;
+        wgpu::OptionalBool depthWriteEnabled = wgpu::OptionalBool::False;
         bool stencilWriteEnabled = false;
 
         float depthClearValue = 0.0;
@@ -395,7 +395,7 @@
     spec1.stencilClearValue = 42;
     spec1.depthClearValue = 0.2;
     spec1.depthCompare = wgpu::CompareFunction::LessEqual;
-    spec1.depthWriteEnabled = true;
+    spec1.depthWriteEnabled = wgpu::OptionalBool::True;
     auto render1 = DoRender(spec1);
 
     // Stencil was read successfully, but only in the bottom part.
diff --git a/src/dawn/tests/end2end/ShaderTests.cpp b/src/dawn/tests/end2end/ShaderTests.cpp
index 05974b5..a5309c0 100644
--- a/src/dawn/tests/end2end/ShaderTests.cpp
+++ b/src/dawn/tests/end2end/ShaderTests.cpp
@@ -2198,7 +2198,7 @@
     desc.cFragment.module = module;
     desc.cFragment.targetCount = 0;
     wgpu::DepthStencilState* dsState = desc.EnableDepthStencil();
-    dsState->depthWriteEnabled = true;
+    dsState->depthWriteEnabled = wgpu::OptionalBool::True;
     dsState->depthCompare = wgpu::CompareFunction::Always;
 
     device.CreateRenderPipeline(&desc);
diff --git a/src/dawn/tests/end2end/VertexOnlyRenderPipelineTests.cpp b/src/dawn/tests/end2end/VertexOnlyRenderPipelineTests.cpp
index 22ebed9..3118c4d 100644
--- a/src/dawn/tests/end2end/VertexOnlyRenderPipelineTests.cpp
+++ b/src/dawn/tests/end2end/VertexOnlyRenderPipelineTests.cpp
@@ -90,32 +90,32 @@
         // ignore the stencil component
         depthPipelineNoFragment =
             CreateRenderPipeline(wgpu::CompareFunction::Always, wgpu::StencilOperation::Keep,
-                                 wgpu::CompareFunction::Always, true, false);
+                                 wgpu::CompareFunction::Always, wgpu::OptionalBool::True, false);
         depthPipelineWithFragment =
             CreateRenderPipeline(wgpu::CompareFunction::Always, wgpu::StencilOperation::Keep,
-                                 wgpu::CompareFunction::Always, true, true);
+                                 wgpu::CompareFunction::Always, wgpu::OptionalBool::True, true);
 
         // Create a vertex-only render pipeline that only modify the stencil in DepthStencilView,
         // and ignore the depth component
         stencilPipelineNoFragment =
             CreateRenderPipeline(wgpu::CompareFunction::Always, wgpu::StencilOperation::Replace,
-                                 wgpu::CompareFunction::Always, false, false);
+                                 wgpu::CompareFunction::Always, wgpu::OptionalBool::False, false);
         stencilPipelineWithFragment =
             CreateRenderPipeline(wgpu::CompareFunction::Always, wgpu::StencilOperation::Replace,
-                                 wgpu::CompareFunction::Always, false, true);
+                                 wgpu::CompareFunction::Always, wgpu::OptionalBool::False, true);
 
         // Create a complete render pipeline that do both depth and stencil tests, and draw to color
         // attachment
-        fullPipeline =
-            CreateRenderPipeline(wgpu::CompareFunction::Equal, wgpu::StencilOperation::Keep,
-                                 wgpu::CompareFunction::GreaterEqual, false, true);
+        fullPipeline = CreateRenderPipeline(
+            wgpu::CompareFunction::Equal, wgpu::StencilOperation::Keep,
+            wgpu::CompareFunction::GreaterEqual, wgpu::OptionalBool::False, true);
     }
 
     wgpu::RenderPipeline CreateRenderPipeline(
         wgpu::CompareFunction stencilCompare = wgpu::CompareFunction::Always,
         wgpu::StencilOperation stencilPassOp = wgpu::StencilOperation::Keep,
         wgpu::CompareFunction depthCompare = wgpu::CompareFunction::Always,
-        bool writeDepth = false,
+        wgpu::OptionalBool writeDepth = wgpu::OptionalBool::False,
         bool useFragment = true) {
         wgpu::ShaderModule vsModule = utils::CreateShaderModule(device, R"(
             @vertex
diff --git a/src/dawn/tests/end2end/ViewportTests.cpp b/src/dawn/tests/end2end/ViewportTests.cpp
index 2d6049b..11df069 100644
--- a/src/dawn/tests/end2end/ViewportTests.cpp
+++ b/src/dawn/tests/end2end/ViewportTests.cpp
@@ -122,7 +122,7 @@
         pipelineDesc.primitive.topology = wgpu::PrimitiveTopology::PointList;
         wgpu::DepthStencilState* depthStencil =
             pipelineDesc.EnableDepthStencil(wgpu::TextureFormat::Depth32Float);
-        depthStencil->depthWriteEnabled = true;
+        depthStencil->depthWriteEnabled = wgpu::OptionalBool::True;
         wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&pipelineDesc);
 
         // Create the texture that will store the post-viewport-transform depth.
diff --git a/src/dawn/tests/unittests/validation/CompatValidationTests.cpp b/src/dawn/tests/unittests/validation/CompatValidationTests.cpp
index 48a1cb2..9280c2b 100644
--- a/src/dawn/tests/unittests/validation/CompatValidationTests.cpp
+++ b/src/dawn/tests/unittests/validation/CompatValidationTests.cpp
@@ -202,7 +202,7 @@
 
     wgpu::DepthStencilState* depthStencil =
         testDescriptor.EnableDepthStencil(wgpu::TextureFormat::Depth24Plus);
-    depthStencil->depthWriteEnabled = true;
+    depthStencil->depthWriteEnabled = wgpu::OptionalBool::True;
     depthStencil->depthBias = 0;
     depthStencil->depthBiasSlopeScale = 0;
 
diff --git a/src/dawn/tests/unittests/validation/PipelineAndPassCompatibilityTests.cpp b/src/dawn/tests/unittests/validation/PipelineAndPassCompatibilityTests.cpp
index 32ba3f7..0e36142 100644
--- a/src/dawn/tests/unittests/validation/PipelineAndPassCompatibilityTests.cpp
+++ b/src/dawn/tests/unittests/validation/PipelineAndPassCompatibilityTests.cpp
@@ -59,7 +59,7 @@
         // Enable depth/stencil write if needed
         wgpu::DepthStencilState* depthStencil = pipelineDescriptor.EnableDepthStencil(format);
         if (enableDepthWrite) {
-            depthStencil->depthWriteEnabled = true;
+            depthStencil->depthWriteEnabled = wgpu::OptionalBool::True;
         }
         if (enableStencilWrite) {
             depthStencil->stencilFront.failOp = wgpu::StencilOperation::Replace;
diff --git a/src/dawn/tests/unittests/validation/RenderPipelineValidationTests.cpp b/src/dawn/tests/unittests/validation/RenderPipelineValidationTests.cpp
index d14f8ac..439c6a9 100644
--- a/src/dawn/tests/unittests/validation/RenderPipelineValidationTests.cpp
+++ b/src/dawn/tests/unittests/validation/RenderPipelineValidationTests.cpp
@@ -292,7 +292,7 @@
         wgpu::DepthStencilState* depthStencil =
             descriptor.EnableDepthStencil(wgpu::TextureFormat::Depth24PlusStencil8);
         depthStencil->depthCompare = wgpu::CompareFunction::LessEqual;
-        depthStencil->depthWriteEnabled = true;
+        depthStencil->depthWriteEnabled = wgpu::OptionalBool::True;
         device.CreateRenderPipeline(&descriptor);
     }
 
@@ -305,7 +305,7 @@
         wgpu::DepthStencilState* depthStencil =
             descriptor.EnableDepthStencil(wgpu::TextureFormat::Stencil8);
         depthStencil->depthCompare = wgpu::CompareFunction::LessEqual;
-        depthStencil->depthWriteEnabled = false;
+        depthStencil->depthWriteEnabled = wgpu::OptionalBool::False;
         ASSERT_DEVICE_ERROR(device.CreateRenderPipeline(&descriptor));
     }
 
@@ -318,7 +318,7 @@
         wgpu::DepthStencilState* depthStencil =
             descriptor.EnableDepthStencil(wgpu::TextureFormat::Stencil8);
         depthStencil->depthCompare = wgpu::CompareFunction::Undefined;
-        depthStencil->depthWriteEnabled = true;
+        depthStencil->depthWriteEnabled = wgpu::OptionalBool::True;
         ASSERT_DEVICE_ERROR(device.CreateRenderPipeline(&descriptor));
     }
 }
@@ -1363,7 +1363,7 @@
     descriptor.vertex.module = vsModule;
     descriptor.cFragment.module = fsModule;
 
-    descriptor.cDepthStencil.depthWriteEnabled = true;
+    descriptor.cDepthStencil.depthWriteEnabled = wgpu::OptionalBool::True;
     descriptor.EnableDepthStencil(wgpu::TextureFormat::Depth32Float);
 
     // Control case: Always is valid for format with depth.
@@ -1375,30 +1375,30 @@
     ASSERT_DEVICE_ERROR(device.CreateRenderPipeline(&descriptor));
 
     // Undefined is valid though if depthCompare is not used by anything.
-    descriptor.cDepthStencil.depthWriteEnabled = false;
+    descriptor.cDepthStencil.depthWriteEnabled = wgpu::OptionalBool::False;
     descriptor.cDepthStencil.stencilFront.depthFailOp = wgpu::StencilOperation::Keep;
     descriptor.cDepthStencil.stencilBack.depthFailOp = wgpu::StencilOperation::Keep;
     device.CreateRenderPipeline(&descriptor);
 
     // Undefined is invalid if depthCompare is used by depthWriteEnabled.
-    descriptor.cDepthStencil.depthWriteEnabled = true;
+    descriptor.cDepthStencil.depthWriteEnabled = wgpu::OptionalBool::True;
     descriptor.cDepthStencil.stencilFront.depthFailOp = wgpu::StencilOperation::Keep;
     descriptor.cDepthStencil.stencilBack.depthFailOp = wgpu::StencilOperation::Keep;
     ASSERT_DEVICE_ERROR(device.CreateRenderPipeline(&descriptor));
 
     // Undefined is invalid if depthCompare is used by stencilFront.depthFailOp.
-    descriptor.cDepthStencil.depthWriteEnabled = false;
+    descriptor.cDepthStencil.depthWriteEnabled = wgpu::OptionalBool::False;
     descriptor.cDepthStencil.stencilFront.depthFailOp = wgpu::StencilOperation::Zero;
     descriptor.cDepthStencil.stencilBack.depthFailOp = wgpu::StencilOperation::Keep;
     ASSERT_DEVICE_ERROR(device.CreateRenderPipeline(&descriptor));
 
     // Undefined is invalid if depthCompare is used by stencilBack.depthFailOp.
-    descriptor.cDepthStencil.depthWriteEnabled = false;
+    descriptor.cDepthStencil.depthWriteEnabled = wgpu::OptionalBool::False;
     descriptor.cDepthStencil.stencilFront.depthFailOp = wgpu::StencilOperation::Keep;
     descriptor.cDepthStencil.stencilBack.depthFailOp = wgpu::StencilOperation::Zero;
     ASSERT_DEVICE_ERROR(device.CreateRenderPipeline(&descriptor));
 
-    descriptor.cDepthStencil.depthWriteEnabled = false;
+    descriptor.cDepthStencil.depthWriteEnabled = wgpu::OptionalBool::False;
     descriptor.cDepthStencil.stencilFront.depthFailOp = wgpu::StencilOperation::Keep;
     descriptor.cDepthStencil.stencilBack.depthFailOp = wgpu::StencilOperation::Keep;
     descriptor.EnableDepthStencil(wgpu::TextureFormat::Stencil8);
@@ -1423,32 +1423,35 @@
         descriptor.EnableDepthStencil(wgpu::TextureFormat::Depth32Float);
 
     // Control case: Set depthWriteEnabled to false for format with depth.
-    depthStencil->depthWriteEnabled = false;
+    depthStencil->depthWriteEnabled = wgpu::OptionalBool::False;
     device.CreateRenderPipeline(&descriptor);
 
-    // When DepthStencilStateDepthWriteDefinedDawn struct is chained, depthWriteEnabled is now
-    // considered optional and depthWriteDefined needs to be true for formats with depth only.
-    wgpu::DepthStencilStateDepthWriteDefinedDawn depthWriteDefined;
     depthStencil = descriptor.EnableDepthStencil(wgpu::TextureFormat::Stencil8);
-    depthStencil->nextInChain = &depthWriteDefined;
 
-    // depthWriteDefined set to true is valid for format with no depth.
-    depthWriteDefined.depthWriteDefined = true;
+    // depthWriteEnabled set to undefined is valid for format with no depth.
+    depthStencil->depthWriteEnabled = wgpu::OptionalBool::Undefined;
     device.CreateRenderPipeline(&descriptor);
 
-    // depthWriteDefined set to false is valid for format with no depth.
-    depthWriteDefined.depthWriteDefined = false;
+    // depthWriteEnabled set to false is valid for format with no depth.
+    depthStencil->depthWriteEnabled = wgpu::OptionalBool::False;
     device.CreateRenderPipeline(&descriptor);
 
+    // Error case: depthWriteEnabled set to true is invalid for format with no depth.
+    depthStencil->depthWriteEnabled = wgpu::OptionalBool::True;
+    ASSERT_DEVICE_ERROR(device.CreateRenderPipeline(&descriptor));
+
     depthStencil = descriptor.EnableDepthStencil(wgpu::TextureFormat::Depth32Float);
-    depthStencil->nextInChain = &depthWriteDefined;
 
-    // depthWriteDefined set to true is valid for format with depth.
-    depthWriteDefined.depthWriteDefined = true;
+    // depthWriteEnabled set to false is valid for format with depth.
+    depthStencil->depthWriteEnabled = wgpu::OptionalBool::False;
     device.CreateRenderPipeline(&descriptor);
 
-    // Error case: depthWriteDefined set to false is invalid for format with depth.
-    depthWriteDefined.depthWriteDefined = false;
+    // depthWriteEnabled set to true is valid for format with depth.
+    depthStencil->depthWriteEnabled = wgpu::OptionalBool::True;
+    device.CreateRenderPipeline(&descriptor);
+
+    // Error case: depthWriteEnabled set to undefined is invalid for format with depth.
+    depthStencil->depthWriteEnabled = wgpu::OptionalBool::Undefined;
     ASSERT_DEVICE_ERROR(device.CreateRenderPipeline(&descriptor));
 }
 
diff --git a/src/dawn/tests/unittests/wire/WireOptionalTests.cpp b/src/dawn/tests/unittests/wire/WireOptionalTests.cpp
index 078e42d..159d0c2 100644
--- a/src/dawn/tests/unittests/wire/WireOptionalTests.cpp
+++ b/src/dawn/tests/unittests/wire/WireOptionalTests.cpp
@@ -108,7 +108,7 @@
 
     wgpu::DepthStencilState depthStencilState = {};
     depthStencilState.format = wgpu::TextureFormat::Depth24PlusStencil8;
-    depthStencilState.depthWriteEnabled = false;
+    depthStencilState.depthWriteEnabled = wgpu::OptionalBool::False;
     depthStencilState.depthCompare = wgpu::CompareFunction::Always;
     depthStencilState.stencilBack = stencilFace;
     depthStencilState.stencilFront = stencilFace;
@@ -158,7 +158,7 @@
             apiDevice, MatchesLambda([](const WGPURenderPipelineDescriptor* desc) -> bool {
                 return desc->depthStencil != nullptr &&
                        desc->depthStencil->nextInChain == nullptr &&
-                       desc->depthStencil->depthWriteEnabled == false &&
+                       desc->depthStencil->depthWriteEnabled == WGPUOptionalBool_False &&
                        desc->depthStencil->depthCompare == WGPUCompareFunction_Always &&
                        desc->depthStencil->stencilBack.compare == WGPUCompareFunction_Always &&
                        desc->depthStencil->stencilBack.failOp == WGPUStencilOperation_Keep &&
diff --git a/src/dawn/utils/ComboRenderPipelineDescriptor.cpp b/src/dawn/utils/ComboRenderPipelineDescriptor.cpp
index 3f653d7..e181766 100644
--- a/src/dawn/utils/ComboRenderPipelineDescriptor.cpp
+++ b/src/dawn/utils/ComboRenderPipelineDescriptor.cpp
@@ -104,7 +104,7 @@
         stencilFace.passOp = wgpu::StencilOperation::Keep;
 
         cDepthStencil.format = wgpu::TextureFormat::Depth24PlusStencil8;
-        cDepthStencil.depthWriteEnabled = false;
+        cDepthStencil.depthWriteEnabled = wgpu::OptionalBool::False;
         cDepthStencil.depthCompare = wgpu::CompareFunction::Always;
         cDepthStencil.stencilBack = stencilFace;
         cDepthStencil.stencilFront = stencilFace;
diff --git a/tools/android/BUILD.gn b/tools/android/BUILD.gn
index f98c605..f614bef 100644
--- a/tools/android/BUILD.gn
+++ b/tools/android/BUILD.gn
@@ -126,6 +126,7 @@
     "java/android/dawn/MapMode.kt",
     "java/android/dawn/MipmapFilterMode.kt",
     "java/android/dawn/MultisampleState.kt",
+    "java/android/dawn/OptionalBool.kt",
     "java/android/dawn/Origin3D.kt",
     "java/android/dawn/PipelineLayout.kt",
     "java/android/dawn/PipelineLayoutDescriptor.kt",
diff --git a/tools/android/webgpu/src/test/java/android/dawn/MappedNamedConstantsTest.kt b/tools/android/webgpu/src/test/java/android/dawn/MappedNamedConstantsTest.kt
index 95d6a94..dd7c388 100644
--- a/tools/android/webgpu/src/test/java/android/dawn/MappedNamedConstantsTest.kt
+++ b/tools/android/webgpu/src/test/java/android/dawn/MappedNamedConstantsTest.kt
@@ -43,6 +43,7 @@
         MapAsyncStatus::class,
         MapMode::class,
         MipmapFilterMode::class,
+        OptionalBool::class,
         PopErrorScopeStatus::class,
         PowerPreference::class,
         PresentMode::class,