Replace DepthStencilState builder via DepthStencilState descriptor.

This change also removes DepthStencilState object.

Bug=dawn:31

Change-Id: I7bb54ef4da527184bb2726c77d93d411d44c3956
Reviewed-on: https://dawn-review.googlesource.com/c/3541
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
Commit-Queue: Yunchao He <yunchao.he@intel.com>
diff --git a/src/dawn_native/DepthStencilState.cpp b/src/dawn_native/DepthStencilState.cpp
deleted file mode 100644
index 2bf6d7e..0000000
--- a/src/dawn_native/DepthStencilState.cpp
+++ /dev/null
@@ -1,135 +0,0 @@
-// Copyright 2017 The Dawn Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "dawn_native/DepthStencilState.h"
-
-#include "dawn_native/Device.h"
-
-namespace dawn_native {
-
-    // DepthStencilStateBase
-
-    DepthStencilStateBase::DepthStencilStateBase(DepthStencilStateBuilder* builder)
-        : ObjectBase(builder->GetDevice()),
-          mDepthInfo(builder->mDepthInfo),
-          mStencilInfo(builder->mStencilInfo) {
-    }
-
-    bool DepthStencilStateBase::StencilTestEnabled() const {
-        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 {
-        return mDepthInfo;
-    }
-
-    const DepthStencilStateBase::StencilInfo& DepthStencilStateBase::GetStencil() const {
-        return mStencilInfo;
-    }
-
-    // DepthStencilStateBuilder
-
-    enum DepthStencilStateSetProperties {
-        DEPTH_STENCIL_STATE_PROPERTY_DEPTH_COMPARE_FUNCTION = 0x1,
-        DEPTH_STENCIL_STATE_PROPERTY_DEPTH_WRITE_ENABLED = 0x2,
-        DEPTH_STENCIL_STATE_PROPERTY_STENCIL_BACK_FUNCTION = 0x4,
-        DEPTH_STENCIL_STATE_PROPERTY_STENCIL_FRONT_FUNCTION = 0x08,
-        DEPTH_STENCIL_STATE_PROPERTY_STENCIL_MASK = 0x10,
-    };
-
-    DepthStencilStateBuilder::DepthStencilStateBuilder(DeviceBase* device) : Builder(device) {
-    }
-
-    DepthStencilStateBase* DepthStencilStateBuilder::GetResultImpl() {
-        return GetDevice()->CreateDepthStencilState(this);
-    }
-
-    void DepthStencilStateBuilder::SetDepthCompareFunction(
-        dawn::CompareFunction depthCompareFunction) {
-        if ((mPropertiesSet & DEPTH_STENCIL_STATE_PROPERTY_DEPTH_COMPARE_FUNCTION) != 0) {
-            HandleError("Depth compare property set multiple times");
-            return;
-        }
-
-        mPropertiesSet |= DEPTH_STENCIL_STATE_PROPERTY_DEPTH_COMPARE_FUNCTION;
-
-        mDepthInfo.compareFunction = depthCompareFunction;
-    }
-
-    void DepthStencilStateBuilder::SetDepthWriteEnabled(bool enabled) {
-        if ((mPropertiesSet & DEPTH_STENCIL_STATE_PROPERTY_DEPTH_WRITE_ENABLED) != 0) {
-            HandleError("Depth write enabled property set multiple times");
-            return;
-        }
-
-        mPropertiesSet |= DEPTH_STENCIL_STATE_PROPERTY_DEPTH_WRITE_ENABLED;
-
-        mDepthInfo.depthWriteEnabled = enabled;
-    }
-
-    void DepthStencilStateBuilder::SetStencilFunction(
-        dawn::Face face,
-        const StencilStateFaceDescriptor* descriptor) {
-        if (face == dawn::Face::None) {
-            HandleError("Can't set stencil function of None face");
-            return;
-        }
-
-        if (face & dawn::Face::Back) {
-            if ((mPropertiesSet & DEPTH_STENCIL_STATE_PROPERTY_STENCIL_BACK_FUNCTION) != 0) {
-                HandleError("Stencil back function property set multiple times");
-                return;
-            }
-
-            mPropertiesSet |= DEPTH_STENCIL_STATE_PROPERTY_STENCIL_BACK_FUNCTION;
-
-            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) {
-                HandleError("Stencil front function property set multiple times");
-                return;
-            }
-
-            mPropertiesSet |= DEPTH_STENCIL_STATE_PROPERTY_STENCIL_FRONT_FUNCTION;
-
-            mStencilInfo.front.compare = descriptor->compare;
-            mStencilInfo.front.stencilFailOp = descriptor->stencilFailOp;
-            mStencilInfo.front.depthFailOp = descriptor->depthFailOp;
-            mStencilInfo.front.passOp = descriptor->passOp;
-        }
-    }
-
-    void DepthStencilStateBuilder::SetStencilMask(uint32_t readMask, uint32_t writeMask) {
-        if ((mPropertiesSet & DEPTH_STENCIL_STATE_PROPERTY_STENCIL_MASK) != 0) {
-            HandleError("Stencilmask property set multiple times");
-            return;
-        }
-
-        mPropertiesSet |= DEPTH_STENCIL_STATE_PROPERTY_STENCIL_MASK;
-        mStencilInfo.readMask = readMask;
-        mStencilInfo.writeMask = writeMask;
-    }
-
-}  // namespace dawn_native
diff --git a/src/dawn_native/DepthStencilState.h b/src/dawn_native/DepthStencilState.h
deleted file mode 100644
index 46da7e9..0000000
--- a/src/dawn_native/DepthStencilState.h
+++ /dev/null
@@ -1,78 +0,0 @@
-// Copyright 2017 The Dawn Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef DAWNNATIVE_DEPTHSTENCILSTATE_H_
-#define DAWNNATIVE_DEPTHSTENCILSTATE_H_
-
-#include "dawn_native/Builder.h"
-#include "dawn_native/Forward.h"
-#include "dawn_native/ObjectBase.h"
-
-#include "dawn_native/dawn_platform.h"
-
-namespace dawn_native {
-
-    class DepthStencilStateBase : public ObjectBase {
-      public:
-        DepthStencilStateBase(DepthStencilStateBuilder* builder);
-
-        struct DepthInfo {
-            dawn::CompareFunction compareFunction = dawn::CompareFunction::Always;
-            bool depthWriteEnabled = false;
-        };
-
-        struct StencilInfo {
-            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;
-        };
-
-        bool StencilTestEnabled() const;
-        const DepthInfo& GetDepth() const;
-        const StencilInfo& GetStencil() const;
-
-      private:
-        DepthInfo mDepthInfo;
-        StencilInfo mStencilInfo;
-    };
-
-    class DepthStencilStateBuilder : public Builder<DepthStencilStateBase> {
-      public:
-        DepthStencilStateBuilder(DeviceBase* device);
-
-        // Dawn API
-        void SetDepthCompareFunction(dawn::CompareFunction depthCompareFunction);
-        void SetDepthWriteEnabled(bool enabled);
-        void SetStencilFunction(dawn::Face face, const StencilStateFaceDescriptor* descriptor);
-        void SetStencilMask(uint32_t readMask, uint32_t writeMask);
-
-      private:
-        friend class DepthStencilStateBase;
-
-        DepthStencilStateBase* GetResultImpl() override;
-
-        int mPropertiesSet = 0;
-
-        DepthStencilStateBase::DepthInfo mDepthInfo;
-        DepthStencilStateBase::StencilInfo mStencilInfo;
-    };
-
-}  // namespace dawn_native
-
-#endif  // DAWNNATIVE_DEPTHSTENCILSTATE_H_
diff --git a/src/dawn_native/Device.cpp b/src/dawn_native/Device.cpp
index c94dc11..100b607 100644
--- a/src/dawn_native/Device.cpp
+++ b/src/dawn_native/Device.cpp
@@ -19,7 +19,6 @@
 #include "dawn_native/Buffer.h"
 #include "dawn_native/CommandBuffer.h"
 #include "dawn_native/ComputePipeline.h"
-#include "dawn_native/DepthStencilState.h"
 #include "dawn_native/ErrorData.h"
 #include "dawn_native/Fence.h"
 #include "dawn_native/FenceSignalTracker.h"
@@ -141,9 +140,6 @@
 
         return result;
     }
-    DepthStencilStateBuilder* DeviceBase::CreateDepthStencilStateBuilder() {
-        return new DepthStencilStateBuilder(this);
-    }
     FenceBase* DeviceBase::CreateFence(const FenceDescriptor* descriptor) {
         FenceBase* result = nullptr;
 
diff --git a/src/dawn_native/Device.h b/src/dawn_native/Device.h
index 012cb22..79e1a35 100644
--- a/src/dawn_native/Device.h
+++ b/src/dawn_native/Device.h
@@ -52,8 +52,6 @@
         FenceSignalTracker* GetFenceSignalTracker() const;
 
         virtual CommandBufferBase* CreateCommandBuffer(CommandBufferBuilder* builder) = 0;
-        virtual DepthStencilStateBase* CreateDepthStencilState(
-            DepthStencilStateBuilder* builder) = 0;
         virtual InputStateBase* CreateInputState(InputStateBuilder* builder) = 0;
         virtual RenderPassDescriptorBase* CreateRenderPassDescriptor(
             RenderPassDescriptorBuilder* builder) = 0;
@@ -87,7 +85,6 @@
         BufferBase* CreateBuffer(const BufferDescriptor* descriptor);
         CommandBufferBuilder* CreateCommandBufferBuilder();
         ComputePipelineBase* CreateComputePipeline(const ComputePipelineDescriptor* descriptor);
-        DepthStencilStateBuilder* CreateDepthStencilStateBuilder();
         FenceBase* CreateFence(const FenceDescriptor* descriptor);
         InputStateBuilder* CreateInputStateBuilder();
         PipelineLayoutBase* CreatePipelineLayout(const PipelineLayoutDescriptor* descriptor);
diff --git a/src/dawn_native/Forward.h b/src/dawn_native/Forward.h
index 93e6352..05b3f80 100644
--- a/src/dawn_native/Forward.h
+++ b/src/dawn_native/Forward.h
@@ -29,8 +29,6 @@
     class CommandBufferBase;
     class CommandBufferBuilder;
     class ComputePassEncoderBase;
-    class DepthStencilStateBase;
-    class DepthStencilStateBuilder;
     class FenceBase;
     class InputStateBase;
     class InputStateBuilder;
diff --git a/src/dawn_native/Pipeline.cpp b/src/dawn_native/Pipeline.cpp
index 175e864..fb2a311 100644
--- a/src/dawn_native/Pipeline.cpp
+++ b/src/dawn_native/Pipeline.cpp
@@ -14,7 +14,6 @@
 
 #include "dawn_native/Pipeline.h"
 
-#include "dawn_native/DepthStencilState.h"
 #include "dawn_native/Device.h"
 #include "dawn_native/InputState.h"
 #include "dawn_native/PipelineLayout.h"
diff --git a/src/dawn_native/RenderPipeline.cpp b/src/dawn_native/RenderPipeline.cpp
index 1fde80a..fc25d37 100644
--- a/src/dawn_native/RenderPipeline.cpp
+++ b/src/dawn_native/RenderPipeline.cpp
@@ -15,7 +15,6 @@
 #include "dawn_native/RenderPipeline.h"
 
 #include "common/BitSetIterator.h"
-#include "dawn_native/DepthStencilState.h"
 #include "dawn_native/Device.h"
 #include "dawn_native/InputState.h"
 #include "dawn_native/RenderPassDescriptor.h"
@@ -86,7 +85,24 @@
             return {};
         }
 
-    }  // namespace
+        MaybeError ValidateDepthStencilStateDescriptor(
+            const DepthStencilStateDescriptor* descriptor) {
+            if (descriptor->nextInChain != nullptr) {
+                return DAWN_VALIDATION_ERROR("nextInChain must be nullptr");
+            }
+            DAWN_TRY(ValidateCompareFunction(descriptor->depthCompare));
+            DAWN_TRY(ValidateCompareFunction(descriptor->front.compare));
+            DAWN_TRY(ValidateStencilOperation(descriptor->front.stencilFailOp));
+            DAWN_TRY(ValidateStencilOperation(descriptor->front.depthFailOp));
+            DAWN_TRY(ValidateStencilOperation(descriptor->front.passOp));
+            DAWN_TRY(ValidateCompareFunction(descriptor->back.compare));
+            DAWN_TRY(ValidateStencilOperation(descriptor->back.stencilFailOp));
+            DAWN_TRY(ValidateStencilOperation(descriptor->back.depthFailOp));
+            DAWN_TRY(ValidateStencilOperation(descriptor->back.passOp));
+            return {};
+        }
+
+    }  // anonymous namespace
 
     MaybeError ValidateRenderPipelineDescriptor(DeviceBase* device,
                                                 const RenderPipelineDescriptor* descriptor) {
@@ -137,10 +153,22 @@
             return DAWN_VALIDATION_ERROR("Each color attachment should have blend state");
         }
 
-        // TODO: validate depth stencil state
+        DAWN_TRY(ValidateDepthStencilStateDescriptor(descriptor->depthStencilState));
+
         return {};
     }
 
+    bool StencilTestEnabled(const DepthStencilStateDescriptor* mDepthStencilState) {
+        return mDepthStencilState->back.compare != dawn::CompareFunction::Always ||
+               mDepthStencilState->back.stencilFailOp != dawn::StencilOperation::Keep ||
+               mDepthStencilState->back.depthFailOp != dawn::StencilOperation::Keep ||
+               mDepthStencilState->back.passOp != dawn::StencilOperation::Keep ||
+               mDepthStencilState->front.compare != dawn::CompareFunction::Always ||
+               mDepthStencilState->front.stencilFailOp != dawn::StencilOperation::Keep ||
+               mDepthStencilState->front.depthFailOp != dawn::StencilOperation::Keep ||
+               mDepthStencilState->front.passOp != dawn::StencilOperation::Keep;
+    }
+
     // RenderPipelineBase
 
     RenderPipelineBase::RenderPipelineBase(DeviceBase* device,
@@ -148,7 +176,7 @@
         : PipelineBase(device,
                        descriptor->layout,
                        dawn::ShaderStageBit::Vertex | dawn::ShaderStageBit::Fragment),
-          mDepthStencilState(descriptor->depthStencilState),
+          mDepthStencilState(*descriptor->depthStencilState),
           mIndexFormat(descriptor->indexFormat),
           mInputState(descriptor->inputState),
           mPrimitiveTopology(descriptor->primitiveTopology),
@@ -175,8 +203,8 @@
         return &mBlendStates[attachmentSlot];
     }
 
-    DepthStencilStateBase* RenderPipelineBase::GetDepthStencilState() {
-        return mDepthStencilState.Get();
+    const DepthStencilStateDescriptor* RenderPipelineBase::GetDepthStencilStateDescriptor() {
+        return &mDepthStencilState;
     }
 
     dawn::IndexFormat RenderPipelineBase::GetIndexFormat() const {
diff --git a/src/dawn_native/RenderPipeline.h b/src/dawn_native/RenderPipeline.h
index 35cf013..2ede129 100644
--- a/src/dawn_native/RenderPipeline.h
+++ b/src/dawn_native/RenderPipeline.h
@@ -15,7 +15,6 @@
 #ifndef DAWNNATIVE_RENDERPIPELINE_H_
 #define DAWNNATIVE_RENDERPIPELINE_H_
 
-#include "dawn_native/DepthStencilState.h"
 #include "dawn_native/InputState.h"
 #include "dawn_native/Pipeline.h"
 
@@ -30,13 +29,14 @@
 
     MaybeError ValidateRenderPipelineDescriptor(DeviceBase* device,
                                                 const RenderPipelineDescriptor* descriptor);
+    bool StencilTestEnabled(const DepthStencilStateDescriptor* mDepthStencilState);
 
     class RenderPipelineBase : public PipelineBase {
       public:
         RenderPipelineBase(DeviceBase* device, const RenderPipelineDescriptor* descriptor);
 
         const BlendStateDescriptor* GetBlendStateDescriptor(uint32_t attachmentSlot);
-        DepthStencilStateBase* GetDepthStencilState();
+        const DepthStencilStateDescriptor* GetDepthStencilStateDescriptor();
         dawn::IndexFormat GetIndexFormat() const;
         InputStateBase* GetInputState();
         dawn::PrimitiveTopology GetPrimitiveTopology() const;
@@ -51,7 +51,7 @@
         bool IsCompatibleWith(const RenderPassDescriptorBase* renderPass) const;
 
       private:
-        Ref<DepthStencilStateBase> mDepthStencilState;
+        DepthStencilStateDescriptor mDepthStencilState;
         dawn::IndexFormat mIndexFormat;
         Ref<InputStateBase> mInputState;
         dawn::PrimitiveTopology mPrimitiveTopology;
diff --git a/src/dawn_native/ToBackend.h b/src/dawn_native/ToBackend.h
index 34b7492..94391f3 100644
--- a/src/dawn_native/ToBackend.h
+++ b/src/dawn_native/ToBackend.h
@@ -49,11 +49,6 @@
     };
 
     template <typename BackendTraits>
-    struct ToBackendTraits<DepthStencilStateBase, BackendTraits> {
-        using BackendType = typename BackendTraits::DepthStencilStateType;
-    };
-
-    template <typename BackendTraits>
     struct ToBackendTraits<DeviceBase, BackendTraits> {
         using BackendType = typename BackendTraits::DeviceType;
     };
diff --git a/src/dawn_native/d3d12/DepthStencilStateD3D12.cpp b/src/dawn_native/d3d12/DepthStencilStateD3D12.cpp
deleted file mode 100644
index 05d04c4..0000000
--- a/src/dawn_native/d3d12/DepthStencilStateD3D12.cpp
+++ /dev/null
@@ -1,99 +0,0 @@
-// Copyright 2017 The Dawn Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "dawn_native/d3d12/DepthStencilStateD3D12.h"
-
-#include "common/BitSetIterator.h"
-
-namespace dawn_native { namespace d3d12 {
-
-    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();
-            }
-        }
-
-        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_DEPTH_STENCILOP_DESC StencilOpDesc(const StencilStateFaceDescriptor descriptor) {
-            D3D12_DEPTH_STENCILOP_DESC desc;
-
-            desc.StencilFailOp = StencilOp(descriptor.stencilFailOp);
-            desc.StencilDepthFailOp = StencilOp(descriptor.depthFailOp);
-            desc.StencilPassOp = StencilOp(descriptor.passOp);
-            desc.StencilFunc = ComparisonFunc(descriptor.compare);
-
-            return desc;
-        }
-    }  // anonymous namespace
-
-    DepthStencilState::DepthStencilState(DepthStencilStateBuilder* builder)
-        : DepthStencilStateBase(builder) {
-        mDepthStencilDescriptor.DepthEnable = TRUE;
-        mDepthStencilDescriptor.DepthWriteMask =
-            GetDepth().depthWriteEnabled ? D3D12_DEPTH_WRITE_MASK_ALL : D3D12_DEPTH_WRITE_MASK_ZERO;
-        mDepthStencilDescriptor.DepthFunc = ComparisonFunc(GetDepth().compareFunction);
-
-        mDepthStencilDescriptor.StencilEnable = StencilTestEnabled() ? TRUE : FALSE;
-        mDepthStencilDescriptor.StencilReadMask = static_cast<UINT8>(GetStencil().readMask);
-        mDepthStencilDescriptor.StencilWriteMask = static_cast<UINT8>(GetStencil().writeMask);
-
-        mDepthStencilDescriptor.FrontFace = StencilOpDesc(GetStencil().front);
-        mDepthStencilDescriptor.BackFace = StencilOpDesc(GetStencil().back);
-    }
-
-    const D3D12_DEPTH_STENCIL_DESC& DepthStencilState::GetD3D12DepthStencilDescriptor() const {
-        return mDepthStencilDescriptor;
-    }
-
-}}  // namespace dawn_native::d3d12
diff --git a/src/dawn_native/d3d12/DepthStencilStateD3D12.h b/src/dawn_native/d3d12/DepthStencilStateD3D12.h
deleted file mode 100644
index e7041b7..0000000
--- a/src/dawn_native/d3d12/DepthStencilStateD3D12.h
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2017 The Dawn Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef DAWNNATIVE_D3D12_DEPTHSTENCILSTATED3D12_H_
-#define DAWNNATIVE_D3D12_DEPTHSTENCILSTATED3D12_H_
-
-#include "dawn_native/DepthStencilState.h"
-
-#include "dawn_native/d3d12/d3d12_platform.h"
-
-namespace dawn_native { namespace d3d12 {
-
-    class Device;
-
-    class DepthStencilState : public DepthStencilStateBase {
-      public:
-        DepthStencilState(DepthStencilStateBuilder* builder);
-
-        const D3D12_DEPTH_STENCIL_DESC& GetD3D12DepthStencilDescriptor() const;
-
-      private:
-        D3D12_DEPTH_STENCIL_DESC mDepthStencilDescriptor;
-    };
-
-}}  // namespace dawn_native::d3d12
-
-#endif  // DAWNNATIVE_D3D12_DEPTHSTENCILSTATED3D12_H_
diff --git a/src/dawn_native/d3d12/DeviceD3D12.cpp b/src/dawn_native/d3d12/DeviceD3D12.cpp
index 5bfc7cc..2d9f6be 100644
--- a/src/dawn_native/d3d12/DeviceD3D12.cpp
+++ b/src/dawn_native/d3d12/DeviceD3D12.cpp
@@ -23,7 +23,6 @@
 #include "dawn_native/d3d12/CommandAllocatorManager.h"
 #include "dawn_native/d3d12/CommandBufferD3D12.h"
 #include "dawn_native/d3d12/ComputePipelineD3D12.h"
-#include "dawn_native/d3d12/DepthStencilStateD3D12.h"
 #include "dawn_native/d3d12/DescriptorHeapAllocator.h"
 #include "dawn_native/d3d12/InputStateD3D12.h"
 #include "dawn_native/d3d12/NativeSwapChainImplD3D12.h"
@@ -303,9 +302,6 @@
         const ComputePipelineDescriptor* descriptor) {
         return new ComputePipeline(this, descriptor);
     }
-    DepthStencilStateBase* Device::CreateDepthStencilState(DepthStencilStateBuilder* builder) {
-        return new DepthStencilState(builder);
-    }
     InputStateBase* Device::CreateInputState(InputStateBuilder* builder) {
         return new InputState(builder);
     }
diff --git a/src/dawn_native/d3d12/DeviceD3D12.h b/src/dawn_native/d3d12/DeviceD3D12.h
index 70341ae..8230227 100644
--- a/src/dawn_native/d3d12/DeviceD3D12.h
+++ b/src/dawn_native/d3d12/DeviceD3D12.h
@@ -42,7 +42,6 @@
         ~Device();
 
         CommandBufferBase* CreateCommandBuffer(CommandBufferBuilder* builder) override;
-        DepthStencilStateBase* CreateDepthStencilState(DepthStencilStateBuilder* builder) override;
         InputStateBase* CreateInputState(InputStateBuilder* builder) override;
         RenderPassDescriptorBase* CreateRenderPassDescriptor(
             RenderPassDescriptorBuilder* builder) override;
diff --git a/src/dawn_native/d3d12/Forward.h b/src/dawn_native/d3d12/Forward.h
index d3b6b44..49d1375 100644
--- a/src/dawn_native/d3d12/Forward.h
+++ b/src/dawn_native/d3d12/Forward.h
@@ -24,7 +24,6 @@
     class Buffer;
     class CommandBuffer;
     class ComputePipeline;
-    class DepthStencilState;
     class Device;
     class InputState;
     class PipelineLayout;
@@ -43,7 +42,6 @@
         using BufferType = Buffer;
         using CommandBufferType = CommandBuffer;
         using ComputePipelineType = ComputePipeline;
-        using DepthStencilStateType = DepthStencilState;
         using DeviceType = Device;
         using InputStateType = InputState;
         using PipelineLayoutType = PipelineLayout;
diff --git a/src/dawn_native/d3d12/RenderPipelineD3D12.cpp b/src/dawn_native/d3d12/RenderPipelineD3D12.cpp
index 2866485..ffd103d 100644
--- a/src/dawn_native/d3d12/RenderPipelineD3D12.cpp
+++ b/src/dawn_native/d3d12/RenderPipelineD3D12.cpp
@@ -15,7 +15,6 @@
 #include "dawn_native/d3d12/RenderPipelineD3D12.h"
 
 #include "common/Assert.h"
-#include "dawn_native/d3d12/DepthStencilStateD3D12.h"
 #include "dawn_native/d3d12/DeviceD3D12.h"
 #include "dawn_native/d3d12/InputStateD3D12.h"
 #include "dawn_native/d3d12/PipelineLayoutD3D12.h"
@@ -142,7 +141,85 @@
             blendDesc.LogicOp = D3D12_LOGIC_OP_NOOP;
             return blendDesc;
         }
-    }  // 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();
+            }
+        }
+
+        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_DEPTH_STENCILOP_DESC StencilOpDesc(const StencilStateFaceDescriptor descriptor) {
+            D3D12_DEPTH_STENCILOP_DESC desc;
+
+            desc.StencilFailOp = StencilOp(descriptor.stencilFailOp);
+            desc.StencilDepthFailOp = StencilOp(descriptor.depthFailOp);
+            desc.StencilPassOp = StencilOp(descriptor.passOp);
+            desc.StencilFunc = ComparisonFunc(descriptor.compare);
+
+            return desc;
+        }
+
+        D3D12_DEPTH_STENCIL_DESC ComputeDepthStencilDesc(
+            const DepthStencilStateDescriptor* descriptor) {
+            D3D12_DEPTH_STENCIL_DESC mDepthStencilDescriptor;
+            mDepthStencilDescriptor.DepthEnable = TRUE;
+            mDepthStencilDescriptor.DepthWriteMask = descriptor->depthWriteEnabled
+                                                         ? D3D12_DEPTH_WRITE_MASK_ALL
+                                                         : D3D12_DEPTH_WRITE_MASK_ZERO;
+            mDepthStencilDescriptor.DepthFunc = ComparisonFunc(descriptor->depthCompare);
+
+            mDepthStencilDescriptor.StencilEnable = StencilTestEnabled(descriptor) ? TRUE : FALSE;
+            mDepthStencilDescriptor.StencilReadMask =
+                static_cast<UINT8>(descriptor->stencilReadMask);
+            mDepthStencilDescriptor.StencilWriteMask =
+                static_cast<UINT8>(descriptor->stencilWriteMask);
+
+            mDepthStencilDescriptor.FrontFace = StencilOpDesc(descriptor->front);
+            mDepthStencilDescriptor.BackFace = StencilOpDesc(descriptor->back);
+            return mDepthStencilDescriptor;
+        }
+
+    }  // anonymous namespace
 
     RenderPipeline::RenderPipeline(Device* device, const RenderPipelineDescriptor* descriptor)
         : RenderPipelineBase(device, descriptor),
@@ -239,8 +316,8 @@
         descriptorD3D12.BlendState.AlphaToCoverageEnable = FALSE;
         descriptorD3D12.BlendState.IndependentBlendEnable = TRUE;
 
-        DepthStencilState* depthStencilState = ToBackend(GetDepthStencilState());
-        descriptorD3D12.DepthStencilState = depthStencilState->GetD3D12DepthStencilDescriptor();
+        descriptorD3D12.DepthStencilState =
+            ComputeDepthStencilDesc(GetDepthStencilStateDescriptor());
 
         descriptorD3D12.SampleMask = UINT_MAX;
         descriptorD3D12.PrimitiveTopologyType = D3D12PrimitiveTopologyType(GetPrimitiveTopology());
diff --git a/src/dawn_native/metal/CommandBufferMTL.mm b/src/dawn_native/metal/CommandBufferMTL.mm
index cbd8262..22f8241 100644
--- a/src/dawn_native/metal/CommandBufferMTL.mm
+++ b/src/dawn_native/metal/CommandBufferMTL.mm
@@ -18,7 +18,6 @@
 #include "dawn_native/Commands.h"
 #include "dawn_native/metal/BufferMTL.h"
 #include "dawn_native/metal/ComputePipelineMTL.h"
-#include "dawn_native/metal/DepthStencilStateMTL.h"
 #include "dawn_native/metal/DeviceMTL.h"
 #include "dawn_native/metal/InputStateMTL.h"
 #include "dawn_native/metal/PipelineLayoutMTL.h"
@@ -435,9 +434,7 @@
                     SetRenderPipelineCmd* cmd = mCommands.NextCommand<SetRenderPipelineCmd>();
                     lastPipeline = ToBackend(cmd->pipeline).Get();
 
-                    DepthStencilState* depthStencilState =
-                        ToBackend(lastPipeline->GetDepthStencilState());
-                    [encoder setDepthStencilState:depthStencilState->GetMTLDepthStencilState()];
+                    [encoder setDepthStencilState:lastPipeline->GetMTLDepthStencilState()];
                     lastPipeline->Encode(encoder);
                 } break;
 
diff --git a/src/dawn_native/metal/DepthStencilStateMTL.h b/src/dawn_native/metal/DepthStencilStateMTL.h
deleted file mode 100644
index c33fadf..0000000
--- a/src/dawn_native/metal/DepthStencilStateMTL.h
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright 2017 The Dawn Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef DAWNNATIVE_METAL_DEPTHSTENCILSTATEMTL_H_
-#define DAWNNATIVE_METAL_DEPTHSTENCILSTATEMTL_H_
-
-#include "dawn_native/DepthStencilState.h"
-
-#import <Metal/Metal.h>
-
-namespace dawn_native { namespace metal {
-
-    class Device;
-
-    class DepthStencilState : public DepthStencilStateBase {
-      public:
-        DepthStencilState(DepthStencilStateBuilder* builder);
-        ~DepthStencilState();
-
-        id<MTLDepthStencilState> GetMTLDepthStencilState();
-
-      private:
-        id<MTLDepthStencilState> mMtlDepthStencilState = nil;
-    };
-
-}}  // namespace dawn_native::metal
-
-#endif  // DAWNNATIVE_METAL_DEPTHSTENCILSTATEMTL_H_
diff --git a/src/dawn_native/metal/DepthStencilStateMTL.mm b/src/dawn_native/metal/DepthStencilStateMTL.mm
deleted file mode 100644
index 8ff2431..0000000
--- a/src/dawn_native/metal/DepthStencilStateMTL.mm
+++ /dev/null
@@ -1,120 +0,0 @@
-// Copyright 2017 The Dawn Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "dawn_native/metal/DepthStencilStateMTL.h"
-
-#include "dawn_native/metal/DeviceMTL.h"
-
-namespace dawn_native { namespace metal {
-
-    namespace {
-        MTLCompareFunction MetalDepthStencilCompareFunction(dawn::CompareFunction compareFunction) {
-            switch (compareFunction) {
-                case dawn::CompareFunction::Never:
-                    return MTLCompareFunctionNever;
-                case dawn::CompareFunction::Less:
-                    return MTLCompareFunctionLess;
-                case dawn::CompareFunction::LessEqual:
-                    return MTLCompareFunctionLessEqual;
-                case dawn::CompareFunction::Greater:
-                    return MTLCompareFunctionGreater;
-                case dawn::CompareFunction::GreaterEqual:
-                    return MTLCompareFunctionGreaterEqual;
-                case dawn::CompareFunction::NotEqual:
-                    return MTLCompareFunctionNotEqual;
-                case dawn::CompareFunction::Equal:
-                    return MTLCompareFunctionEqual;
-                case dawn::CompareFunction::Always:
-                    return MTLCompareFunctionAlways;
-            }
-        }
-
-        MTLStencilOperation MetalStencilOperation(dawn::StencilOperation stencilOperation) {
-            switch (stencilOperation) {
-                case dawn::StencilOperation::Keep:
-                    return MTLStencilOperationKeep;
-                case dawn::StencilOperation::Zero:
-                    return MTLStencilOperationZero;
-                case dawn::StencilOperation::Replace:
-                    return MTLStencilOperationReplace;
-                case dawn::StencilOperation::Invert:
-                    return MTLStencilOperationInvert;
-                case dawn::StencilOperation::IncrementClamp:
-                    return MTLStencilOperationIncrementClamp;
-                case dawn::StencilOperation::DecrementClamp:
-                    return MTLStencilOperationDecrementClamp;
-                case dawn::StencilOperation::IncrementWrap:
-                    return MTLStencilOperationIncrementWrap;
-                case dawn::StencilOperation::DecrementWrap:
-                    return MTLStencilOperationDecrementWrap;
-            }
-        }
-    }
-
-    DepthStencilState::DepthStencilState(DepthStencilStateBuilder* builder)
-        : DepthStencilStateBase(builder) {
-        MTLDepthStencilDescriptor* mtlDepthStencilDescriptor = [MTLDepthStencilDescriptor new];
-
-        auto& depth = GetDepth();
-        mtlDepthStencilDescriptor.depthCompareFunction =
-            MetalDepthStencilCompareFunction(depth.compareFunction);
-        mtlDepthStencilDescriptor.depthWriteEnabled = depth.depthWriteEnabled;
-
-        auto& stencil = GetStencil();
-        if (StencilTestEnabled()) {
-            MTLStencilDescriptor* backFaceStencil = [MTLStencilDescriptor new];
-            MTLStencilDescriptor* frontFaceStencil = [MTLStencilDescriptor new];
-
-            backFaceStencil.stencilCompareFunction =
-                MetalDepthStencilCompareFunction(stencil.back.compare);
-            backFaceStencil.stencilFailureOperation =
-                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.compare);
-            frontFaceStencil.stencilFailureOperation =
-                MetalStencilOperation(stencil.front.stencilFailOp);
-            frontFaceStencil.depthFailureOperation =
-                MetalStencilOperation(stencil.front.depthFailOp);
-            frontFaceStencil.depthStencilPassOperation =
-                MetalStencilOperation(stencil.front.passOp);
-            frontFaceStencil.readMask = stencil.readMask;
-            frontFaceStencil.writeMask = stencil.writeMask;
-
-            mtlDepthStencilDescriptor.backFaceStencil = backFaceStencil;
-            mtlDepthStencilDescriptor.frontFaceStencil = frontFaceStencil;
-            [backFaceStencil release];
-            [frontFaceStencil release];
-        }
-
-        auto mtlDevice = ToBackend(builder->GetDevice())->GetMTLDevice();
-        mMtlDepthStencilState =
-            [mtlDevice newDepthStencilStateWithDescriptor:mtlDepthStencilDescriptor];
-        [mtlDepthStencilDescriptor release];
-    }
-
-    DepthStencilState::~DepthStencilState() {
-        [mMtlDepthStencilState release];
-        mMtlDepthStencilState = nil;
-    }
-
-    id<MTLDepthStencilState> DepthStencilState::GetMTLDepthStencilState() {
-        return mMtlDepthStencilState;
-    }
-
-}}  // namespace dawn_native::metal
diff --git a/src/dawn_native/metal/DeviceMTL.h b/src/dawn_native/metal/DeviceMTL.h
index 9aeb4a7..fa96d4e 100644
--- a/src/dawn_native/metal/DeviceMTL.h
+++ b/src/dawn_native/metal/DeviceMTL.h
@@ -38,7 +38,6 @@
         ~Device();
 
         CommandBufferBase* CreateCommandBuffer(CommandBufferBuilder* builder) override;
-        DepthStencilStateBase* CreateDepthStencilState(DepthStencilStateBuilder* builder) override;
         InputStateBase* CreateInputState(InputStateBuilder* builder) override;
         RenderPassDescriptorBase* CreateRenderPassDescriptor(
             RenderPassDescriptorBuilder* builder) override;
diff --git a/src/dawn_native/metal/DeviceMTL.mm b/src/dawn_native/metal/DeviceMTL.mm
index 8f88822..b11018a 100644
--- a/src/dawn_native/metal/DeviceMTL.mm
+++ b/src/dawn_native/metal/DeviceMTL.mm
@@ -21,7 +21,6 @@
 #include "dawn_native/metal/BufferMTL.h"
 #include "dawn_native/metal/CommandBufferMTL.h"
 #include "dawn_native/metal/ComputePipelineMTL.h"
-#include "dawn_native/metal/DepthStencilStateMTL.h"
 #include "dawn_native/metal/InputStateMTL.h"
 #include "dawn_native/metal/PipelineLayoutMTL.h"
 #include "dawn_native/metal/QueueMTL.h"
@@ -179,9 +178,6 @@
         const ComputePipelineDescriptor* descriptor) {
         return new ComputePipeline(this, descriptor);
     }
-    DepthStencilStateBase* Device::CreateDepthStencilState(DepthStencilStateBuilder* builder) {
-        return new DepthStencilState(builder);
-    }
     InputStateBase* Device::CreateInputState(InputStateBuilder* builder) {
         return new InputState(builder);
     }
diff --git a/src/dawn_native/metal/Forward.h b/src/dawn_native/metal/Forward.h
index 6e67558..599a797 100644
--- a/src/dawn_native/metal/Forward.h
+++ b/src/dawn_native/metal/Forward.h
@@ -30,7 +30,6 @@
     class Buffer;
     class CommandBuffer;
     class ComputePipeline;
-    class DepthStencilState;
     class Device;
     class Framebuffer;
     class InputState;
@@ -50,7 +49,6 @@
         using BufferType = Buffer;
         using CommandBufferType = CommandBuffer;
         using ComputePipelineType = ComputePipeline;
-        using DepthStencilStateType = DepthStencilState;
         using DeviceType = Device;
         using InputStateType = InputState;
         using PipelineLayoutType = PipelineLayout;
diff --git a/src/dawn_native/metal/RenderPipelineMTL.h b/src/dawn_native/metal/RenderPipelineMTL.h
index ff58cc9..6da06e2 100644
--- a/src/dawn_native/metal/RenderPipelineMTL.h
+++ b/src/dawn_native/metal/RenderPipelineMTL.h
@@ -33,10 +33,13 @@
 
         void Encode(id<MTLRenderCommandEncoder> encoder);
 
+        id<MTLDepthStencilState> GetMTLDepthStencilState();
+
       private:
         MTLIndexType mMtlIndexType;
         MTLPrimitiveType mMtlPrimitiveTopology;
         id<MTLRenderPipelineState> mMtlRenderPipelineState = nil;
+        id<MTLDepthStencilState> mMtlDepthStencilState = nil;
     };
 
 }}  // namespace dawn_native::metal
diff --git a/src/dawn_native/metal/RenderPipelineMTL.mm b/src/dawn_native/metal/RenderPipelineMTL.mm
index b8ba954..15822b4 100644
--- a/src/dawn_native/metal/RenderPipelineMTL.mm
+++ b/src/dawn_native/metal/RenderPipelineMTL.mm
@@ -14,7 +14,6 @@
 
 #include "dawn_native/metal/RenderPipelineMTL.h"
 
-#include "dawn_native/metal/DepthStencilStateMTL.h"
 #include "dawn_native/metal/DeviceMTL.h"
 #include "dawn_native/metal/InputStateMTL.h"
 #include "dawn_native/metal/PipelineLayoutMTL.h"
@@ -143,6 +142,89 @@
             attachment.alphaBlendOperation = MetalBlendOperation(descriptor->alphaBlend.operation);
             attachment.writeMask = MetalColorWriteMask(descriptor->colorWriteMask);
         }
+
+        MTLCompareFunction MetalDepthStencilCompareFunction(dawn::CompareFunction compareFunction) {
+            switch (compareFunction) {
+                case dawn::CompareFunction::Never:
+                    return MTLCompareFunctionNever;
+                case dawn::CompareFunction::Less:
+                    return MTLCompareFunctionLess;
+                case dawn::CompareFunction::LessEqual:
+                    return MTLCompareFunctionLessEqual;
+                case dawn::CompareFunction::Greater:
+                    return MTLCompareFunctionGreater;
+                case dawn::CompareFunction::GreaterEqual:
+                    return MTLCompareFunctionGreaterEqual;
+                case dawn::CompareFunction::NotEqual:
+                    return MTLCompareFunctionNotEqual;
+                case dawn::CompareFunction::Equal:
+                    return MTLCompareFunctionEqual;
+                case dawn::CompareFunction::Always:
+                    return MTLCompareFunctionAlways;
+            }
+        }
+
+        MTLStencilOperation MetalStencilOperation(dawn::StencilOperation stencilOperation) {
+            switch (stencilOperation) {
+                case dawn::StencilOperation::Keep:
+                    return MTLStencilOperationKeep;
+                case dawn::StencilOperation::Zero:
+                    return MTLStencilOperationZero;
+                case dawn::StencilOperation::Replace:
+                    return MTLStencilOperationReplace;
+                case dawn::StencilOperation::Invert:
+                    return MTLStencilOperationInvert;
+                case dawn::StencilOperation::IncrementClamp:
+                    return MTLStencilOperationIncrementClamp;
+                case dawn::StencilOperation::DecrementClamp:
+                    return MTLStencilOperationDecrementClamp;
+                case dawn::StencilOperation::IncrementWrap:
+                    return MTLStencilOperationIncrementWrap;
+                case dawn::StencilOperation::DecrementWrap:
+                    return MTLStencilOperationDecrementWrap;
+            }
+        }
+
+        MTLDepthStencilDescriptor* ComputeDepthStencilDesc(
+            const DepthStencilStateDescriptor* descriptor) {
+            MTLDepthStencilDescriptor* mtlDepthStencilDescriptor =
+                [[MTLDepthStencilDescriptor new] autorelease];
+            mtlDepthStencilDescriptor.depthCompareFunction =
+                MetalDepthStencilCompareFunction(descriptor->depthCompare);
+            mtlDepthStencilDescriptor.depthWriteEnabled = descriptor->depthWriteEnabled;
+
+            if (StencilTestEnabled(descriptor)) {
+                MTLStencilDescriptor* backFaceStencil = [[MTLStencilDescriptor new] autorelease];
+                MTLStencilDescriptor* frontFaceStencil = [[MTLStencilDescriptor new] autorelease];
+
+                backFaceStencil.stencilCompareFunction =
+                    MetalDepthStencilCompareFunction(descriptor->back.compare);
+                backFaceStencil.stencilFailureOperation =
+                    MetalStencilOperation(descriptor->back.stencilFailOp);
+                backFaceStencil.depthFailureOperation =
+                    MetalStencilOperation(descriptor->back.depthFailOp);
+                backFaceStencil.depthStencilPassOperation =
+                    MetalStencilOperation(descriptor->back.passOp);
+                backFaceStencil.readMask = descriptor->stencilReadMask;
+                backFaceStencil.writeMask = descriptor->stencilWriteMask;
+
+                frontFaceStencil.stencilCompareFunction =
+                    MetalDepthStencilCompareFunction(descriptor->front.compare);
+                frontFaceStencil.stencilFailureOperation =
+                    MetalStencilOperation(descriptor->front.stencilFailOp);
+                frontFaceStencil.depthFailureOperation =
+                    MetalStencilOperation(descriptor->front.depthFailOp);
+                frontFaceStencil.depthStencilPassOperation =
+                    MetalStencilOperation(descriptor->front.passOp);
+                frontFaceStencil.readMask = descriptor->stencilReadMask;
+                frontFaceStencil.writeMask = descriptor->stencilWriteMask;
+
+                mtlDepthStencilDescriptor.backFaceStencil = backFaceStencil;
+                mtlDepthStencilDescriptor.frontFaceStencil = frontFaceStencil;
+            }
+            return mtlDepthStencilDescriptor;
+        }
+
     }  // anonymous namespace
 
     RenderPipeline::RenderPipeline(Device* device, const RenderPipelineDescriptor* descriptor)
@@ -186,21 +268,29 @@
 
         // TODO(kainino@chromium.org): push constants, textures, samplers
 
-        NSError* error = nil;
-        mMtlRenderPipelineState = [mtlDevice newRenderPipelineStateWithDescriptor:descriptorMTL
-                                                                            error:&error];
-        if (error != nil) {
-            NSLog(@" error => %@", error);
-            device->HandleError("Error creating rendering pipeline state");
+        {
+            NSError* error = nil;
+            mMtlRenderPipelineState = [mtlDevice newRenderPipelineStateWithDescriptor:descriptorMTL
+                                                                                error:&error];
             [descriptorMTL release];
-            return;
+            if (error != nil) {
+                NSLog(@" error => %@", error);
+                device->HandleError("Error creating rendering pipeline state");
+                return;
+            }
         }
 
-        [descriptorMTL release];
+        // create depth stencil state and cache it, fetch the cached depth stencil state when we
+        // call setDepthStencilState() for a given render pipeline in CommandBuffer, in order to
+        // improve performance.
+        mMtlDepthStencilState =
+            [mtlDevice newDepthStencilStateWithDescriptor:ComputeDepthStencilDesc(
+                                                              GetDepthStencilStateDescriptor())];
     }
 
     RenderPipeline::~RenderPipeline() {
         [mMtlRenderPipelineState release];
+        [mMtlDepthStencilState release];
     }
 
     MTLIndexType RenderPipeline::GetMTLIndexType() const {
@@ -215,4 +305,8 @@
         [encoder setRenderPipelineState:mMtlRenderPipelineState];
     }
 
+    id<MTLDepthStencilState> RenderPipeline::GetMTLDepthStencilState() {
+        return mMtlDepthStencilState;
+    }
+
 }}  // namespace dawn_native::metal
diff --git a/src/dawn_native/null/NullBackend.cpp b/src/dawn_native/null/NullBackend.cpp
index 4c84785..aa3ec7f 100644
--- a/src/dawn_native/null/NullBackend.cpp
+++ b/src/dawn_native/null/NullBackend.cpp
@@ -52,9 +52,6 @@
         const ComputePipelineDescriptor* descriptor) {
         return new ComputePipeline(this, descriptor);
     }
-    DepthStencilStateBase* Device::CreateDepthStencilState(DepthStencilStateBuilder* builder) {
-        return new DepthStencilState(builder);
-    }
     InputStateBase* Device::CreateInputState(InputStateBuilder* builder) {
         return new InputState(builder);
     }
diff --git a/src/dawn_native/null/NullBackend.h b/src/dawn_native/null/NullBackend.h
index aecb4df..15a25f3 100644
--- a/src/dawn_native/null/NullBackend.h
+++ b/src/dawn_native/null/NullBackend.h
@@ -22,7 +22,6 @@
 #include "dawn_native/Buffer.h"
 #include "dawn_native/CommandBuffer.h"
 #include "dawn_native/ComputePipeline.h"
-#include "dawn_native/DepthStencilState.h"
 #include "dawn_native/Device.h"
 #include "dawn_native/InputState.h"
 #include "dawn_native/PipelineLayout.h"
@@ -42,7 +41,6 @@
     class Buffer;
     class CommandBuffer;
     using ComputePipeline = ComputePipelineBase;
-    using DepthStencilState = DepthStencilStateBase;
     class Device;
     using InputState = InputStateBase;
     using PipelineLayout = PipelineLayoutBase;
@@ -61,7 +59,6 @@
         using BufferType = Buffer;
         using CommandBufferType = CommandBuffer;
         using ComputePipelineType = ComputePipeline;
-        using DepthStencilStateType = DepthStencilState;
         using DeviceType = Device;
         using InputStateType = InputState;
         using PipelineLayoutType = PipelineLayout;
@@ -91,7 +88,6 @@
         ~Device();
 
         CommandBufferBase* CreateCommandBuffer(CommandBufferBuilder* builder) override;
-        DepthStencilStateBase* CreateDepthStencilState(DepthStencilStateBuilder* builder) override;
         InputStateBase* CreateInputState(InputStateBuilder* builder) override;
         RenderPassDescriptorBase* CreateRenderPassDescriptor(
             RenderPassDescriptorBuilder* builder) override;
diff --git a/src/dawn_native/opengl/DepthStencilStateGL.cpp b/src/dawn_native/opengl/DepthStencilStateGL.cpp
deleted file mode 100644
index b71aa7f..0000000
--- a/src/dawn_native/opengl/DepthStencilStateGL.cpp
+++ /dev/null
@@ -1,116 +0,0 @@
-// Copyright 2017 The Dawn Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "dawn_native/opengl/DepthStencilStateGL.h"
-
-#include "common/Assert.h"
-#include "dawn_native/opengl/PersistentPipelineStateGL.h"
-
-namespace dawn_native { namespace opengl {
-
-    namespace {
-        GLuint OpenGLCompareFunction(dawn::CompareFunction compareFunction) {
-            switch (compareFunction) {
-                case dawn::CompareFunction::Never:
-                    return GL_NEVER;
-                case dawn::CompareFunction::Less:
-                    return GL_LESS;
-                case dawn::CompareFunction::LessEqual:
-                    return GL_LEQUAL;
-                case dawn::CompareFunction::Greater:
-                    return GL_GREATER;
-                case dawn::CompareFunction::GreaterEqual:
-                    return GL_GEQUAL;
-                case dawn::CompareFunction::NotEqual:
-                    return GL_NOTEQUAL;
-                case dawn::CompareFunction::Equal:
-                    return GL_EQUAL;
-                case dawn::CompareFunction::Always:
-                    return GL_ALWAYS;
-                default:
-                    UNREACHABLE();
-            }
-        }
-
-        GLuint OpenGLStencilOperation(dawn::StencilOperation stencilOperation) {
-            switch (stencilOperation) {
-                case dawn::StencilOperation::Keep:
-                    return GL_KEEP;
-                case dawn::StencilOperation::Zero:
-                    return GL_ZERO;
-                case dawn::StencilOperation::Replace:
-                    return GL_REPLACE;
-                case dawn::StencilOperation::Invert:
-                    return GL_INVERT;
-                case dawn::StencilOperation::IncrementClamp:
-                    return GL_INCR;
-                case dawn::StencilOperation::DecrementClamp:
-                    return GL_DECR;
-                case dawn::StencilOperation::IncrementWrap:
-                    return GL_INCR_WRAP;
-                case dawn::StencilOperation::DecrementWrap:
-                    return GL_DECR_WRAP;
-                default:
-                    UNREACHABLE();
-            }
-        }
-    }  // namespace
-
-    DepthStencilState::DepthStencilState(DepthStencilStateBuilder* builder)
-        : DepthStencilStateBase(builder) {
-    }
-
-    void DepthStencilState::ApplyNow(PersistentPipelineState& persistentPipelineState) const {
-        auto& depthInfo = GetDepth();
-
-        // Depth writes only occur if depth is enabled
-        if (depthInfo.compareFunction == dawn::CompareFunction::Always &&
-            !depthInfo.depthWriteEnabled) {
-            glDisable(GL_DEPTH_TEST);
-        } else {
-            glEnable(GL_DEPTH_TEST);
-        }
-
-        if (depthInfo.depthWriteEnabled) {
-            glDepthMask(GL_TRUE);
-        } else {
-            glDepthMask(GL_FALSE);
-        }
-
-        glDepthFunc(OpenGLCompareFunction(depthInfo.compareFunction));
-
-        if (StencilTestEnabled()) {
-            glEnable(GL_STENCIL_TEST);
-        } else {
-            glDisable(GL_STENCIL_TEST);
-        }
-
-        auto& stencilInfo = GetStencil();
-
-        GLenum backCompareFunction = OpenGLCompareFunction(stencilInfo.back.compare);
-        GLenum frontCompareFunction = OpenGLCompareFunction(stencilInfo.front.compare);
-        persistentPipelineState.SetStencilFuncsAndMask(backCompareFunction, frontCompareFunction,
-                                                       stencilInfo.readMask);
-
-        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);
-    }
-
-}}  // namespace dawn_native::opengl
diff --git a/src/dawn_native/opengl/DepthStencilStateGL.h b/src/dawn_native/opengl/DepthStencilStateGL.h
deleted file mode 100644
index da06830..0000000
--- a/src/dawn_native/opengl/DepthStencilStateGL.h
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2017 The Dawn Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef DAWNNATIVE_OPENGL_DEPTHSTENCILSTATEGL_H_
-#define DAWNNATIVE_OPENGL_DEPTHSTENCILSTATEGL_H_
-
-#include "dawn_native/DepthStencilState.h"
-
-namespace dawn_native { namespace opengl {
-
-    class Device;
-    class PersistentPipelineState;
-
-    class DepthStencilState : public DepthStencilStateBase {
-      public:
-        DepthStencilState(DepthStencilStateBuilder* builder);
-
-        void ApplyNow(PersistentPipelineState& persistentPipelineState) const;
-    };
-
-}}  // namespace dawn_native::opengl
-
-#endif  // DAWNNATIVE_OPENGL_DEPTHSTENCILSTATEGL_H_
diff --git a/src/dawn_native/opengl/DeviceGL.cpp b/src/dawn_native/opengl/DeviceGL.cpp
index fec3004..7afd520 100644
--- a/src/dawn_native/opengl/DeviceGL.cpp
+++ b/src/dawn_native/opengl/DeviceGL.cpp
@@ -21,7 +21,6 @@
 #include "dawn_native/opengl/BufferGL.h"
 #include "dawn_native/opengl/CommandBufferGL.h"
 #include "dawn_native/opengl/ComputePipelineGL.h"
-#include "dawn_native/opengl/DepthStencilStateGL.h"
 #include "dawn_native/opengl/InputStateGL.h"
 #include "dawn_native/opengl/PipelineLayoutGL.h"
 #include "dawn_native/opengl/QueueGL.h"
@@ -78,9 +77,6 @@
         const ComputePipelineDescriptor* descriptor) {
         return new ComputePipeline(this, descriptor);
     }
-    DepthStencilStateBase* Device::CreateDepthStencilState(DepthStencilStateBuilder* builder) {
-        return new DepthStencilState(builder);
-    }
     InputStateBase* Device::CreateInputState(InputStateBuilder* builder) {
         return new InputState(builder);
     }
diff --git a/src/dawn_native/opengl/DeviceGL.h b/src/dawn_native/opengl/DeviceGL.h
index 8216035..b32d269 100644
--- a/src/dawn_native/opengl/DeviceGL.h
+++ b/src/dawn_native/opengl/DeviceGL.h
@@ -41,7 +41,6 @@
 
         // Dawn API
         CommandBufferBase* CreateCommandBuffer(CommandBufferBuilder* builder) override;
-        DepthStencilStateBase* CreateDepthStencilState(DepthStencilStateBuilder* builder) override;
         InputStateBase* CreateInputState(InputStateBuilder* builder) override;
         RenderPassDescriptorBase* CreateRenderPassDescriptor(
             RenderPassDescriptorBuilder* builder) override;
diff --git a/src/dawn_native/opengl/Forward.h b/src/dawn_native/opengl/Forward.h
index 1c5942f..49c381c 100644
--- a/src/dawn_native/opengl/Forward.h
+++ b/src/dawn_native/opengl/Forward.h
@@ -30,7 +30,6 @@
     class Buffer;
     class CommandBuffer;
     class ComputePipeline;
-    class DepthStencilState;
     class Device;
     class InputState;
     class PersistentPipelineState;
@@ -50,7 +49,6 @@
         using BufferType = Buffer;
         using CommandBufferType = CommandBuffer;
         using ComputePipelineType = ComputePipeline;
-        using DepthStencilStateType = DepthStencilState;
         using DeviceType = Device;
         using InputStateType = InputState;
         using PipelineLayoutType = PipelineLayout;
diff --git a/src/dawn_native/opengl/RenderPipelineGL.cpp b/src/dawn_native/opengl/RenderPipelineGL.cpp
index fec187a..9d14fc4 100644
--- a/src/dawn_native/opengl/RenderPipelineGL.cpp
+++ b/src/dawn_native/opengl/RenderPipelineGL.cpp
@@ -14,7 +14,6 @@
 
 #include "dawn_native/opengl/RenderPipelineGL.h"
 
-#include "dawn_native/opengl/DepthStencilStateGL.h"
 #include "dawn_native/opengl/DeviceGL.h"
 #include "dawn_native/opengl/Forward.h"
 #include "dawn_native/opengl/InputStateGL.h"
@@ -109,7 +108,92 @@
                          descriptor->colorWriteMask & dawn::ColorWriteMask::Alpha);
         }
 
-    }  // namespace
+        GLuint OpenGLCompareFunction(dawn::CompareFunction compareFunction) {
+            switch (compareFunction) {
+                case dawn::CompareFunction::Never:
+                    return GL_NEVER;
+                case dawn::CompareFunction::Less:
+                    return GL_LESS;
+                case dawn::CompareFunction::LessEqual:
+                    return GL_LEQUAL;
+                case dawn::CompareFunction::Greater:
+                    return GL_GREATER;
+                case dawn::CompareFunction::GreaterEqual:
+                    return GL_GEQUAL;
+                case dawn::CompareFunction::NotEqual:
+                    return GL_NOTEQUAL;
+                case dawn::CompareFunction::Equal:
+                    return GL_EQUAL;
+                case dawn::CompareFunction::Always:
+                    return GL_ALWAYS;
+                default:
+                    UNREACHABLE();
+            }
+        }
+
+        GLuint OpenGLStencilOperation(dawn::StencilOperation stencilOperation) {
+            switch (stencilOperation) {
+                case dawn::StencilOperation::Keep:
+                    return GL_KEEP;
+                case dawn::StencilOperation::Zero:
+                    return GL_ZERO;
+                case dawn::StencilOperation::Replace:
+                    return GL_REPLACE;
+                case dawn::StencilOperation::Invert:
+                    return GL_INVERT;
+                case dawn::StencilOperation::IncrementClamp:
+                    return GL_INCR;
+                case dawn::StencilOperation::DecrementClamp:
+                    return GL_DECR;
+                case dawn::StencilOperation::IncrementWrap:
+                    return GL_INCR_WRAP;
+                case dawn::StencilOperation::DecrementWrap:
+                    return GL_DECR_WRAP;
+                default:
+                    UNREACHABLE();
+            }
+        }
+
+        void ApplyDepthStencilState(const DepthStencilStateDescriptor* descriptor,
+                                    PersistentPipelineState* persistentPipelineState) {
+            // Depth writes only occur if depth is enabled
+            if (descriptor->depthCompare == dawn::CompareFunction::Always &&
+                !descriptor->depthWriteEnabled) {
+                glDisable(GL_DEPTH_TEST);
+            } else {
+                glEnable(GL_DEPTH_TEST);
+            }
+
+            if (descriptor->depthWriteEnabled) {
+                glDepthMask(GL_TRUE);
+            } else {
+                glDepthMask(GL_FALSE);
+            }
+
+            glDepthFunc(OpenGLCompareFunction(descriptor->depthCompare));
+
+            if (StencilTestEnabled(descriptor)) {
+                glEnable(GL_STENCIL_TEST);
+            } else {
+                glDisable(GL_STENCIL_TEST);
+            }
+
+            GLenum backCompareFunction = OpenGLCompareFunction(descriptor->back.compare);
+            GLenum frontCompareFunction = OpenGLCompareFunction(descriptor->front.compare);
+            persistentPipelineState->SetStencilFuncsAndMask(
+                backCompareFunction, frontCompareFunction, descriptor->stencilReadMask);
+
+            glStencilOpSeparate(GL_BACK, OpenGLStencilOperation(descriptor->back.stencilFailOp),
+                                OpenGLStencilOperation(descriptor->back.depthFailOp),
+                                OpenGLStencilOperation(descriptor->back.passOp));
+            glStencilOpSeparate(GL_FRONT, OpenGLStencilOperation(descriptor->front.stencilFailOp),
+                                OpenGLStencilOperation(descriptor->front.depthFailOp),
+                                OpenGLStencilOperation(descriptor->front.passOp));
+
+            glStencilMask(descriptor->stencilWriteMask);
+        }
+
+    }  // anonymous namespace
 
     RenderPipeline::RenderPipeline(Device* device, const RenderPipelineDescriptor* descriptor)
         : RenderPipelineBase(device, descriptor),
@@ -131,8 +215,7 @@
         auto inputState = ToBackend(GetInputState());
         glBindVertexArray(inputState->GetVAO());
 
-        auto depthStencilState = ToBackend(GetDepthStencilState());
-        depthStencilState->ApplyNow(persistentPipelineState);
+        ApplyDepthStencilState(GetDepthStencilStateDescriptor(), &persistentPipelineState);
 
         for (uint32_t attachmentSlot : IterateBitSet(GetColorAttachmentsMask())) {
             ApplyBlendState(attachmentSlot, GetBlendStateDescriptor(attachmentSlot));
diff --git a/src/dawn_native/vulkan/DepthStencilStateVk.cpp b/src/dawn_native/vulkan/DepthStencilStateVk.cpp
deleted file mode 100644
index 2f6472c..0000000
--- a/src/dawn_native/vulkan/DepthStencilStateVk.cpp
+++ /dev/null
@@ -1,116 +0,0 @@
-// Copyright 2018 The Dawn Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "dawn_native/vulkan/DepthStencilStateVk.h"
-
-#include "common/Assert.h"
-
-namespace dawn_native { namespace vulkan {
-
-    namespace {
-        VkCompareOp VulkanCompareOp(dawn::CompareFunction op) {
-            switch (op) {
-                case dawn::CompareFunction::Always:
-                    return VK_COMPARE_OP_ALWAYS;
-                case dawn::CompareFunction::Equal:
-                    return VK_COMPARE_OP_EQUAL;
-                case dawn::CompareFunction::Greater:
-                    return VK_COMPARE_OP_GREATER;
-                case dawn::CompareFunction::GreaterEqual:
-                    return VK_COMPARE_OP_GREATER_OR_EQUAL;
-                case dawn::CompareFunction::Less:
-                    return VK_COMPARE_OP_LESS;
-                case dawn::CompareFunction::LessEqual:
-                    return VK_COMPARE_OP_LESS_OR_EQUAL;
-                case dawn::CompareFunction::Never:
-                    return VK_COMPARE_OP_NEVER;
-                case dawn::CompareFunction::NotEqual:
-                    return VK_COMPARE_OP_NOT_EQUAL;
-                default:
-                    UNREACHABLE();
-            }
-        }
-
-        VkStencilOp VulkanStencilOp(dawn::StencilOperation op) {
-            switch (op) {
-                case dawn::StencilOperation::Keep:
-                    return VK_STENCIL_OP_KEEP;
-                case dawn::StencilOperation::Zero:
-                    return VK_STENCIL_OP_ZERO;
-                case dawn::StencilOperation::Replace:
-                    return VK_STENCIL_OP_REPLACE;
-                case dawn::StencilOperation::IncrementClamp:
-                    return VK_STENCIL_OP_INCREMENT_AND_CLAMP;
-                case dawn::StencilOperation::DecrementClamp:
-                    return VK_STENCIL_OP_DECREMENT_AND_CLAMP;
-                case dawn::StencilOperation::Invert:
-                    return VK_STENCIL_OP_INVERT;
-                case dawn::StencilOperation::IncrementWrap:
-                    return VK_STENCIL_OP_INCREMENT_AND_WRAP;
-                case dawn::StencilOperation::DecrementWrap:
-                    return VK_STENCIL_OP_DECREMENT_AND_WRAP;
-                default:
-                    UNREACHABLE();
-            }
-        }
-
-    }  // anonymous namespace
-
-    DepthStencilState::DepthStencilState(DepthStencilStateBuilder* builder)
-        : DepthStencilStateBase(builder) {
-        mCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
-        mCreateInfo.pNext = nullptr;
-        mCreateInfo.flags = 0;
-
-        const auto& depth = GetDepth();
-        // Depth writes only occur if depth is enabled
-        mCreateInfo.depthTestEnable =
-            (depth.compareFunction == dawn::CompareFunction::Always && !depth.depthWriteEnabled)
-                ? VK_FALSE
-                : VK_TRUE;
-        mCreateInfo.depthWriteEnable = depth.depthWriteEnabled ? VK_TRUE : VK_FALSE;
-        mCreateInfo.depthCompareOp = VulkanCompareOp(depth.compareFunction);
-        mCreateInfo.depthBoundsTestEnable = false;
-        mCreateInfo.minDepthBounds = 0.0f;
-        mCreateInfo.maxDepthBounds = 1.0f;
-
-        const auto& stencil = GetStencil();
-        mCreateInfo.stencilTestEnable = StencilTestEnabled() ? VK_TRUE : VK_FALSE;
-
-        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.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;
-        mCreateInfo.back.compareMask = stencil.readMask;
-        mCreateInfo.front.writeMask = stencil.writeMask;
-        mCreateInfo.back.writeMask = stencil.writeMask;
-
-        // The stencil reference is always dynamic
-        mCreateInfo.front.reference = 0;
-        mCreateInfo.back.reference = 0;
-    }
-
-    const VkPipelineDepthStencilStateCreateInfo* DepthStencilState::GetCreateInfo() const {
-        return &mCreateInfo;
-    }
-
-}}  // namespace dawn_native::vulkan
diff --git a/src/dawn_native/vulkan/DepthStencilStateVk.h b/src/dawn_native/vulkan/DepthStencilStateVk.h
deleted file mode 100644
index 1f9a2a5..0000000
--- a/src/dawn_native/vulkan/DepthStencilStateVk.h
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright 2018 The Dawn Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef DAWNNATIVE_VULKAN_DEPTHSTENCILSTATEVK_H_
-#define DAWNNATIVE_VULKAN_DEPTHSTENCILSTATEVK_H_
-
-#include "dawn_native/DepthStencilState.h"
-
-#include "common/vulkan_platform.h"
-
-namespace dawn_native { namespace vulkan {
-
-    class Device;
-
-    // Pre-computes the depth-stencil configuration to give to a graphics pipeline create info.
-    class DepthStencilState : public DepthStencilStateBase {
-      public:
-        DepthStencilState(DepthStencilStateBuilder* builder);
-
-        const VkPipelineDepthStencilStateCreateInfo* GetCreateInfo() const;
-
-      private:
-        VkPipelineDepthStencilStateCreateInfo mCreateInfo;
-    };
-
-}}  // namespace dawn_native::vulkan
-
-#endif  // DAWNNATIVE_VULKAN_DEPTHSTENCILSTATEVK_H_
diff --git a/src/dawn_native/vulkan/DeviceVk.cpp b/src/dawn_native/vulkan/DeviceVk.cpp
index 3e78b5e..1a33e61 100644
--- a/src/dawn_native/vulkan/DeviceVk.cpp
+++ b/src/dawn_native/vulkan/DeviceVk.cpp
@@ -25,7 +25,6 @@
 #include "dawn_native/vulkan/BufferVk.h"
 #include "dawn_native/vulkan/CommandBufferVk.h"
 #include "dawn_native/vulkan/ComputePipelineVk.h"
-#include "dawn_native/vulkan/DepthStencilStateVk.h"
 #include "dawn_native/vulkan/FencedDeleter.h"
 #include "dawn_native/vulkan/InputStateVk.h"
 #include "dawn_native/vulkan/NativeSwapChainImplVk.h"
@@ -237,9 +236,6 @@
         const ComputePipelineDescriptor* descriptor) {
         return new ComputePipeline(this, descriptor);
     }
-    DepthStencilStateBase* Device::CreateDepthStencilState(DepthStencilStateBuilder* builder) {
-        return new DepthStencilState(builder);
-    }
     InputStateBase* Device::CreateInputState(InputStateBuilder* builder) {
         return new InputState(builder);
     }
diff --git a/src/dawn_native/vulkan/DeviceVk.h b/src/dawn_native/vulkan/DeviceVk.h
index 086b706..4ff27d41 100644
--- a/src/dawn_native/vulkan/DeviceVk.h
+++ b/src/dawn_native/vulkan/DeviceVk.h
@@ -64,7 +64,6 @@
 
         // Dawn API
         CommandBufferBase* CreateCommandBuffer(CommandBufferBuilder* builder) override;
-        DepthStencilStateBase* CreateDepthStencilState(DepthStencilStateBuilder* builder) override;
         InputStateBase* CreateInputState(InputStateBuilder* builder) override;
         RenderPassDescriptorBase* CreateRenderPassDescriptor(
             RenderPassDescriptorBuilder* builder) override;
diff --git a/src/dawn_native/vulkan/Forward.h b/src/dawn_native/vulkan/Forward.h
index 3e43e32..36b35ce 100644
--- a/src/dawn_native/vulkan/Forward.h
+++ b/src/dawn_native/vulkan/Forward.h
@@ -24,7 +24,6 @@
     class Buffer;
     class CommandBuffer;
     class ComputePipeline;
-    class DepthStencilState;
     class Device;
     class InputState;
     class PipelineLayout;
@@ -43,7 +42,6 @@
         using BufferType = Buffer;
         using CommandBufferType = CommandBuffer;
         using ComputePipelineType = ComputePipeline;
-        using DepthStencilStateType = DepthStencilState;
         using DeviceType = Device;
         using InputStateType = InputState;
         using PipelineLayoutType = PipelineLayout;
diff --git a/src/dawn_native/vulkan/RenderPipelineVk.cpp b/src/dawn_native/vulkan/RenderPipelineVk.cpp
index a1ef014..481ab1b 100644
--- a/src/dawn_native/vulkan/RenderPipelineVk.cpp
+++ b/src/dawn_native/vulkan/RenderPipelineVk.cpp
@@ -14,7 +14,6 @@
 
 #include "dawn_native/vulkan/RenderPipelineVk.h"
 
-#include "dawn_native/vulkan/DepthStencilStateVk.h"
 #include "dawn_native/vulkan/DeviceVk.h"
 #include "dawn_native/vulkan/FencedDeleter.h"
 #include "dawn_native/vulkan/InputStateVk.h"
@@ -126,6 +125,97 @@
             return attachment;
         }
 
+        VkCompareOp VulkanCompareOp(dawn::CompareFunction op) {
+            switch (op) {
+                case dawn::CompareFunction::Always:
+                    return VK_COMPARE_OP_ALWAYS;
+                case dawn::CompareFunction::Equal:
+                    return VK_COMPARE_OP_EQUAL;
+                case dawn::CompareFunction::Greater:
+                    return VK_COMPARE_OP_GREATER;
+                case dawn::CompareFunction::GreaterEqual:
+                    return VK_COMPARE_OP_GREATER_OR_EQUAL;
+                case dawn::CompareFunction::Less:
+                    return VK_COMPARE_OP_LESS;
+                case dawn::CompareFunction::LessEqual:
+                    return VK_COMPARE_OP_LESS_OR_EQUAL;
+                case dawn::CompareFunction::Never:
+                    return VK_COMPARE_OP_NEVER;
+                case dawn::CompareFunction::NotEqual:
+                    return VK_COMPARE_OP_NOT_EQUAL;
+                default:
+                    UNREACHABLE();
+            }
+        }
+
+        VkStencilOp VulkanStencilOp(dawn::StencilOperation op) {
+            switch (op) {
+                case dawn::StencilOperation::Keep:
+                    return VK_STENCIL_OP_KEEP;
+                case dawn::StencilOperation::Zero:
+                    return VK_STENCIL_OP_ZERO;
+                case dawn::StencilOperation::Replace:
+                    return VK_STENCIL_OP_REPLACE;
+                case dawn::StencilOperation::IncrementClamp:
+                    return VK_STENCIL_OP_INCREMENT_AND_CLAMP;
+                case dawn::StencilOperation::DecrementClamp:
+                    return VK_STENCIL_OP_DECREMENT_AND_CLAMP;
+                case dawn::StencilOperation::Invert:
+                    return VK_STENCIL_OP_INVERT;
+                case dawn::StencilOperation::IncrementWrap:
+                    return VK_STENCIL_OP_INCREMENT_AND_WRAP;
+                case dawn::StencilOperation::DecrementWrap:
+                    return VK_STENCIL_OP_DECREMENT_AND_WRAP;
+                default:
+                    UNREACHABLE();
+            }
+        }
+
+        VkPipelineDepthStencilStateCreateInfo ComputeDepthStencilDesc(
+            const DepthStencilStateDescriptor* descriptor) {
+            VkPipelineDepthStencilStateCreateInfo depthStencilState;
+            depthStencilState.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
+            depthStencilState.pNext = nullptr;
+            depthStencilState.flags = 0;
+
+            // Depth writes only occur if depth is enabled
+            depthStencilState.depthTestEnable =
+                (descriptor->depthCompare == dawn::CompareFunction::Always &&
+                 !descriptor->depthWriteEnabled)
+                    ? VK_FALSE
+                    : VK_TRUE;
+            depthStencilState.depthWriteEnable = descriptor->depthWriteEnabled ? VK_TRUE : VK_FALSE;
+            depthStencilState.depthCompareOp = VulkanCompareOp(descriptor->depthCompare);
+            depthStencilState.depthBoundsTestEnable = false;
+            depthStencilState.minDepthBounds = 0.0f;
+            depthStencilState.maxDepthBounds = 1.0f;
+
+            depthStencilState.stencilTestEnable =
+                StencilTestEnabled(descriptor) ? VK_TRUE : VK_FALSE;
+
+            depthStencilState.front.failOp = VulkanStencilOp(descriptor->front.stencilFailOp);
+            depthStencilState.front.passOp = VulkanStencilOp(descriptor->front.passOp);
+            depthStencilState.front.depthFailOp = VulkanStencilOp(descriptor->front.depthFailOp);
+            depthStencilState.front.compareOp = VulkanCompareOp(descriptor->front.compare);
+
+            depthStencilState.back.failOp = VulkanStencilOp(descriptor->back.stencilFailOp);
+            depthStencilState.back.passOp = VulkanStencilOp(descriptor->back.passOp);
+            depthStencilState.back.depthFailOp = VulkanStencilOp(descriptor->back.depthFailOp);
+            depthStencilState.back.compareOp = VulkanCompareOp(descriptor->back.compare);
+
+            // Dawn doesn't have separate front and back stencil masks.
+            depthStencilState.front.compareMask = descriptor->stencilReadMask;
+            depthStencilState.back.compareMask = descriptor->stencilReadMask;
+            depthStencilState.front.writeMask = descriptor->stencilWriteMask;
+            depthStencilState.back.writeMask = descriptor->stencilWriteMask;
+
+            // The stencil reference is always dynamic
+            depthStencilState.front.reference = 0;
+            depthStencilState.back.reference = 0;
+
+            return depthStencilState;
+        }
+
     }  // anonymous namespace
 
     RenderPipeline::RenderPipeline(Device* device, const RenderPipelineDescriptor* descriptor)
@@ -210,6 +300,9 @@
         multisample.alphaToCoverageEnable = VK_FALSE;
         multisample.alphaToOneEnable = VK_FALSE;
 
+        VkPipelineDepthStencilStateCreateInfo depthStencilState =
+            ComputeDepthStencilDesc(GetDepthStencilStateDescriptor());
+
         // Initialize the "blend state info" that will be chained in the "create info" from the data
         // pre-computed in the BlendState
         std::array<VkPipelineColorBlendAttachmentState, kMaxColorAttachments> colorBlendAttachments;
@@ -279,7 +372,7 @@
         createInfo.pViewportState = &viewport;
         createInfo.pRasterizationState = &rasterization;
         createInfo.pMultisampleState = &multisample;
-        createInfo.pDepthStencilState = ToBackend(GetDepthStencilState())->GetCreateInfo();
+        createInfo.pDepthStencilState = &depthStencilState;
         createInfo.pColorBlendState = &colorBlend;
         createInfo.pDynamicState = &dynamic;
         createInfo.layout = ToBackend(GetLayout())->GetHandle();
diff --git a/src/tests/end2end/DepthStencilStateTests.cpp b/src/tests/end2end/DepthStencilStateTests.cpp
index e8782be..e68d447 100644
--- a/src/tests/end2end/DepthStencilStateTests.cpp
+++ b/src/tests/end2end/DepthStencilStateTests.cpp
@@ -110,7 +110,7 @@
         }
 
         struct TestSpec {
-            const dawn::DepthStencilState& depthStencilState;
+            const dawn::DepthStencilStateDescriptor& depthStencilState;
             RGBA8 color;
             float depth;
             uint32_t stencil;
@@ -119,15 +119,27 @@
         // Check whether a depth comparison function works as expected
         // The less, equal, greater booleans denote wether the respective triangle should be visible based on the comparison function
         void CheckDepthCompareFunction(dawn::CompareFunction compareFunction, bool less, bool equal, bool greater) {
-            dawn::DepthStencilState baseState = device.CreateDepthStencilStateBuilder()
-                .SetDepthCompareFunction(dawn::CompareFunction::Always)
-                .SetDepthWriteEnabled(true)
-                .GetResult();
+            dawn::StencilStateFaceDescriptor stencilFace;
+            stencilFace.compare = dawn::CompareFunction::Always;
+            stencilFace.stencilFailOp = dawn::StencilOperation::Keep;
+            stencilFace.depthFailOp = dawn::StencilOperation::Keep;
+            stencilFace.passOp = dawn::StencilOperation::Keep;
 
-            dawn::DepthStencilState state = device.CreateDepthStencilStateBuilder()
-                .SetDepthCompareFunction(compareFunction)
-                .SetDepthWriteEnabled(true)
-                .GetResult();
+            dawn::DepthStencilStateDescriptor baseState;
+            baseState.depthWriteEnabled = true;
+            baseState.depthCompare = dawn::CompareFunction::Always;
+            baseState.back = stencilFace;
+            baseState.front = stencilFace;
+            baseState.stencilReadMask = 0xff;
+            baseState.stencilWriteMask = 0xff;
+
+            dawn::DepthStencilStateDescriptor state;
+            state.depthWriteEnabled = true;
+            state.depthCompare = compareFunction;
+            state.back = stencilFace;
+            state.front = stencilFace;
+            state.stencilReadMask = 0xff;
+            state.stencilWriteMask = 0xff;
 
             RGBA8 baseColor = RGBA8(255, 255, 255, 255);
             RGBA8 lessColor = RGBA8(255, 0, 0, 255);
@@ -155,20 +167,26 @@
             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::DepthStencilStateDescriptor baseState;
+            baseState.depthWriteEnabled = false;
+            baseState.depthCompare = dawn::CompareFunction::Always;
+            baseState.back = baseStencilFaceDescriptor;
+            baseState.front = baseStencilFaceDescriptor;
+            baseState.stencilReadMask = 0xff;
+            baseState.stencilWriteMask = 0xff;
 
             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();
+            dawn::DepthStencilStateDescriptor state;
+            state.depthWriteEnabled = false;
+            state.depthCompare = dawn::CompareFunction::Always;
+            state.back = stencilFaceDescriptor;
+            state.front = stencilFaceDescriptor;
+            state.stencilReadMask = 0xff;
+            state.stencilWriteMask = 0xff;
 
             RGBA8 baseColor = RGBA8(255, 255, 255, 255);
             RGBA8 lessColor = RGBA8(255, 0, 0, 255);
@@ -195,20 +213,26 @@
             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::DepthStencilStateDescriptor baseState;
+            baseState.depthWriteEnabled = false;
+            baseState.depthCompare = dawn::CompareFunction::Always;
+            baseState.back = baseStencilFaceDescriptor;
+            baseState.front = baseStencilFaceDescriptor;
+            baseState.stencilReadMask = 0xff;
+            baseState.stencilWriteMask = 0xff;
 
             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();
+            dawn::DepthStencilStateDescriptor state;
+            state.depthWriteEnabled = false;
+            state.depthCompare = dawn::CompareFunction::Always;
+            state.back = stencilFaceDescriptor;
+            state.front = stencilFaceDescriptor;
+            state.stencilReadMask = 0xff;
+            state.stencilWriteMask = 0xff;
 
             CheckStencil({
                 // Wipe the stencil buffer with the initialStencil value
@@ -226,10 +250,13 @@
             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();
+            dawn::DepthStencilStateDescriptor state;
+            state.depthWriteEnabled = false;
+            state.depthCompare = dawn::CompareFunction::Always;
+            state.back = stencilFaceDescriptor;
+            state.front = stencilFaceDescriptor;
+            state.stencilReadMask = 0xff;
+            state.stencilWriteMask = 0xff;
 
             testParams.push_back({ state, RGBA8(0, 255, 0, 255), 0, expectedStencil });
             DoTest(testParams, RGBA8(0, 255, 0, 255));
@@ -268,7 +295,7 @@
                 descriptor.cFragmentStage.module = fsModule;
                 descriptor.cAttachmentsState.hasDepthStencilAttachment = true;
                 descriptor.cDepthStencilAttachment.format = dawn::TextureFormat::D32FloatS8Uint;
-                descriptor.depthStencilState = test.depthStencilState;
+                descriptor.depthStencilState = &test.depthStencilState;
 
                 dawn::RenderPipeline pipeline = device.CreateRenderPipeline(&descriptor);
 
@@ -303,8 +330,19 @@
 
 // Test compilation and usage of the fixture
 TEST_P(DepthStencilStateTest, Basic) {
-    dawn::DepthStencilState state = device.CreateDepthStencilStateBuilder()
-        .GetResult();
+    dawn::StencilStateFaceDescriptor stencilFace;
+    stencilFace.compare = dawn::CompareFunction::Always;
+    stencilFace.stencilFailOp = dawn::StencilOperation::Keep;
+    stencilFace.depthFailOp = dawn::StencilOperation::Keep;
+    stencilFace.passOp = dawn::StencilOperation::Keep;
+
+    dawn::DepthStencilStateDescriptor state;
+    state.depthWriteEnabled = false;
+    state.depthCompare = dawn::CompareFunction::Always;
+    state.back = stencilFace;
+    state.front = stencilFace;
+    state.stencilReadMask = 0xff;
+    state.stencilWriteMask = 0xff;
 
     DoTest({
         { state, RGBA8(0, 255, 0, 255), 0.5f, 0u },
@@ -313,8 +351,19 @@
 
 // Test defaults: depth and stencil tests disabled
 TEST_P(DepthStencilStateTest, DepthStencilDisabled) {
-    dawn::DepthStencilState state = device.CreateDepthStencilStateBuilder()
-        .GetResult();
+    dawn::StencilStateFaceDescriptor stencilFace;
+    stencilFace.compare = dawn::CompareFunction::Always;
+    stencilFace.stencilFailOp = dawn::StencilOperation::Keep;
+    stencilFace.depthFailOp = dawn::StencilOperation::Keep;
+    stencilFace.passOp = dawn::StencilOperation::Keep;
+
+    dawn::DepthStencilStateDescriptor state;
+    state.depthWriteEnabled = false;
+    state.depthCompare = dawn::CompareFunction::Always;
+    state.back = stencilFace;
+    state.front = stencilFace;
+    state.stencilReadMask = 0xff;
+    state.stencilWriteMask = 0xff;
 
     TestSpec specs[3] = {
         { state, RGBA8(255, 0, 0, 255), 0.0f, 0u },
@@ -367,19 +416,35 @@
 
 // Test that disabling depth writes works and leaves the depth buffer unchanged
 TEST_P(DepthStencilStateTest, DepthWriteDisabled) {
-    dawn::DepthStencilState baseState = device.CreateDepthStencilStateBuilder()
-        .SetDepthCompareFunction(dawn::CompareFunction::Always)
-        .SetDepthWriteEnabled(true)
-        .GetResult();
+    dawn::StencilStateFaceDescriptor stencilFace;
+    stencilFace.compare = dawn::CompareFunction::Always;
+    stencilFace.stencilFailOp = dawn::StencilOperation::Keep;
+    stencilFace.depthFailOp = dawn::StencilOperation::Keep;
+    stencilFace.passOp = dawn::StencilOperation::Keep;
 
-    dawn::DepthStencilState noDepthWrite = device.CreateDepthStencilStateBuilder()
-        .SetDepthCompareFunction(dawn::CompareFunction::Always)
-        .SetDepthWriteEnabled(false)
-        .GetResult();
+    dawn::DepthStencilStateDescriptor baseState;
+    baseState.depthWriteEnabled = true;
+    baseState.depthCompare = dawn::CompareFunction::Always;
+    baseState.back = stencilFace;
+    baseState.front = stencilFace;
+    baseState.stencilReadMask = 0xff;
+    baseState.stencilWriteMask = 0xff;
 
-    dawn::DepthStencilState checkState = device.CreateDepthStencilStateBuilder()
-        .SetDepthCompareFunction(dawn::CompareFunction::Equal)
-        .GetResult();
+    dawn::DepthStencilStateDescriptor noDepthWrite;
+    noDepthWrite.depthWriteEnabled = false;
+    noDepthWrite.depthCompare = dawn::CompareFunction::Always;
+    noDepthWrite.back = stencilFace;
+    noDepthWrite.front = stencilFace;
+    noDepthWrite.stencilReadMask = 0xff;
+    noDepthWrite.stencilWriteMask = 0xff;
+
+    dawn::DepthStencilStateDescriptor checkState;
+    checkState.depthWriteEnabled = false;
+    checkState.depthCompare = dawn::CompareFunction::Equal;
+    checkState.back = stencilFace;
+    checkState.front = stencilFace;
+    checkState.stencilReadMask = 0xff;
+    checkState.stencilWriteMask = 0xff;
 
     DoTest({
         { baseState, RGBA8(255, 255, 255, 255), 1.f, 0u }, // Draw a base triangle with depth enabled
@@ -465,21 +530,26 @@
     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::DepthStencilStateDescriptor baseState;
+    baseState.depthWriteEnabled = false;
+    baseState.depthCompare = dawn::CompareFunction::Always;
+    baseState.back = baseStencilFaceDescriptor;
+    baseState.front = baseStencilFaceDescriptor;
+    baseState.stencilReadMask = 0xff;
+    baseState.stencilWriteMask = 0xff;
 
     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();
+    dawn::DepthStencilStateDescriptor state;
+    state.depthWriteEnabled = false;
+    state.depthCompare = dawn::CompareFunction::Always;
+    state.back = stencilFaceDescriptor;
+    state.front = stencilFaceDescriptor;
+    state.stencilReadMask = 0x2;
+    state.stencilWriteMask = 0xff;
 
     RGBA8 baseColor = RGBA8(255, 255, 255, 255);
     RGBA8 red = RGBA8(255, 0, 0, 255);
@@ -497,21 +567,26 @@
     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::DepthStencilStateDescriptor baseState;
+    baseState.depthWriteEnabled = false;
+    baseState.depthCompare = dawn::CompareFunction::Always;
+    baseState.back = baseStencilFaceDescriptor;
+    baseState.front = baseStencilFaceDescriptor;
+    baseState.stencilReadMask = 0xff;
+    baseState.stencilWriteMask = 0x1;
 
     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();
+    dawn::DepthStencilStateDescriptor state;
+    state.depthWriteEnabled = false;
+    state.depthCompare = dawn::CompareFunction::Always;
+    state.back = stencilFaceDescriptor;
+    state.front = stencilFaceDescriptor;
+    state.stencilReadMask = 0xff;
+    state.stencilWriteMask = 0xff;
 
     RGBA8 baseColor = RGBA8(255, 255, 255, 255);
     RGBA8 green = RGBA8(0, 255, 0, 255);
@@ -528,20 +603,26 @@
     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::DepthStencilStateDescriptor baseState;
+    baseState.depthWriteEnabled = false;
+    baseState.depthCompare = dawn::CompareFunction::Always;
+    baseState.back = baseStencilFaceDescriptor;
+    baseState.front = baseStencilFaceDescriptor;
+    baseState.stencilReadMask = 0xff;
+    baseState.stencilWriteMask = 0xff;
 
     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();
+    dawn::DepthStencilStateDescriptor state;
+    state.depthWriteEnabled = false;
+    state.depthCompare = dawn::CompareFunction::Always;
+    state.back = stencilFaceDescriptor;
+    state.front = stencilFaceDescriptor;
+    state.stencilReadMask = 0xff;
+    state.stencilWriteMask = 0xff;
 
     CheckStencil({
         { baseState, RGBA8(255, 255, 255, 255), 1.f, 1 },   // Triangle to set stencil value to 1
@@ -556,23 +637,26 @@
     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::DepthStencilStateDescriptor baseState;
+    baseState.depthWriteEnabled = true;
+    baseState.depthCompare = dawn::CompareFunction::Always;
+    baseState.back = baseStencilFaceDescriptor;
+    baseState.front = baseStencilFaceDescriptor;
+    baseState.stencilReadMask = 0xff;
+    baseState.stencilWriteMask = 0xff;
 
     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();
+    dawn::DepthStencilStateDescriptor state;
+    state.depthWriteEnabled = true;
+    state.depthCompare = dawn::CompareFunction::Less;
+    state.back = stencilFaceDescriptor;
+    state.front = stencilFaceDescriptor;
+    state.stencilReadMask = 0xff;
+    state.stencilWriteMask = 0xff;
 
     CheckStencil({
         { baseState, RGBA8(255, 255, 255, 255), 0.f, 1 },   // Triangle to set stencil value to 1. Depth is 0
@@ -587,23 +671,26 @@
     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::DepthStencilStateDescriptor baseState;
+    baseState.depthWriteEnabled = true;
+    baseState.depthCompare = dawn::CompareFunction::Always;
+    baseState.back = baseStencilFaceDescriptor;
+    baseState.front = baseStencilFaceDescriptor;
+    baseState.stencilReadMask = 0xff;
+    baseState.stencilWriteMask = 0xff;
 
     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();
+    dawn::DepthStencilStateDescriptor state;
+    state.depthWriteEnabled = true;
+    state.depthCompare = dawn::CompareFunction::Less;
+    state.back = stencilFaceDescriptor;
+    state.front = stencilFaceDescriptor;
+    state.stencilReadMask = 0xff;
+    state.stencilWriteMask = 0xff;
 
     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/WireTests.cpp b/src/tests/unittests/WireTests.cpp
index 6812271..aa08fea 100644
--- a/src/tests/unittests/WireTests.cpp
+++ b/src/tests/unittests/WireTests.cpp
@@ -350,15 +350,20 @@
         .WillOnce(Return(apiInputState));
 
     // Create the depth-stencil state
-    dawnDepthStencilStateBuilder depthStencilStateBuilder = dawnDeviceCreateDepthStencilStateBuilder(device);
-    dawnDepthStencilStateBuilder apiDepthStencilStateBuilder = api.GetNewDepthStencilStateBuilder();
-    EXPECT_CALL(api, DeviceCreateDepthStencilStateBuilder(apiDevice))
-        .WillOnce(Return(apiDepthStencilStateBuilder));
+    dawnStencilStateFaceDescriptor stencilFace;
+    stencilFace.compare = DAWN_COMPARE_FUNCTION_ALWAYS;
+    stencilFace.stencilFailOp = DAWN_STENCIL_OPERATION_KEEP;
+    stencilFace.depthFailOp = DAWN_STENCIL_OPERATION_KEEP;
+    stencilFace.passOp = DAWN_STENCIL_OPERATION_KEEP;
 
-    dawnDepthStencilState depthStencilState = dawnDepthStencilStateBuilderGetResult(depthStencilStateBuilder);
-    dawnDepthStencilState apiDepthStencilState = api.GetNewDepthStencilState();
-    EXPECT_CALL(api, DepthStencilStateBuilderGetResult(apiDepthStencilStateBuilder))
-        .WillOnce(Return(apiDepthStencilState));
+    dawnDepthStencilStateDescriptor depthStencilState;
+    depthStencilState.nextInChain = nullptr;
+    depthStencilState.depthWriteEnabled = false;
+    depthStencilState.depthCompare = DAWN_COMPARE_FUNCTION_ALWAYS;
+    depthStencilState.back = stencilFace;
+    depthStencilState.front = stencilFace;
+    depthStencilState.stencilReadMask = 0xff;
+    depthStencilState.stencilWriteMask = 0xff;
 
     // Create the pipeline layout
     dawnPipelineLayoutDescriptor layoutDescriptor;
@@ -405,7 +410,7 @@
     pipelineDescriptor.inputState = inputState;
     pipelineDescriptor.indexFormat = DAWN_INDEX_FORMAT_UINT32;
     pipelineDescriptor.primitiveTopology = DAWN_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
-    pipelineDescriptor.depthStencilState = depthStencilState;
+    pipelineDescriptor.depthStencilState = &depthStencilState;
 
     dawnDeviceCreateRenderPipeline(device, &pipelineDescriptor);
 	EXPECT_CALL(api, DeviceCreateRenderPipeline(apiDevice, MatchesLambda([](const dawnRenderPipelineDescriptor* desc) -> bool {
diff --git a/src/tests/unittests/validation/DepthStencilStateValidationTests.cpp b/src/tests/unittests/validation/DepthStencilStateValidationTests.cpp
deleted file mode 100644
index f2639f9..0000000
--- a/src/tests/unittests/validation/DepthStencilStateValidationTests.cpp
+++ /dev/null
@@ -1,127 +0,0 @@
-// Copyright 2017 The Dawn Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "tests/unittests/validation/ValidationTest.h"
-
-class DepthStencilStateValidationTest : public ValidationTest {
-};
-
-// Test cases where creation should succeed
-TEST_F(DepthStencilStateValidationTest, CreationSuccess) {
-    // Success for setting all properties
-    {
-        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
-    {
-        dawn::DepthStencilState ds = AssertWillBeSuccess(device.CreateDepthStencilStateBuilder())
-            .GetResult();
-    }
-
-    // Test success when setting stencil function on separate faces
-    {
-        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();
-    }
-}
-
-// Test creation failure when specifying properties multiple times
-TEST_F(DepthStencilStateValidationTest, CreationDuplicates) {
-    // Test failure when specifying depth write enabled multiple times
-    {
-        dawn::DepthStencilState ds = AssertWillBeError(device.CreateDepthStencilStateBuilder())
-            .SetDepthWriteEnabled(true)
-            .SetDepthWriteEnabled(false)
-            .GetResult();
-    }
-
-    // Test failure when specifying depth compare function multiple times
-    {
-        dawn::DepthStencilState ds = AssertWillBeError(device.CreateDepthStencilStateBuilder())
-            .SetDepthCompareFunction(dawn::CompareFunction::Less)
-            .SetDepthCompareFunction(dawn::CompareFunction::Greater)
-            .GetResult();
-    }
-
-    // Test failure when setting stencil mask  multiple times
-    {
-        dawn::DepthStencilState ds = AssertWillBeError(device.CreateDepthStencilStateBuilder())
-            .SetStencilMask(0x00, 0x00)
-            .SetStencilMask(0xff, 0xff)
-            .GetResult();
-    }
-
-    // Test failure when directly setting stencil function on a face multiple times
-    {
-        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::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();
-    }
-}
diff --git a/src/utils/ComboRenderPipelineDescriptor.cpp b/src/utils/ComboRenderPipelineDescriptor.cpp
index 9e9ff97..edbe01f 100644
--- a/src/utils/ComboRenderPipelineDescriptor.cpp
+++ b/src/utils/ComboRenderPipelineDescriptor.cpp
@@ -50,25 +50,45 @@
             }
         }
 
-        descriptor->inputState = device.CreateInputStateBuilder().GetResult();
-        descriptor->depthStencilState = device.CreateDepthStencilStateBuilder().GetResult();
-        descriptor->layout = utils::MakeBasicPipelineLayout(device, nullptr);
+        // Set defaults for the blend state descriptors.
+        {
+            descriptor->numBlendStates = 1;
+            descriptor->blendStates = &cBlendStates[0];
 
-        descriptor->numBlendStates = 1;
-        descriptor->blendStates = &cBlendStates[0];
-
-        dawn::BlendDescriptor blend;
-        blend.operation = dawn::BlendOperation::Add;
-        blend.srcFactor = dawn::BlendFactor::One;
-        blend.dstFactor = dawn::BlendFactor::Zero;
-        dawn::BlendStateDescriptor blendStateDescriptor;
-        blendStateDescriptor.blendEnabled = false;
-        blendStateDescriptor.alphaBlend = blend;
-        blendStateDescriptor.colorBlend = blend;
-        blendStateDescriptor.colorWriteMask = dawn::ColorWriteMask::All;
-        for (uint32_t i = 0; i < kMaxColorAttachments; ++i) {
-            cBlendStates[i] = blendStateDescriptor;
+            dawn::BlendDescriptor blend;
+            blend.operation = dawn::BlendOperation::Add;
+            blend.srcFactor = dawn::BlendFactor::One;
+            blend.dstFactor = dawn::BlendFactor::Zero;
+            dawn::BlendStateDescriptor blendStateDescriptor;
+            blendStateDescriptor.blendEnabled = false;
+            blendStateDescriptor.alphaBlend = blend;
+            blendStateDescriptor.colorBlend = blend;
+            blendStateDescriptor.colorWriteMask = dawn::ColorWriteMask::All;
+            for (uint32_t i = 0; i < kMaxColorAttachments; ++i) {
+                cBlendStates[i] = blendStateDescriptor;
+            }
         }
+
+        // Set defaults for the depth stencil state descriptors.
+        {
+            dawn::StencilStateFaceDescriptor stencilFace;
+            stencilFace.compare = dawn::CompareFunction::Always;
+            stencilFace.stencilFailOp = dawn::StencilOperation::Keep;
+            stencilFace.depthFailOp = dawn::StencilOperation::Keep;
+            stencilFace.passOp = dawn::StencilOperation::Keep;
+
+            // dawn::DepthStencilStateDescriptor depthStencilState;
+            cDepthStencilState.depthWriteEnabled = false;
+            cDepthStencilState.depthCompare = dawn::CompareFunction::Always;
+            cDepthStencilState.back = stencilFace;
+            cDepthStencilState.front = stencilFace;
+            cDepthStencilState.stencilReadMask = 0xff;
+            cDepthStencilState.stencilWriteMask = 0xff;
+            descriptor->depthStencilState = &cDepthStencilState;
+        }
+
+        descriptor->inputState = device.CreateInputStateBuilder().GetResult();
+        descriptor->layout = utils::MakeBasicPipelineLayout(device, nullptr);
     }
 
 }  // namespace utils
diff --git a/src/utils/ComboRenderPipelineDescriptor.h b/src/utils/ComboRenderPipelineDescriptor.h
index f9c7ffa..8acbdb5 100644
--- a/src/utils/ComboRenderPipelineDescriptor.h
+++ b/src/utils/ComboRenderPipelineDescriptor.h
@@ -34,6 +34,7 @@
         std::array<dawn::AttachmentDescriptor, kMaxColorAttachments> cColorAttachments;

         dawn::AttachmentDescriptor cDepthStencilAttachment;

         std::array<dawn::BlendStateDescriptor, kMaxColorAttachments> cBlendStates;

+        dawn::DepthStencilStateDescriptor cDepthStencilState;

     };

 

 }  // namespace utils