Update validation for pass encoding beginRenderPass/beginComputePass

Make validation for pass encoding aligned to spec, where
descriptor validation failure will make pass invalid and stop
immediately instead of defer to CommandEncoder::Finish()

Bug: dawn:1602
Change-Id: I7892009e31f7565e4da43c38d365b056c9ecc22f
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/112448
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Commit-Queue: Shrek Shao <shrekshao@google.com>
diff --git a/src/dawn/native/CommandEncoder.cpp b/src/dawn/native/CommandEncoder.cpp
index 13c8431..95157ca 100644
--- a/src/dawn/native/CommandEncoder.cpp
+++ b/src/dawn/native/CommandEncoder.cpp
@@ -781,11 +781,14 @@
 Ref<ComputePassEncoder> CommandEncoder::BeginComputePass(const ComputePassDescriptor* descriptor) {
     DeviceBase* device = GetDevice();
 
+    // If descriptor is invalid, make pass invalid and stop immediately
+    if (device->ConsumedError(ValidateComputePassDescriptor(device, descriptor))) {
+        return ComputePassEncoder::MakeError(device, this, &mEncodingContext);
+    }
+
     bool success = mEncodingContext.TryEncode(
         this,
         [&](CommandAllocator* allocator) -> MaybeError {
-            DAWN_TRY(ValidateComputePassDescriptor(device, descriptor));
-
             BeginComputePassCmd* cmd =
                 allocator->Allocate<BeginComputePassCmd>(Command::BeginComputePass);
 
@@ -844,17 +847,20 @@
 
     uint32_t width = 0;
     uint32_t height = 0;
+    uint32_t sampleCount = 0;
     bool depthReadOnly = false;
     bool stencilReadOnly = false;
     Ref<AttachmentState> attachmentState;
+
+    // If descriptor is invalid, make pass invalid and stop immediately
+    if (device->ConsumedError(ValidateRenderPassDescriptor(device, descriptor, &width, &height,
+                                                           &sampleCount, mUsageValidationMode))) {
+        return RenderPassEncoder::MakeError(device, this, &mEncodingContext);
+    }
+
     bool success = mEncodingContext.TryEncode(
         this,
         [&](CommandAllocator* allocator) -> MaybeError {
-            uint32_t sampleCount = 0;
-
-            DAWN_TRY(ValidateRenderPassDescriptor(device, descriptor, &width, &height, &sampleCount,
-                                                  mUsageValidationMode));
-
             ASSERT(width > 0 && height > 0 && sampleCount > 0);
 
             mEncodingContext.WillBeginRenderPass();
diff --git a/src/dawn/tests/end2end/DeprecatedAPITests.cpp b/src/dawn/tests/end2end/DeprecatedAPITests.cpp
index a015a58..20d3fdd 100644
--- a/src/dawn/tests/end2end/DeprecatedAPITests.cpp
+++ b/src/dawn/tests/end2end/DeprecatedAPITests.cpp
@@ -47,8 +47,7 @@
 
 // Test that setting attachment rather than view for render pass color and depth/stencil attachments
 // is deprecated.
-// TODO(dawn:1602): validation implementations need updating
-TEST_P(DeprecationTests, DISABLED_ReadOnlyDepthStencilStoreLoadOpsAttachment) {
+TEST_P(DeprecationTests, ReadOnlyDepthStencilStoreLoadOpsAttachment) {
     utils::BasicRenderPass renderPass = utils::CreateBasicRenderPass(device, 1, 1);
     wgpu::RenderPassEncoder pass;
 
@@ -71,6 +70,8 @@
 
     depthAttachment->depthLoadOp = wgpu::LoadOp::Load;
     depthAttachment->depthStoreOp = wgpu::StoreOp::Store;
+    depthAttachment->stencilLoadOp = wgpu::LoadOp::Undefined;
+    depthAttachment->stencilStoreOp = wgpu::StoreOp::Undefined;
 
     {
         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
@@ -92,8 +93,7 @@
 
 // Test that setting the clearColor, clearDepth, or clearStencil values for render pass attachments
 // is deprecated. (dawn:1269)
-// TODO(dawn:1602): validation implementations need updating
-TEST_P(DeprecationTests, DISABLED_AttachmentClearColor) {
+TEST_P(DeprecationTests, AttachmentClearColor) {
     utils::BasicRenderPass renderPass = utils::CreateBasicRenderPass(device, 1, 1);
     wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
     wgpu::RenderPassEncoder pass;
diff --git a/src/dawn/tests/end2end/SwapChainValidationTests.cpp b/src/dawn/tests/end2end/SwapChainValidationTests.cpp
index b02d760..20948ed 100644
--- a/src/dawn/tests/end2end/SwapChainValidationTests.cpp
+++ b/src/dawn/tests/end2end/SwapChainValidationTests.cpp
@@ -78,16 +78,16 @@
     void CheckTextureViewIsValid(wgpu::TextureView view) { CheckTextureView(view, false, false); }
 
   private:
-    void CheckTextureView(wgpu::TextureView view, bool errorAtFinish, bool errorAtSubmit) {
+    void CheckTextureView(wgpu::TextureView view, bool errorAtBeginRenderPass, bool errorAtSubmit) {
         utils::ComboRenderPassDescriptor renderPassDesc({view});
 
         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
-        wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPassDesc);
-        pass.End();
 
-        if (errorAtFinish) {
-            ASSERT_DEVICE_ERROR(encoder.Finish());
+        if (errorAtBeginRenderPass) {
+            ASSERT_DEVICE_ERROR(encoder.BeginRenderPass(&renderPassDesc));
         } else {
+            wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPassDesc);
+            pass.End();
             wgpu::CommandBuffer commands = encoder.Finish();
 
             if (errorAtSubmit) {
diff --git a/src/dawn/tests/unittests/validation/QueryValidationTests.cpp b/src/dawn/tests/unittests/validation/QueryValidationTests.cpp
index d0289e2..0712461 100644
--- a/src/dawn/tests/unittests/validation/QueryValidationTests.cpp
+++ b/src/dawn/tests/unittests/validation/QueryValidationTests.cpp
@@ -156,9 +156,7 @@
             CreateQuerySet(otherDevice, wgpu::QueryType::Occlusion, 2);
         renderPass.occlusionQuerySet = occlusionQuerySetOnOther;
         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
-        wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
-        pass.End();
-        ASSERT_DEVICE_ERROR(encoder.Finish());
+        ASSERT_DEVICE_ERROR(encoder.BeginRenderPass(&renderPass));
 
         // Clear this out so we don't hold a reference. The query set
         // must be destroyed before the device local to this test case.
@@ -335,8 +333,7 @@
     renderPass.occlusionQuerySet = querySet;
 
     wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
-    encoder.BeginRenderPass(&renderPass);
-    ASSERT_DEVICE_ERROR(encoder.Finish());
+    ASSERT_DEVICE_ERROR(encoder.BeginRenderPass(&renderPass));
 }
 
 // Test timestampWrites in compute pass descriptor
@@ -357,9 +354,8 @@
         wgpu::QuerySet occlusionQuerySet = CreateQuerySet(device, wgpu::QueryType::Occlusion, 1);
 
         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
-        EncodeComputePassWithTimestampWrites(
-            encoder, {{occlusionQuerySet, 0, wgpu::ComputePassTimestampLocation::Beginning}});
-        ASSERT_DEVICE_ERROR(encoder.Finish());
+        ASSERT_DEVICE_ERROR(EncodeComputePassWithTimestampWrites(
+            encoder, {{occlusionQuerySet, 0, wgpu::ComputePassTimestampLocation::Beginning}}));
     }
 
     // Fail to write timestamps to a query set created from another device
@@ -369,18 +365,16 @@
             CreateQuerySet(otherDevice, wgpu::QueryType::Timestamp, 2);
 
         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
-        EncodeComputePassWithTimestampWrites(
+        ASSERT_DEVICE_ERROR(EncodeComputePassWithTimestampWrites(
             encoder, {{querySet, 0, wgpu::ComputePassTimestampLocation::Beginning},
-                      {querySetFromOtherDevice, 1, wgpu::ComputePassTimestampLocation::End}});
-        ASSERT_DEVICE_ERROR(encoder.Finish());
+                      {querySetFromOtherDevice, 1, wgpu::ComputePassTimestampLocation::End}}));
     }
 
     // Fail to write timestamps to the query index which exceeds the number of queries in query set
     {
         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
-        EncodeComputePassWithTimestampWrites(
-            encoder, {{querySet, 2, wgpu::ComputePassTimestampLocation::Beginning}});
-        ASSERT_DEVICE_ERROR(encoder.Finish());
+        ASSERT_DEVICE_ERROR(EncodeComputePassWithTimestampWrites(
+            encoder, {{querySet, 2, wgpu::ComputePassTimestampLocation::Beginning}}));
     }
 
     // Success to write timestamps to the same query index twice on same compute pass
@@ -405,18 +399,16 @@
     // Fail to write timestamps at same location of a compute pass
     {
         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
-        EncodeComputePassWithTimestampWrites(
+        ASSERT_DEVICE_ERROR(EncodeComputePassWithTimestampWrites(
             encoder, {{querySet, 0, wgpu::ComputePassTimestampLocation::Beginning},
-                      {querySet, 1, wgpu::ComputePassTimestampLocation::Beginning}});
-        ASSERT_DEVICE_ERROR(encoder.Finish());
+                      {querySet, 1, wgpu::ComputePassTimestampLocation::Beginning}}));
     }
 
     // Fail to write timestamps at invalid location of compute pass
     {
         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
-        EncodeComputePassWithTimestampWrites(
-            encoder, {{querySet, 0, static_cast<wgpu::ComputePassTimestampLocation>(0xFFFFFFFF)}});
-        ASSERT_DEVICE_ERROR(encoder.Finish());
+        ASSERT_DEVICE_ERROR(EncodeComputePassWithTimestampWrites(
+            encoder, {{querySet, 0, static_cast<wgpu::ComputePassTimestampLocation>(0xFFFFFFFF)}}));
     }
 
     // Fail to write timestamps to a destroyed query set
@@ -451,9 +443,8 @@
         wgpu::QuerySet occlusionQuerySet = CreateQuerySet(device, wgpu::QueryType::Occlusion, 1);
 
         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
-        EncodeRenderPassWithTimestampWrites(
-            encoder, {{occlusionQuerySet, 0, wgpu::RenderPassTimestampLocation::Beginning}});
-        ASSERT_DEVICE_ERROR(encoder.Finish());
+        ASSERT_DEVICE_ERROR(EncodeRenderPassWithTimestampWrites(
+            encoder, {{occlusionQuerySet, 0, wgpu::RenderPassTimestampLocation::Beginning}}));
     }
 
     // Fail to write timestamps to a query set created from another device
@@ -463,18 +454,16 @@
             CreateQuerySet(otherDevice, wgpu::QueryType::Timestamp, 2);
 
         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
-        EncodeRenderPassWithTimestampWrites(
+        ASSERT_DEVICE_ERROR(EncodeRenderPassWithTimestampWrites(
             encoder, {{querySet, 0, wgpu::RenderPassTimestampLocation::Beginning},
-                      {querySetFromOtherDevice, 1, wgpu::RenderPassTimestampLocation::End}});
-        ASSERT_DEVICE_ERROR(encoder.Finish());
+                      {querySetFromOtherDevice, 1, wgpu::RenderPassTimestampLocation::End}}));
     }
 
     // Fail to write timestamps to the query index which exceeds the number of queries in query set
     {
         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
-        EncodeRenderPassWithTimestampWrites(
-            encoder, {{querySet, 2, wgpu::RenderPassTimestampLocation::Beginning}});
-        ASSERT_DEVICE_ERROR(encoder.Finish());
+        ASSERT_DEVICE_ERROR(EncodeRenderPassWithTimestampWrites(
+            encoder, {{querySet, 2, wgpu::RenderPassTimestampLocation::Beginning}}));
     }
 
     // Success to write timestamps to the same query index and location twice on different render
@@ -494,27 +483,24 @@
     // Fail to write timestamps to the same query index twice on same render pass
     {
         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
-        EncodeRenderPassWithTimestampWrites(
+        ASSERT_DEVICE_ERROR(EncodeRenderPassWithTimestampWrites(
             encoder, {{querySet, 0, wgpu::RenderPassTimestampLocation::Beginning},
-                      {querySet, 0, wgpu::RenderPassTimestampLocation::End}});
-        ASSERT_DEVICE_ERROR(encoder.Finish());
+                      {querySet, 0, wgpu::RenderPassTimestampLocation::End}}));
     }
 
     // Fail to write timestamps at same location of a render pass
     {
         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
-        EncodeRenderPassWithTimestampWrites(
+        ASSERT_DEVICE_ERROR(EncodeRenderPassWithTimestampWrites(
             encoder, {{querySet, 0, wgpu::RenderPassTimestampLocation::Beginning},
-                      {querySet, 1, wgpu::RenderPassTimestampLocation::Beginning}});
-        ASSERT_DEVICE_ERROR(encoder.Finish());
+                      {querySet, 1, wgpu::RenderPassTimestampLocation::Beginning}}));
     }
 
     // Fail to write timestamps at invalid location of render pass
     {
         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
-        EncodeRenderPassWithTimestampWrites(
-            encoder, {{querySet, 0, static_cast<wgpu::RenderPassTimestampLocation>(0xFFFFFFFF)}});
-        ASSERT_DEVICE_ERROR(encoder.Finish());
+        ASSERT_DEVICE_ERROR(EncodeRenderPassWithTimestampWrites(
+            encoder, {{querySet, 0, static_cast<wgpu::RenderPassTimestampLocation>(0xFFFFFFFF)}}));
     }
 
     // Fail to write timestamps to a destroyed query set
@@ -785,8 +771,7 @@
     renderPass.occlusionQuerySet = querySet;
 
     wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
-    encoder.BeginRenderPass(&renderPass);
-    ASSERT_DEVICE_ERROR(encoder.Finish());
+    ASSERT_DEVICE_ERROR(encoder.BeginRenderPass(&renderPass));
 }
 
 class ResolveQuerySetValidationTest : public QuerySetValidationTest {
diff --git a/src/dawn/tests/unittests/validation/RenderPassDescriptorValidationTests.cpp b/src/dawn/tests/unittests/validation/RenderPassDescriptorValidationTests.cpp
index f0cfd3c..87b292f 100644
--- a/src/dawn/tests/unittests/validation/RenderPassDescriptorValidationTests.cpp
+++ b/src/dawn/tests/unittests/validation/RenderPassDescriptorValidationTests.cpp
@@ -27,20 +27,14 @@
 class RenderPassDescriptorValidationTest : public ValidationTest {
   public:
     void AssertBeginRenderPassSuccess(const wgpu::RenderPassDescriptor* descriptor) {
-        wgpu::CommandEncoder commandEncoder = TestBeginRenderPass(descriptor);
-        commandEncoder.Finish();
-    }
-    void AssertBeginRenderPassError(const wgpu::RenderPassDescriptor* descriptor) {
-        wgpu::CommandEncoder commandEncoder = TestBeginRenderPass(descriptor);
-        ASSERT_DEVICE_ERROR(commandEncoder.Finish());
-    }
-
-  private:
-    wgpu::CommandEncoder TestBeginRenderPass(const wgpu::RenderPassDescriptor* descriptor) {
         wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
         wgpu::RenderPassEncoder renderPassEncoder = commandEncoder.BeginRenderPass(descriptor);
         renderPassEncoder.End();
-        return commandEncoder;
+        commandEncoder.Finish();
+    }
+    void AssertBeginRenderPassError(const wgpu::RenderPassDescriptor* descriptor) {
+        wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
+        ASSERT_DEVICE_ERROR(commandEncoder.BeginRenderPass(descriptor));
     }
 };
 
diff --git a/src/dawn/tests/unittests/validation/RenderPipelineValidationTests.cpp b/src/dawn/tests/unittests/validation/RenderPipelineValidationTests.cpp
index 675b1d9..927f05b 100644
--- a/src/dawn/tests/unittests/validation/RenderPipelineValidationTests.cpp
+++ b/src/dawn/tests/unittests/validation/RenderPipelineValidationTests.cpp
@@ -710,11 +710,7 @@
         utils::ComboRenderPassDescriptor renderPassDescriptor({});
 
         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
-        wgpu::RenderPassEncoder renderPass = encoder.BeginRenderPass(&renderPassDescriptor);
-        renderPass.SetPipeline(vertexOnlyPipeline);
-        renderPass.End();
-
-        ASSERT_DEVICE_ERROR(encoder.Finish());
+        ASSERT_DEVICE_ERROR(encoder.BeginRenderPass(&renderPassDescriptor));
     }
 
     // Vertex-only render pipeline can not work with color target
diff --git a/webgpu-cts/expectations.txt b/webgpu-cts/expectations.txt
index 956ce88..66dc697 100644
--- a/webgpu-cts/expectations.txt
+++ b/webgpu-cts/expectations.txt
@@ -446,6 +446,19 @@
 ################################################################################
 
 ################################################################################
+# commandEncoder validation tests need updates in CTS
+################################################################################
+crbug.com/dawn/1602 webgpu:api,validation,encoding,beginComputePass:* [ Skip ]
+crbug.com/dawn/1602 webgpu:api,validation,encoding,beginRenderPass:* [ Skip ]
+crbug.com/dawn/1602 webgpu:api,validation,encoding,encoder_open_state:non_pass_commands:* [ Skip ]
+crbug.com/dawn/1602 webgpu:api,validation,encoding,queries,general:occlusion_query,* [ Skip ]
+crbug.com/dawn/1602 webgpu:api,validation,render_pass,render_pass_descriptor:* [ Skip ]
+crbug.com/dawn/1602 webgpu:api,validation,render_pass,resolve:resolve_attachment:* [ Skip ]
+crbug.com/dawn/1602 webgpu:api,validation,render_pass,storeOp:* [ Skip ]
+crbug.com/dawn/1602 webgpu:api,validation,resource_usages,texture,in_render_misc:subresources,set_bind_group_on_same_index_depth_stencil_texture:* [ Skip ]
+################################################################################
+
+################################################################################
 # untriaged failures
 # KEEP
 ################################################################################