Add StencilStateFaceDescriptor, in order to match web idl

BUG=dawn:31

Change-Id: I52f95ed134ae5afdf4fc872d5cfc5f36ec1a7a69
Reviewed-on: https://dawn-review.googlesource.com/c/3302
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
Commit-Queue: Yunchao He <yunchao.he@intel.com>
diff --git a/dawn.json b/dawn.json
index ade8a303..61875cd 100644
--- a/dawn.json
+++ b/dawn.json
@@ -550,10 +550,7 @@
                 "name": "set stencil function",
                 "args": [
                     {"name": "face", "type": "face"},
-                    {"name": "stencil compare function", "type": "compare function"},
-                    {"name": "stencil failure operation", "type": "stencil operation"},
-                    {"name": "depth failure operation", "type": "stencil operation"},
-                    {"name": "stencil pass operation", "type": "stencil operation"}
+                    {"name": "descriptor", "type": "stencil state face descriptor", "annotation": "const*"}
                 ]
             },
             {
@@ -965,6 +962,16 @@
             {"value": 7, "name": "decrement wrap"}
         ]
     },
+    "stencil state face descriptor": {
+        "category": "structure",
+        "extensible": false,
+        "members": [
+            {"name": "compare", "type": "compare function"},
+            {"name": "stencil fail op", "type": "stencil operation"},
+            {"name": "depth fail op", "type": "stencil operation"},
+            {"name": "pass op", "type": "stencil operation"}
+        ]
+    },
     "swap chain": {
         "category": "object",
         "methods": [
diff --git a/examples/CubeReflection.cpp b/examples/CubeReflection.cpp
index 5dd6e91..8fce260 100644
--- a/examples/CubeReflection.cpp
+++ b/examples/CubeReflection.cpp
@@ -211,11 +211,16 @@
 
     pipeline = device.CreateRenderPipeline(&descriptor);
 
+    dawn::StencilStateFaceDescriptor planeStencilDescriptor;
+    planeStencilDescriptor.compare = dawn::CompareFunction::Always;
+    planeStencilDescriptor.stencilFailOp = dawn::StencilOperation::Keep;
+    planeStencilDescriptor.depthFailOp = dawn::StencilOperation::Keep;
+    planeStencilDescriptor.passOp = dawn::StencilOperation::Replace;
     auto planeStencilState = device.CreateDepthStencilStateBuilder()
-        .SetDepthCompareFunction(dawn::CompareFunction::Less)
-        .SetDepthWriteEnabled(false)
-        .SetStencilFunction(dawn::Face::Both, dawn::CompareFunction::Always, dawn::StencilOperation::Keep, dawn::StencilOperation::Keep, dawn::StencilOperation::Replace)
-        .GetResult();
+                                 .SetDepthCompareFunction(dawn::CompareFunction::Less)
+                                 .SetDepthWriteEnabled(false)
+                                 .SetStencilFunction(dawn::Face::Both, &planeStencilDescriptor)
+                                 .GetResult();
 
     utils::ComboRenderPipelineDescriptor pDescriptor(device);
     pDescriptor.layout = pl;
@@ -230,11 +235,17 @@
 
     planePipeline = device.CreateRenderPipeline(&pDescriptor);
 
-    auto reflectionStencilState = device.CreateDepthStencilStateBuilder()
-        .SetDepthCompareFunction(dawn::CompareFunction::Less)
-        .SetDepthWriteEnabled(true)
-        .SetStencilFunction(dawn::Face::Both, dawn::CompareFunction::Equal, dawn::StencilOperation::Keep, dawn::StencilOperation::Keep, dawn::StencilOperation::Replace)
-        .GetResult();
+    dawn::StencilStateFaceDescriptor reflectionStencilDescriptor;
+    reflectionStencilDescriptor.compare = dawn::CompareFunction::Equal;
+    reflectionStencilDescriptor.stencilFailOp = dawn::StencilOperation::Keep;
+    reflectionStencilDescriptor.depthFailOp = dawn::StencilOperation::Keep;
+    reflectionStencilDescriptor.passOp = dawn::StencilOperation::Replace;
+    auto reflectionStencilState =
+        device.CreateDepthStencilStateBuilder()
+            .SetDepthCompareFunction(dawn::CompareFunction::Less)
+            .SetDepthWriteEnabled(true)
+            .SetStencilFunction(dawn::Face::Both, &reflectionStencilDescriptor)
+            .GetResult();
 
     utils::ComboRenderPipelineDescriptor rfDescriptor(device);
     rfDescriptor.layout = pl;
diff --git a/src/dawn_native/DepthStencilState.cpp b/src/dawn_native/DepthStencilState.cpp
index 9405cfa..2bf6d7e 100644
--- a/src/dawn_native/DepthStencilState.cpp
+++ b/src/dawn_native/DepthStencilState.cpp
@@ -27,14 +27,14 @@
     }
 
     bool DepthStencilStateBase::StencilTestEnabled() const {
-        return mStencilInfo.back.compareFunction != dawn::CompareFunction::Always ||
-               mStencilInfo.back.stencilFail != dawn::StencilOperation::Keep ||
-               mStencilInfo.back.depthFail != dawn::StencilOperation::Keep ||
-               mStencilInfo.back.depthStencilPass != dawn::StencilOperation::Keep ||
-               mStencilInfo.front.compareFunction != dawn::CompareFunction::Always ||
-               mStencilInfo.front.stencilFail != dawn::StencilOperation::Keep ||
-               mStencilInfo.front.depthFail != dawn::StencilOperation::Keep ||
-               mStencilInfo.front.depthStencilPass != dawn::StencilOperation::Keep;
+        return mStencilInfo.back.compare != dawn::CompareFunction::Always ||
+               mStencilInfo.back.stencilFailOp != dawn::StencilOperation::Keep ||
+               mStencilInfo.back.depthFailOp != dawn::StencilOperation::Keep ||
+               mStencilInfo.back.passOp != dawn::StencilOperation::Keep ||
+               mStencilInfo.front.compare != dawn::CompareFunction::Always ||
+               mStencilInfo.front.stencilFailOp != dawn::StencilOperation::Keep ||
+               mStencilInfo.front.depthFailOp != dawn::StencilOperation::Keep ||
+               mStencilInfo.front.passOp != dawn::StencilOperation::Keep;
     }
 
     const DepthStencilStateBase::DepthInfo& DepthStencilStateBase::GetDepth() const {
@@ -85,11 +85,9 @@
         mDepthInfo.depthWriteEnabled = enabled;
     }
 
-    void DepthStencilStateBuilder::SetStencilFunction(dawn::Face face,
-                                                      dawn::CompareFunction stencilCompareFunction,
-                                                      dawn::StencilOperation stencilFail,
-                                                      dawn::StencilOperation depthFail,
-                                                      dawn::StencilOperation depthStencilPass) {
+    void DepthStencilStateBuilder::SetStencilFunction(
+        dawn::Face face,
+        const StencilStateFaceDescriptor* descriptor) {
         if (face == dawn::Face::None) {
             HandleError("Can't set stencil function of None face");
             return;
@@ -103,10 +101,10 @@
 
             mPropertiesSet |= DEPTH_STENCIL_STATE_PROPERTY_STENCIL_BACK_FUNCTION;
 
-            mStencilInfo.back.compareFunction = stencilCompareFunction;
-            mStencilInfo.back.stencilFail = stencilFail;
-            mStencilInfo.back.depthFail = depthFail;
-            mStencilInfo.back.depthStencilPass = depthStencilPass;
+            mStencilInfo.back.compare = descriptor->compare;
+            mStencilInfo.back.stencilFailOp = descriptor->stencilFailOp;
+            mStencilInfo.back.depthFailOp = descriptor->depthFailOp;
+            mStencilInfo.back.passOp = descriptor->passOp;
         }
         if (face & dawn::Face::Front) {
             if ((mPropertiesSet & DEPTH_STENCIL_STATE_PROPERTY_STENCIL_FRONT_FUNCTION) != 0) {
@@ -116,10 +114,10 @@
 
             mPropertiesSet |= DEPTH_STENCIL_STATE_PROPERTY_STENCIL_FRONT_FUNCTION;
 
-            mStencilInfo.front.compareFunction = stencilCompareFunction;
-            mStencilInfo.front.stencilFail = stencilFail;
-            mStencilInfo.front.depthFail = depthFail;
-            mStencilInfo.front.depthStencilPass = depthStencilPass;
+            mStencilInfo.front.compare = descriptor->compare;
+            mStencilInfo.front.stencilFailOp = descriptor->stencilFailOp;
+            mStencilInfo.front.depthFailOp = descriptor->depthFailOp;
+            mStencilInfo.front.passOp = descriptor->passOp;
         }
     }
 
diff --git a/src/dawn_native/DepthStencilState.h b/src/dawn_native/DepthStencilState.h
index 87a8952..46da7e9 100644
--- a/src/dawn_native/DepthStencilState.h
+++ b/src/dawn_native/DepthStencilState.h
@@ -32,16 +32,13 @@
             bool depthWriteEnabled = false;
         };
 
-        struct StencilFaceInfo {
-            dawn::CompareFunction compareFunction = dawn::CompareFunction::Always;
-            dawn::StencilOperation stencilFail = dawn::StencilOperation::Keep;
-            dawn::StencilOperation depthFail = dawn::StencilOperation::Keep;
-            dawn::StencilOperation depthStencilPass = dawn::StencilOperation::Keep;
-        };
-
         struct StencilInfo {
-            StencilFaceInfo back;
-            StencilFaceInfo front;
+            StencilStateFaceDescriptor back = {
+                dawn::CompareFunction::Always, dawn::StencilOperation::Keep,
+                dawn::StencilOperation::Keep, dawn::StencilOperation::Keep};
+            StencilStateFaceDescriptor front = {
+                dawn::CompareFunction::Always, dawn::StencilOperation::Keep,
+                dawn::StencilOperation::Keep, dawn::StencilOperation::Keep};
             uint32_t readMask = 0xff;
             uint32_t writeMask = 0xff;
         };
@@ -62,11 +59,7 @@
         // Dawn API
         void SetDepthCompareFunction(dawn::CompareFunction depthCompareFunction);
         void SetDepthWriteEnabled(bool enabled);
-        void SetStencilFunction(dawn::Face face,
-                                dawn::CompareFunction stencilCompareFunction,
-                                dawn::StencilOperation stencilFail,
-                                dawn::StencilOperation depthFail,
-                                dawn::StencilOperation depthStencilPass);
+        void SetStencilFunction(dawn::Face face, const StencilStateFaceDescriptor* descriptor);
         void SetStencilMask(uint32_t readMask, uint32_t writeMask);
 
       private:
diff --git a/src/dawn_native/d3d12/DepthStencilStateD3D12.cpp b/src/dawn_native/d3d12/DepthStencilStateD3D12.cpp
index 9b202c8..05d04c4 100644
--- a/src/dawn_native/d3d12/DepthStencilStateD3D12.cpp
+++ b/src/dawn_native/d3d12/DepthStencilStateD3D12.cpp
@@ -18,63 +18,64 @@
 
 namespace dawn_native { namespace d3d12 {
 
-    static D3D12_STENCIL_OP StencilOp(dawn::StencilOperation op) {
-        switch (op) {
-            case dawn::StencilOperation::Keep:
-                return D3D12_STENCIL_OP_KEEP;
-            case dawn::StencilOperation::Zero:
-                return D3D12_STENCIL_OP_ZERO;
-            case dawn::StencilOperation::Replace:
-                return D3D12_STENCIL_OP_REPLACE;
-            case dawn::StencilOperation::IncrementClamp:
-                return D3D12_STENCIL_OP_INCR_SAT;
-            case dawn::StencilOperation::DecrementClamp:
-                return D3D12_STENCIL_OP_DECR_SAT;
-            case dawn::StencilOperation::Invert:
-                return D3D12_STENCIL_OP_INVERT;
-            case dawn::StencilOperation::IncrementWrap:
-                return D3D12_STENCIL_OP_INCR;
-            case dawn::StencilOperation::DecrementWrap:
-                return D3D12_STENCIL_OP_DECR;
-            default:
-                UNREACHABLE();
+    namespace {
+        D3D12_STENCIL_OP StencilOp(dawn::StencilOperation op) {
+            switch (op) {
+                case dawn::StencilOperation::Keep:
+                    return D3D12_STENCIL_OP_KEEP;
+                case dawn::StencilOperation::Zero:
+                    return D3D12_STENCIL_OP_ZERO;
+                case dawn::StencilOperation::Replace:
+                    return D3D12_STENCIL_OP_REPLACE;
+                case dawn::StencilOperation::IncrementClamp:
+                    return D3D12_STENCIL_OP_INCR_SAT;
+                case dawn::StencilOperation::DecrementClamp:
+                    return D3D12_STENCIL_OP_DECR_SAT;
+                case dawn::StencilOperation::Invert:
+                    return D3D12_STENCIL_OP_INVERT;
+                case dawn::StencilOperation::IncrementWrap:
+                    return D3D12_STENCIL_OP_INCR;
+                case dawn::StencilOperation::DecrementWrap:
+                    return D3D12_STENCIL_OP_DECR;
+                default:
+                    UNREACHABLE();
+            }
         }
-    }
 
-    static D3D12_COMPARISON_FUNC ComparisonFunc(dawn::CompareFunction func) {
-        switch (func) {
-            case dawn::CompareFunction::Always:
-                return D3D12_COMPARISON_FUNC_ALWAYS;
-            case dawn::CompareFunction::Equal:
-                return D3D12_COMPARISON_FUNC_EQUAL;
-            case dawn::CompareFunction::Greater:
-                return D3D12_COMPARISON_FUNC_GREATER;
-            case dawn::CompareFunction::GreaterEqual:
-                return D3D12_COMPARISON_FUNC_GREATER_EQUAL;
-            case dawn::CompareFunction::Less:
-                return D3D12_COMPARISON_FUNC_LESS;
-            case dawn::CompareFunction::LessEqual:
-                return D3D12_COMPARISON_FUNC_LESS_EQUAL;
-            case dawn::CompareFunction::Never:
-                return D3D12_COMPARISON_FUNC_NEVER;
-            case dawn::CompareFunction::NotEqual:
-                return D3D12_COMPARISON_FUNC_NOT_EQUAL;
-            default:
-                UNREACHABLE();
+        D3D12_COMPARISON_FUNC ComparisonFunc(dawn::CompareFunction func) {
+            switch (func) {
+                case dawn::CompareFunction::Always:
+                    return D3D12_COMPARISON_FUNC_ALWAYS;
+                case dawn::CompareFunction::Equal:
+                    return D3D12_COMPARISON_FUNC_EQUAL;
+                case dawn::CompareFunction::Greater:
+                    return D3D12_COMPARISON_FUNC_GREATER;
+                case dawn::CompareFunction::GreaterEqual:
+                    return D3D12_COMPARISON_FUNC_GREATER_EQUAL;
+                case dawn::CompareFunction::Less:
+                    return D3D12_COMPARISON_FUNC_LESS;
+                case dawn::CompareFunction::LessEqual:
+                    return D3D12_COMPARISON_FUNC_LESS_EQUAL;
+                case dawn::CompareFunction::Never:
+                    return D3D12_COMPARISON_FUNC_NEVER;
+                case dawn::CompareFunction::NotEqual:
+                    return D3D12_COMPARISON_FUNC_NOT_EQUAL;
+                default:
+                    UNREACHABLE();
+            }
         }
-    }
 
-    static D3D12_DEPTH_STENCILOP_DESC StencilOpDesc(
-        DepthStencilStateBase::StencilFaceInfo faceInfo) {
-        D3D12_DEPTH_STENCILOP_DESC desc;
+        D3D12_DEPTH_STENCILOP_DESC StencilOpDesc(const StencilStateFaceDescriptor descriptor) {
+            D3D12_DEPTH_STENCILOP_DESC desc;
 
-        desc.StencilFailOp = StencilOp(faceInfo.stencilFail);
-        desc.StencilDepthFailOp = StencilOp(faceInfo.depthFail);
-        desc.StencilPassOp = StencilOp(faceInfo.depthStencilPass);
-        desc.StencilFunc = ComparisonFunc(faceInfo.compareFunction);
+            desc.StencilFailOp = StencilOp(descriptor.stencilFailOp);
+            desc.StencilDepthFailOp = StencilOp(descriptor.depthFailOp);
+            desc.StencilPassOp = StencilOp(descriptor.passOp);
+            desc.StencilFunc = ComparisonFunc(descriptor.compare);
 
-        return desc;
-    }
+            return desc;
+        }
+    }  // anonymous namespace
 
     DepthStencilState::DepthStencilState(DepthStencilStateBuilder* builder)
         : DepthStencilStateBase(builder) {
diff --git a/src/dawn_native/metal/DepthStencilStateMTL.mm b/src/dawn_native/metal/DepthStencilStateMTL.mm
index fc81133..8ff2431 100644
--- a/src/dawn_native/metal/DepthStencilStateMTL.mm
+++ b/src/dawn_native/metal/DepthStencilStateMTL.mm
@@ -77,22 +77,22 @@
             MTLStencilDescriptor* frontFaceStencil = [MTLStencilDescriptor new];
 
             backFaceStencil.stencilCompareFunction =
-                MetalDepthStencilCompareFunction(stencil.back.compareFunction);
+                MetalDepthStencilCompareFunction(stencil.back.compare);
             backFaceStencil.stencilFailureOperation =
-                MetalStencilOperation(stencil.back.stencilFail);
-            backFaceStencil.depthFailureOperation = MetalStencilOperation(stencil.back.depthFail);
-            backFaceStencil.depthStencilPassOperation =
-                MetalStencilOperation(stencil.back.depthStencilPass);
+                MetalStencilOperation(stencil.back.stencilFailOp);
+            backFaceStencil.depthFailureOperation = MetalStencilOperation(stencil.back.depthFailOp);
+            backFaceStencil.depthStencilPassOperation = MetalStencilOperation(stencil.back.passOp);
             backFaceStencil.readMask = stencil.readMask;
             backFaceStencil.writeMask = stencil.writeMask;
 
             frontFaceStencil.stencilCompareFunction =
-                MetalDepthStencilCompareFunction(stencil.front.compareFunction);
+                MetalDepthStencilCompareFunction(stencil.front.compare);
             frontFaceStencil.stencilFailureOperation =
-                MetalStencilOperation(stencil.front.stencilFail);
-            frontFaceStencil.depthFailureOperation = MetalStencilOperation(stencil.front.depthFail);
+                MetalStencilOperation(stencil.front.stencilFailOp);
+            frontFaceStencil.depthFailureOperation =
+                MetalStencilOperation(stencil.front.depthFailOp);
             frontFaceStencil.depthStencilPassOperation =
-                MetalStencilOperation(stencil.front.depthStencilPass);
+                MetalStencilOperation(stencil.front.passOp);
             frontFaceStencil.readMask = stencil.readMask;
             frontFaceStencil.writeMask = stencil.writeMask;
 
diff --git a/src/dawn_native/opengl/DepthStencilStateGL.cpp b/src/dawn_native/opengl/DepthStencilStateGL.cpp
index 03cf763..b71aa7f 100644
--- a/src/dawn_native/opengl/DepthStencilStateGL.cpp
+++ b/src/dawn_native/opengl/DepthStencilStateGL.cpp
@@ -98,17 +98,17 @@
 
         auto& stencilInfo = GetStencil();
 
-        GLenum backCompareFunction = OpenGLCompareFunction(stencilInfo.back.compareFunction);
-        GLenum frontCompareFunction = OpenGLCompareFunction(stencilInfo.front.compareFunction);
+        GLenum backCompareFunction = OpenGLCompareFunction(stencilInfo.back.compare);
+        GLenum frontCompareFunction = OpenGLCompareFunction(stencilInfo.front.compare);
         persistentPipelineState.SetStencilFuncsAndMask(backCompareFunction, frontCompareFunction,
                                                        stencilInfo.readMask);
 
-        glStencilOpSeparate(GL_BACK, OpenGLStencilOperation(stencilInfo.back.stencilFail),
-                            OpenGLStencilOperation(stencilInfo.back.depthFail),
-                            OpenGLStencilOperation(stencilInfo.back.depthStencilPass));
-        glStencilOpSeparate(GL_FRONT, OpenGLStencilOperation(stencilInfo.front.stencilFail),
-                            OpenGLStencilOperation(stencilInfo.front.depthFail),
-                            OpenGLStencilOperation(stencilInfo.front.depthStencilPass));
+        glStencilOpSeparate(GL_BACK, OpenGLStencilOperation(stencilInfo.back.stencilFailOp),
+                            OpenGLStencilOperation(stencilInfo.back.depthFailOp),
+                            OpenGLStencilOperation(stencilInfo.back.passOp));
+        glStencilOpSeparate(GL_FRONT, OpenGLStencilOperation(stencilInfo.front.stencilFailOp),
+                            OpenGLStencilOperation(stencilInfo.front.depthFailOp),
+                            OpenGLStencilOperation(stencilInfo.front.passOp));
 
         glStencilMask(stencilInfo.writeMask);
     }
diff --git a/src/dawn_native/vulkan/DepthStencilStateVk.cpp b/src/dawn_native/vulkan/DepthStencilStateVk.cpp
index a50bb0d..c2f29a4 100644
--- a/src/dawn_native/vulkan/DepthStencilStateVk.cpp
+++ b/src/dawn_native/vulkan/DepthStencilStateVk.cpp
@@ -84,15 +84,15 @@
         const auto& stencil = GetStencil();
         mCreateInfo.stencilTestEnable = StencilTestEnabled() ? VK_TRUE : VK_FALSE;
 
-        mCreateInfo.front.failOp = VulkanStencilOp(stencil.front.stencilFail);
-        mCreateInfo.front.passOp = VulkanStencilOp(stencil.front.depthStencilPass);
-        mCreateInfo.front.depthFailOp = VulkanStencilOp(stencil.front.depthFail);
-        mCreateInfo.front.compareOp = VulkanCompareOp(stencil.front.compareFunction);
+        mCreateInfo.front.failOp = VulkanStencilOp(stencil.front.stencilFailOp);
+        mCreateInfo.front.passOp = VulkanStencilOp(stencil.front.passOp);
+        mCreateInfo.front.depthFailOp = VulkanStencilOp(stencil.front.depthFailOp);
+        mCreateInfo.front.compareOp = VulkanCompareOp(stencil.front.compare);
 
-        mCreateInfo.back.failOp = VulkanStencilOp(stencil.back.stencilFail);
-        mCreateInfo.back.passOp = VulkanStencilOp(stencil.back.depthStencilPass);
-        mCreateInfo.back.depthFailOp = VulkanStencilOp(stencil.back.depthFail);
-        mCreateInfo.back.compareOp = VulkanCompareOp(stencil.back.compareFunction);
+        mCreateInfo.back.failOp = VulkanStencilOp(stencil.back.stencilFailOp);
+        mCreateInfo.back.passOp = VulkanStencilOp(stencil.back.passOp);
+        mCreateInfo.back.depthFailOp = VulkanStencilOp(stencil.back.depthFailOp);
+        mCreateInfo.back.compareOp = VulkanCompareOp(stencil.back.compare);
 
         // Dawn doesn't have separate front and back stencil masks.
         mCreateInfo.front.compareMask = stencil.readMask;
diff --git a/src/tests/end2end/DepthStencilStateTests.cpp b/src/tests/end2end/DepthStencilStateTests.cpp
index 7eb080a..81c1b39 100644
--- a/src/tests/end2end/DepthStencilStateTests.cpp
+++ b/src/tests/end2end/DepthStencilStateTests.cpp
@@ -135,13 +135,25 @@
         // Check whether a stencil comparison function works as expected
         // The less, equal, greater booleans denote wether the respective triangle should be visible based on the comparison function
         void CheckStencilCompareFunction(dawn::CompareFunction compareFunction, bool less, bool equal, bool greater) {
-            dawn::DepthStencilState baseState = device.CreateDepthStencilStateBuilder()
-                .SetStencilFunction(dawn::Face::Both, dawn::CompareFunction::Always, dawn::StencilOperation::Keep, dawn::StencilOperation::Keep, dawn::StencilOperation::Replace)
-                .GetResult();
+            dawn::StencilStateFaceDescriptor baseStencilFaceDescriptor;
+            baseStencilFaceDescriptor.compare = dawn::CompareFunction::Always;
+            baseStencilFaceDescriptor.stencilFailOp = dawn::StencilOperation::Keep;
+            baseStencilFaceDescriptor.depthFailOp = dawn::StencilOperation::Keep;
+            baseStencilFaceDescriptor.passOp = dawn::StencilOperation::Replace;
+            dawn::DepthStencilState baseState =
+                device.CreateDepthStencilStateBuilder()
+                    .SetStencilFunction(dawn::Face::Both, &baseStencilFaceDescriptor)
+                    .GetResult();
 
-            dawn::DepthStencilState state = device.CreateDepthStencilStateBuilder()
-                .SetStencilFunction(dawn::Face::Both, compareFunction, dawn::StencilOperation::Keep, dawn::StencilOperation::Keep, dawn::StencilOperation::Keep)
-                .GetResult();
+            dawn::StencilStateFaceDescriptor stencilFaceDescriptor;
+            stencilFaceDescriptor.compare = compareFunction;
+            stencilFaceDescriptor.stencilFailOp = dawn::StencilOperation::Keep;
+            stencilFaceDescriptor.depthFailOp = dawn::StencilOperation::Keep;
+            stencilFaceDescriptor.passOp = dawn::StencilOperation::Keep;
+            dawn::DepthStencilState state =
+                device.CreateDepthStencilStateBuilder()
+                    .SetStencilFunction(dawn::Face::Both, &stencilFaceDescriptor)
+                    .GetResult();
 
             RGBA8 baseColor = RGBA8(255, 255, 255, 255);
             RGBA8 lessColor = RGBA8(255, 0, 0, 255);
@@ -163,13 +175,25 @@
 
         // Given the provided `initialStencil` and `reference`, check that applying the `stencilOperation` produces the `expectedStencil`
         void CheckStencilOperation(dawn::StencilOperation stencilOperation, uint32_t initialStencil, uint32_t reference, uint32_t expectedStencil) {
-            dawn::DepthStencilState baseState = device.CreateDepthStencilStateBuilder()
-                .SetStencilFunction(dawn::Face::Both, dawn::CompareFunction::Always, dawn::StencilOperation::Keep, dawn::StencilOperation::Keep, dawn::StencilOperation::Replace)
-                .GetResult();
+            dawn::StencilStateFaceDescriptor baseStencilFaceDescriptor;
+            baseStencilFaceDescriptor.compare = dawn::CompareFunction::Always;
+            baseStencilFaceDescriptor.stencilFailOp = dawn::StencilOperation::Keep;
+            baseStencilFaceDescriptor.depthFailOp = dawn::StencilOperation::Keep;
+            baseStencilFaceDescriptor.passOp = dawn::StencilOperation::Replace;
+            dawn::DepthStencilState baseState =
+                device.CreateDepthStencilStateBuilder()
+                    .SetStencilFunction(dawn::Face::Both, &baseStencilFaceDescriptor)
+                    .GetResult();
 
-            dawn::DepthStencilState state = device.CreateDepthStencilStateBuilder()
-                .SetStencilFunction(dawn::Face::Both, dawn::CompareFunction::Always, dawn::StencilOperation::Keep, dawn::StencilOperation::Keep, stencilOperation)
-                .GetResult();
+            dawn::StencilStateFaceDescriptor stencilFaceDescriptor;
+            stencilFaceDescriptor.compare = dawn::CompareFunction::Always;
+            stencilFaceDescriptor.stencilFailOp = dawn::StencilOperation::Keep;
+            stencilFaceDescriptor.depthFailOp = dawn::StencilOperation::Keep;
+            stencilFaceDescriptor.passOp = stencilOperation;
+            dawn::DepthStencilState state =
+                device.CreateDepthStencilStateBuilder()
+                    .SetStencilFunction(dawn::Face::Both, &stencilFaceDescriptor)
+                    .GetResult();
 
             CheckStencil({
                 // Wipe the stencil buffer with the initialStencil value
@@ -182,9 +206,15 @@
 
         // Draw a list of test specs, and check if the stencil value is equal to the expected value
         void CheckStencil(std::vector<TestSpec> testParams, uint32_t expectedStencil) {
-            dawn::DepthStencilState state = device.CreateDepthStencilStateBuilder()
-                .SetStencilFunction(dawn::Face::Both, dawn::CompareFunction::Equal, dawn::StencilOperation::Keep, dawn::StencilOperation::Keep, dawn::StencilOperation::Keep)
-                .GetResult();
+            dawn::StencilStateFaceDescriptor stencilFaceDescriptor;
+            stencilFaceDescriptor.compare = dawn::CompareFunction::Equal;
+            stencilFaceDescriptor.stencilFailOp = dawn::StencilOperation::Keep;
+            stencilFaceDescriptor.depthFailOp = dawn::StencilOperation::Keep;
+            stencilFaceDescriptor.passOp = dawn::StencilOperation::Keep;
+            dawn::DepthStencilState state =
+                device.CreateDepthStencilStateBuilder()
+                    .SetStencilFunction(dawn::Face::Both, &stencilFaceDescriptor)
+                    .GetResult();
 
             testParams.push_back({ state, RGBA8(0, 255, 0, 255), 0, expectedStencil });
             DoTest(testParams, RGBA8(0, 255, 0, 255));
@@ -415,14 +445,26 @@
 
 // Check that the setting a stencil read mask works
 TEST_P(DepthStencilStateTest, StencilReadMask) {
-    dawn::DepthStencilState baseState = device.CreateDepthStencilStateBuilder()
-        .SetStencilFunction(dawn::Face::Both, dawn::CompareFunction::Always, dawn::StencilOperation::Keep, dawn::StencilOperation::Keep, dawn::StencilOperation::Replace)
-        .GetResult();
+    dawn::StencilStateFaceDescriptor baseStencilFaceDescriptor;
+    baseStencilFaceDescriptor.compare = dawn::CompareFunction::Always;
+    baseStencilFaceDescriptor.stencilFailOp = dawn::StencilOperation::Keep;
+    baseStencilFaceDescriptor.depthFailOp = dawn::StencilOperation::Keep;
+    baseStencilFaceDescriptor.passOp = dawn::StencilOperation::Replace;
+    dawn::DepthStencilState baseState =
+        device.CreateDepthStencilStateBuilder()
+            .SetStencilFunction(dawn::Face::Both, &baseStencilFaceDescriptor)
+            .GetResult();
 
-    dawn::DepthStencilState state = device.CreateDepthStencilStateBuilder()
-        .SetStencilFunction(dawn::Face::Both, dawn::CompareFunction::Equal, dawn::StencilOperation::Keep, dawn::StencilOperation::Keep, dawn::StencilOperation::Keep)
-        .SetStencilMask(0x2, 0xff)
-        .GetResult();
+    dawn::StencilStateFaceDescriptor stencilFaceDescriptor;
+    stencilFaceDescriptor.compare = dawn::CompareFunction::Equal;
+    stencilFaceDescriptor.stencilFailOp = dawn::StencilOperation::Keep;
+    stencilFaceDescriptor.depthFailOp = dawn::StencilOperation::Keep;
+    stencilFaceDescriptor.passOp = dawn::StencilOperation::Keep;
+    dawn::DepthStencilState state =
+        device.CreateDepthStencilStateBuilder()
+            .SetStencilFunction(dawn::Face::Both, &stencilFaceDescriptor)
+            .SetStencilMask(0x2, 0xff)
+            .GetResult();
 
     RGBA8 baseColor = RGBA8(255, 255, 255, 255);
     RGBA8 red = RGBA8(255, 0, 0, 255);
@@ -435,14 +477,26 @@
 
 // Check that setting a stencil write mask works
 TEST_P(DepthStencilStateTest, StencilWriteMask) {
-    dawn::DepthStencilState baseState = device.CreateDepthStencilStateBuilder()
-        .SetStencilFunction(dawn::Face::Both, dawn::CompareFunction::Always, dawn::StencilOperation::Keep, dawn::StencilOperation::Keep, dawn::StencilOperation::Replace)
-        .SetStencilMask(0xff, 0x1)
-        .GetResult();
+    dawn::StencilStateFaceDescriptor baseStencilFaceDescriptor;
+    baseStencilFaceDescriptor.compare = dawn::CompareFunction::Always;
+    baseStencilFaceDescriptor.stencilFailOp = dawn::StencilOperation::Keep;
+    baseStencilFaceDescriptor.depthFailOp = dawn::StencilOperation::Keep;
+    baseStencilFaceDescriptor.passOp = dawn::StencilOperation::Replace;
+    dawn::DepthStencilState baseState =
+        device.CreateDepthStencilStateBuilder()
+            .SetStencilFunction(dawn::Face::Both, &baseStencilFaceDescriptor)
+            .SetStencilMask(0xff, 0x1)
+            .GetResult();
 
-    dawn::DepthStencilState state = device.CreateDepthStencilStateBuilder()
-        .SetStencilFunction(dawn::Face::Both, dawn::CompareFunction::Equal, dawn::StencilOperation::Keep, dawn::StencilOperation::Keep, dawn::StencilOperation::Keep)
-        .GetResult();
+    dawn::StencilStateFaceDescriptor stencilFaceDescriptor;
+    stencilFaceDescriptor.compare = dawn::CompareFunction::Equal;
+    stencilFaceDescriptor.stencilFailOp = dawn::StencilOperation::Keep;
+    stencilFaceDescriptor.depthFailOp = dawn::StencilOperation::Keep;
+    stencilFaceDescriptor.passOp = dawn::StencilOperation::Keep;
+    dawn::DepthStencilState state =
+        device.CreateDepthStencilStateBuilder()
+            .SetStencilFunction(dawn::Face::Both, &stencilFaceDescriptor)
+            .GetResult();
 
     RGBA8 baseColor = RGBA8(255, 255, 255, 255);
     RGBA8 green = RGBA8(0, 255, 0, 255);
@@ -454,13 +508,25 @@
 
 // Test that the stencil operation is executed on stencil fail
 TEST_P(DepthStencilStateTest, StencilFail) {
-    dawn::DepthStencilState baseState = device.CreateDepthStencilStateBuilder()
-        .SetStencilFunction(dawn::Face::Both, dawn::CompareFunction::Always, dawn::StencilOperation::Keep, dawn::StencilOperation::Keep, dawn::StencilOperation::Replace)
-        .GetResult();
+    dawn::StencilStateFaceDescriptor baseStencilFaceDescriptor;
+    baseStencilFaceDescriptor.compare = dawn::CompareFunction::Always;
+    baseStencilFaceDescriptor.stencilFailOp = dawn::StencilOperation::Keep;
+    baseStencilFaceDescriptor.depthFailOp = dawn::StencilOperation::Keep;
+    baseStencilFaceDescriptor.passOp = dawn::StencilOperation::Replace;
+    dawn::DepthStencilState baseState =
+        device.CreateDepthStencilStateBuilder()
+            .SetStencilFunction(dawn::Face::Both, &baseStencilFaceDescriptor)
+            .GetResult();
 
-    dawn::DepthStencilState state = device.CreateDepthStencilStateBuilder()
-        .SetStencilFunction(dawn::Face::Both, dawn::CompareFunction::Less, dawn::StencilOperation::Replace, dawn::StencilOperation::Keep, dawn::StencilOperation::Keep)
-        .GetResult();
+    dawn::StencilStateFaceDescriptor stencilFaceDescriptor;
+    stencilFaceDescriptor.compare = dawn::CompareFunction::Less;
+    stencilFaceDescriptor.stencilFailOp = dawn::StencilOperation::Replace;
+    stencilFaceDescriptor.depthFailOp = dawn::StencilOperation::Keep;
+    stencilFaceDescriptor.passOp = dawn::StencilOperation::Keep;
+    dawn::DepthStencilState state =
+        device.CreateDepthStencilStateBuilder()
+            .SetStencilFunction(dawn::Face::Both, &stencilFaceDescriptor)
+            .GetResult();
 
     CheckStencil({
         { baseState, RGBA8(255, 255, 255, 255), 1.f, 1 },   // Triangle to set stencil value to 1
@@ -470,16 +536,28 @@
 
 // Test that the stencil operation is executed on stencil pass, depth fail
 TEST_P(DepthStencilStateTest, StencilDepthFail) {
-    dawn::DepthStencilState baseState = device.CreateDepthStencilStateBuilder()
-        .SetStencilFunction(dawn::Face::Both, dawn::CompareFunction::Always, dawn::StencilOperation::Keep, dawn::StencilOperation::Keep, dawn::StencilOperation::Replace)
-        .SetDepthWriteEnabled(true)
-        .GetResult();
+    dawn::StencilStateFaceDescriptor baseStencilFaceDescriptor;
+    baseStencilFaceDescriptor.compare = dawn::CompareFunction::Always;
+    baseStencilFaceDescriptor.stencilFailOp = dawn::StencilOperation::Keep;
+    baseStencilFaceDescriptor.depthFailOp = dawn::StencilOperation::Keep;
+    baseStencilFaceDescriptor.passOp = dawn::StencilOperation::Replace;
+    dawn::DepthStencilState baseState =
+        device.CreateDepthStencilStateBuilder()
+            .SetStencilFunction(dawn::Face::Both, &baseStencilFaceDescriptor)
+            .SetDepthWriteEnabled(true)
+            .GetResult();
 
-    dawn::DepthStencilState state = device.CreateDepthStencilStateBuilder()
-        .SetStencilFunction(dawn::Face::Both, dawn::CompareFunction::Greater, dawn::StencilOperation::Keep, dawn::StencilOperation::Replace, dawn::StencilOperation::Keep)
-        .SetDepthWriteEnabled(true)
-        .SetDepthCompareFunction(dawn::CompareFunction::Less)
-        .GetResult();
+    dawn::StencilStateFaceDescriptor stencilFaceDescriptor;
+    stencilFaceDescriptor.compare = dawn::CompareFunction::Greater;
+    stencilFaceDescriptor.stencilFailOp = dawn::StencilOperation::Keep;
+    stencilFaceDescriptor.depthFailOp = dawn::StencilOperation::Replace;
+    stencilFaceDescriptor.passOp = dawn::StencilOperation::Keep;
+    dawn::DepthStencilState state =
+        device.CreateDepthStencilStateBuilder()
+            .SetStencilFunction(dawn::Face::Both, &stencilFaceDescriptor)
+            .SetDepthWriteEnabled(true)
+            .SetDepthCompareFunction(dawn::CompareFunction::Less)
+            .GetResult();
 
     CheckStencil({
         { baseState, RGBA8(255, 255, 255, 255), 0.f, 1 },   // Triangle to set stencil value to 1. Depth is 0
@@ -489,16 +567,28 @@
 
 // Test that the stencil operation is executed on stencil pass, depth pass
 TEST_P(DepthStencilStateTest, StencilDepthPass) {
-    dawn::DepthStencilState baseState = device.CreateDepthStencilStateBuilder()
-        .SetStencilFunction(dawn::Face::Both, dawn::CompareFunction::Always, dawn::StencilOperation::Keep, dawn::StencilOperation::Keep, dawn::StencilOperation::Replace)
-        .SetDepthWriteEnabled(true)
-        .GetResult();
+    dawn::StencilStateFaceDescriptor baseStencilFaceDescriptor;
+    baseStencilFaceDescriptor.compare = dawn::CompareFunction::Always;
+    baseStencilFaceDescriptor.stencilFailOp = dawn::StencilOperation::Keep;
+    baseStencilFaceDescriptor.depthFailOp = dawn::StencilOperation::Keep;
+    baseStencilFaceDescriptor.passOp = dawn::StencilOperation::Replace;
+    dawn::DepthStencilState baseState =
+        device.CreateDepthStencilStateBuilder()
+            .SetStencilFunction(dawn::Face::Both, &baseStencilFaceDescriptor)
+            .SetDepthWriteEnabled(true)
+            .GetResult();
 
-    dawn::DepthStencilState state = device.CreateDepthStencilStateBuilder()
-        .SetStencilFunction(dawn::Face::Both, dawn::CompareFunction::Greater, dawn::StencilOperation::Keep, dawn::StencilOperation::Keep, dawn::StencilOperation::Replace)
-        .SetDepthWriteEnabled(true)
-        .SetDepthCompareFunction(dawn::CompareFunction::Less)
-        .GetResult();
+    dawn::StencilStateFaceDescriptor stencilFaceDescriptor;
+    stencilFaceDescriptor.compare = dawn::CompareFunction::Greater;
+    stencilFaceDescriptor.stencilFailOp = dawn::StencilOperation::Keep;
+    stencilFaceDescriptor.depthFailOp = dawn::StencilOperation::Keep;
+    stencilFaceDescriptor.passOp = dawn::StencilOperation::Replace;
+    dawn::DepthStencilState state =
+        device.CreateDepthStencilStateBuilder()
+            .SetStencilFunction(dawn::Face::Both, &stencilFaceDescriptor)
+            .SetDepthWriteEnabled(true)
+            .SetDepthCompareFunction(dawn::CompareFunction::Less)
+            .GetResult();
 
     CheckStencil({
         { baseState, RGBA8(255, 255, 255, 255), 1.f, 1 },   // Triangle to set stencil value to 1. Depth is 0
diff --git a/src/tests/unittests/validation/DepthStencilStateValidationTests.cpp b/src/tests/unittests/validation/DepthStencilStateValidationTests.cpp
index 858c2b4..f2639f9 100644
--- a/src/tests/unittests/validation/DepthStencilStateValidationTests.cpp
+++ b/src/tests/unittests/validation/DepthStencilStateValidationTests.cpp
@@ -21,13 +21,18 @@
 TEST_F(DepthStencilStateValidationTest, CreationSuccess) {
     // Success for setting all properties
     {
-        dawn::DepthStencilState ds = AssertWillBeSuccess(device.CreateDepthStencilStateBuilder())
-            .SetDepthCompareFunction(dawn::CompareFunction::Less)
-            .SetDepthWriteEnabled(true)
-            .SetStencilFunction(dawn::Face::Both, dawn::CompareFunction::Greater,
-                dawn::StencilOperation::Keep, dawn::StencilOperation::Keep, dawn::StencilOperation::Replace)
-            .SetStencilMask(0x0, 0x1)
-            .GetResult();
+        dawn::StencilStateFaceDescriptor stencilFaceDescriptor;
+        stencilFaceDescriptor.compare = dawn::CompareFunction::Greater;
+        stencilFaceDescriptor.stencilFailOp = dawn::StencilOperation::Keep;
+        stencilFaceDescriptor.depthFailOp = dawn::StencilOperation::Keep;
+        stencilFaceDescriptor.passOp = dawn::StencilOperation::Replace;
+        dawn::DepthStencilState ds =
+            AssertWillBeSuccess(device.CreateDepthStencilStateBuilder())
+                .SetDepthCompareFunction(dawn::CompareFunction::Less)
+                .SetDepthWriteEnabled(true)
+                .SetStencilFunction(dawn::Face::Both, &stencilFaceDescriptor)
+                .SetStencilMask(0x0, 0x1)
+                .GetResult();
     }
 
     // Success for empty builder
@@ -38,12 +43,21 @@
 
     // Test success when setting stencil function on separate faces
     {
-        dawn::DepthStencilState ds = AssertWillBeSuccess(device.CreateDepthStencilStateBuilder())
-            .SetStencilFunction(dawn::Face::Front, dawn::CompareFunction::Less,
-                dawn::StencilOperation::Replace, dawn::StencilOperation::Replace, dawn::StencilOperation::Replace)
-            .SetStencilFunction(dawn::Face::Back, dawn::CompareFunction::Greater,
-                dawn::StencilOperation::Replace, dawn::StencilOperation::Replace, dawn::StencilOperation::Replace)
-            .GetResult();
+        dawn::StencilStateFaceDescriptor stencilFrontDescriptor;
+        stencilFrontDescriptor.compare = dawn::CompareFunction::Less;
+        stencilFrontDescriptor.stencilFailOp = dawn::StencilOperation::Replace;
+        stencilFrontDescriptor.depthFailOp = dawn::StencilOperation::Replace;
+        stencilFrontDescriptor.passOp = dawn::StencilOperation::Replace;
+        dawn::StencilStateFaceDescriptor stencilBackDescriptor;
+        stencilBackDescriptor.compare = dawn::CompareFunction::Greater;
+        stencilBackDescriptor.stencilFailOp = dawn::StencilOperation::Replace;
+        stencilBackDescriptor.depthFailOp = dawn::StencilOperation::Replace;
+        stencilBackDescriptor.passOp = dawn::StencilOperation::Replace;
+        dawn::DepthStencilState ds =
+            AssertWillBeSuccess(device.CreateDepthStencilStateBuilder())
+                .SetStencilFunction(dawn::Face::Front, &stencilFrontDescriptor)
+                .SetStencilFunction(dawn::Face::Back, &stencilBackDescriptor)
+                .GetResult();
     }
 }
 
@@ -75,21 +89,39 @@
 
     // Test failure when directly setting stencil function on a face multiple times
     {
-        dawn::DepthStencilState ds = AssertWillBeError(device.CreateDepthStencilStateBuilder())
-            .SetStencilFunction(dawn::Face::Back, dawn::CompareFunction::Less,
-                dawn::StencilOperation::Replace, dawn::StencilOperation::Replace, dawn::StencilOperation::Replace)
-            .SetStencilFunction(dawn::Face::Back, dawn::CompareFunction::Greater,
-                dawn::StencilOperation::Replace, dawn::StencilOperation::Replace, dawn::StencilOperation::Replace)
-            .GetResult();
+        dawn::StencilStateFaceDescriptor stencilBackDescriptor1;
+        stencilBackDescriptor1.compare = dawn::CompareFunction::Less;
+        stencilBackDescriptor1.stencilFailOp = dawn::StencilOperation::Replace;
+        stencilBackDescriptor1.depthFailOp = dawn::StencilOperation::Replace;
+        stencilBackDescriptor1.passOp = dawn::StencilOperation::Replace;
+        dawn::StencilStateFaceDescriptor stencilBackDescriptor2;
+        stencilBackDescriptor2.compare = dawn::CompareFunction::Greater;
+        stencilBackDescriptor2.stencilFailOp = dawn::StencilOperation::Replace;
+        stencilBackDescriptor2.depthFailOp = dawn::StencilOperation::Replace;
+        stencilBackDescriptor2.passOp = dawn::StencilOperation::Replace;
+        dawn::DepthStencilState ds =
+            AssertWillBeError(device.CreateDepthStencilStateBuilder())
+                .SetStencilFunction(dawn::Face::Back, &stencilBackDescriptor1)
+                .SetStencilFunction(dawn::Face::Back, &stencilBackDescriptor2)
+                .GetResult();
     }
 
     // Test failure when indirectly setting stencil function on a face multiple times
     {
-        dawn::DepthStencilState ds = AssertWillBeError(device.CreateDepthStencilStateBuilder())
-            .SetStencilFunction(dawn::Face::Both, dawn::CompareFunction::Less,
-                dawn::StencilOperation::Replace, dawn::StencilOperation::Replace, dawn::StencilOperation::Replace)
-            .SetStencilFunction(dawn::Face::Back, dawn::CompareFunction::Greater,
-                dawn::StencilOperation::Replace, dawn::StencilOperation::Replace, dawn::StencilOperation::Replace)
-            .GetResult();
+        dawn::StencilStateFaceDescriptor stencilBothDescriptor;
+        stencilBothDescriptor.compare = dawn::CompareFunction::Less;
+        stencilBothDescriptor.stencilFailOp = dawn::StencilOperation::Replace;
+        stencilBothDescriptor.depthFailOp = dawn::StencilOperation::Replace;
+        stencilBothDescriptor.passOp = dawn::StencilOperation::Replace;
+        dawn::StencilStateFaceDescriptor stencilBackDescriptor;
+        stencilBackDescriptor.compare = dawn::CompareFunction::Greater;
+        stencilBackDescriptor.stencilFailOp = dawn::StencilOperation::Replace;
+        stencilBackDescriptor.depthFailOp = dawn::StencilOperation::Replace;
+        stencilBackDescriptor.passOp = dawn::StencilOperation::Replace;
+        dawn::DepthStencilState ds =
+            AssertWillBeError(device.CreateDepthStencilStateBuilder())
+                .SetStencilFunction(dawn::Face::Both, &stencilBothDescriptor)
+                .SetStencilFunction(dawn::Face::Back, &stencilBackDescriptor)
+                .GetResult();
     }
 }