Add a toggle to disable Dawn validation

Trusted users of Dawn should be able to use it without the
overhead of command validation. This patch adds the toggle and
skips validation for object creation.

Bug: dawn:271
Change-Id: Ica9a1988177685d73e2c36e05c4d525ad1ab0fdb
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/13802
Commit-Queue: Austin Eng <enga@chromium.org>
Reviewed-by: Jiawei Shao <jiawei.shao@intel.com>
diff --git a/src/dawn_native/Device.cpp b/src/dawn_native/Device.cpp
index bfe8d09..cade900 100644
--- a/src/dawn_native/Device.cpp
+++ b/src/dawn_native/Device.cpp
@@ -617,6 +617,10 @@
         return mTogglesSet.IsEnabled(toggle);
     }
 
+    bool DeviceBase::IsValidationEnabled() const {
+        return !IsToggleEnabled(Toggle::SkipValidation);
+    }
+
     size_t DeviceBase::GetLazyClearCountForTesting() {
         return mLazyClearCountForTesting;
     }
@@ -634,7 +638,9 @@
 
     MaybeError DeviceBase::CreateBindGroupInternal(BindGroupBase** result,
                                                    const BindGroupDescriptor* descriptor) {
-        DAWN_TRY(ValidateBindGroupDescriptor(this, descriptor));
+        if (IsValidationEnabled()) {
+            DAWN_TRY(ValidateBindGroupDescriptor(this, descriptor));
+        }
         DAWN_TRY_ASSIGN(*result, CreateBindGroupImpl(descriptor));
         return {};
     }
@@ -642,14 +648,18 @@
     MaybeError DeviceBase::CreateBindGroupLayoutInternal(
         BindGroupLayoutBase** result,
         const BindGroupLayoutDescriptor* descriptor) {
-        DAWN_TRY(ValidateBindGroupLayoutDescriptor(this, descriptor));
+        if (IsValidationEnabled()) {
+            DAWN_TRY(ValidateBindGroupLayoutDescriptor(this, descriptor));
+        }
         DAWN_TRY_ASSIGN(*result, GetOrCreateBindGroupLayout(descriptor));
         return {};
     }
 
     MaybeError DeviceBase::CreateBufferInternal(BufferBase** result,
                                                 const BufferDescriptor* descriptor) {
-        DAWN_TRY(ValidateBufferDescriptor(this, descriptor));
+        if (IsValidationEnabled()) {
+            DAWN_TRY(ValidateBufferDescriptor(this, descriptor));
+        }
         DAWN_TRY_ASSIGN(*result, CreateBufferImpl(descriptor));
         return {};
     }
@@ -657,7 +667,9 @@
     MaybeError DeviceBase::CreateComputePipelineInternal(
         ComputePipelineBase** result,
         const ComputePipelineDescriptor* descriptor) {
-        DAWN_TRY(ValidateComputePipelineDescriptor(this, descriptor));
+        if (IsValidationEnabled()) {
+            DAWN_TRY(ValidateComputePipelineDescriptor(this, descriptor));
+        }
         DAWN_TRY_ASSIGN(*result, GetOrCreateComputePipeline(descriptor));
         return {};
     }
@@ -665,7 +677,9 @@
     MaybeError DeviceBase::CreatePipelineLayoutInternal(
         PipelineLayoutBase** result,
         const PipelineLayoutDescriptor* descriptor) {
-        DAWN_TRY(ValidatePipelineLayoutDescriptor(this, descriptor));
+        if (IsValidationEnabled()) {
+            DAWN_TRY(ValidatePipelineLayoutDescriptor(this, descriptor));
+        }
         DAWN_TRY_ASSIGN(*result, GetOrCreatePipelineLayout(descriptor));
         return {};
     }
@@ -678,7 +692,9 @@
     MaybeError DeviceBase::CreateRenderBundleEncoderInternal(
         RenderBundleEncoder** result,
         const RenderBundleEncoderDescriptor* descriptor) {
-        DAWN_TRY(ValidateRenderBundleEncoderDescriptor(this, descriptor));
+        if (IsValidationEnabled()) {
+            DAWN_TRY(ValidateRenderBundleEncoderDescriptor(this, descriptor));
+        }
         *result = new RenderBundleEncoder(this, descriptor);
         return {};
     }
@@ -686,35 +702,45 @@
     MaybeError DeviceBase::CreateRenderPipelineInternal(
         RenderPipelineBase** result,
         const RenderPipelineDescriptor* descriptor) {
-        DAWN_TRY(ValidateRenderPipelineDescriptor(this, descriptor));
+        if (IsValidationEnabled()) {
+            DAWN_TRY(ValidateRenderPipelineDescriptor(this, descriptor));
+        }
         DAWN_TRY_ASSIGN(*result, GetOrCreateRenderPipeline(descriptor));
         return {};
     }
 
     MaybeError DeviceBase::CreateSamplerInternal(SamplerBase** result,
                                                  const SamplerDescriptor* descriptor) {
-        DAWN_TRY(ValidateSamplerDescriptor(this, descriptor));
+        if (IsValidationEnabled()) {
+            DAWN_TRY(ValidateSamplerDescriptor(this, descriptor));
+        }
         DAWN_TRY_ASSIGN(*result, GetOrCreateSampler(descriptor));
         return {};
     }
 
     MaybeError DeviceBase::CreateShaderModuleInternal(ShaderModuleBase** result,
                                                       const ShaderModuleDescriptor* descriptor) {
-        DAWN_TRY(ValidateShaderModuleDescriptor(this, descriptor));
+        if (IsValidationEnabled()) {
+            DAWN_TRY(ValidateShaderModuleDescriptor(this, descriptor));
+        }
         DAWN_TRY_ASSIGN(*result, GetOrCreateShaderModule(descriptor));
         return {};
     }
 
     MaybeError DeviceBase::CreateSwapChainInternal(SwapChainBase** result,
                                                    const SwapChainDescriptor* descriptor) {
-        DAWN_TRY(ValidateSwapChainDescriptor(this, descriptor));
+        if (IsValidationEnabled()) {
+            DAWN_TRY(ValidateSwapChainDescriptor(this, descriptor));
+        }
         DAWN_TRY_ASSIGN(*result, CreateSwapChainImpl(descriptor));
         return {};
     }
 
     MaybeError DeviceBase::CreateTextureInternal(TextureBase** result,
                                                  const TextureDescriptor* descriptor) {
-        DAWN_TRY(ValidateTextureDescriptor(this, descriptor));
+        if (IsValidationEnabled()) {
+            DAWN_TRY(ValidateTextureDescriptor(this, descriptor));
+        }
         DAWN_TRY_ASSIGN(*result, CreateTextureImpl(descriptor));
         return {};
     }
@@ -724,7 +750,9 @@
                                                      const TextureViewDescriptor* descriptor) {
         DAWN_TRY(ValidateObject(texture));
         TextureViewDescriptor desc = GetTextureViewDescriptorWithDefaults(texture, descriptor);
-        DAWN_TRY(ValidateTextureViewDescriptor(texture, &desc));
+        if (IsValidationEnabled()) {
+            DAWN_TRY(ValidateTextureViewDescriptor(texture, &desc));
+        }
         DAWN_TRY_ASSIGN(*result, CreateTextureViewImpl(texture, &desc));
         return {};
     }
diff --git a/src/dawn_native/Device.h b/src/dawn_native/Device.h
index a1e09e6..e887fa7 100644
--- a/src/dawn_native/Device.h
+++ b/src/dawn_native/Device.h
@@ -185,6 +185,7 @@
         std::vector<const char*> GetTogglesUsed() const;
         bool IsExtensionEnabled(Extension extension) const;
         bool IsToggleEnabled(Toggle toggle) const;
+        bool IsValidationEnabled() const;
         size_t GetLazyClearCountForTesting();
         void IncrementLazyClearCountForTesting();
 
diff --git a/src/dawn_native/Toggles.cpp b/src/dawn_native/Toggles.cpp
index f69ccd1..cfe8253 100644
--- a/src/dawn_native/Toggles.cpp
+++ b/src/dawn_native/Toggles.cpp
@@ -80,7 +80,9 @@
               {"use_d3d12_render_pass",
                "Use the D3D12 render pass API introduced in Windows build 1809 by default. On "
                "versions of Windows prior to build 1809, or when this toggle is turned off, Dawn "
-               "will emulate a render pass."}}}};
+               "will emulate a render pass."}},
+             {Toggle::SkipValidation,
+              {"skip_validation", "Skip expensive validation of Dawn commands."}}}};
     }  // anonymous namespace
 
     void TogglesSet::SetToggle(Toggle toggle, bool enabled) {
diff --git a/src/dawn_native/Toggles.h b/src/dawn_native/Toggles.h
index 73db7f9..0d5aa7f 100644
--- a/src/dawn_native/Toggles.h
+++ b/src/dawn_native/Toggles.h
@@ -32,6 +32,7 @@
         UseTemporaryBufferInCompressedTextureToTextureCopy,
         UseD3D12ResourceHeapTier2,
         UseD3D12RenderPass,
+        SkipValidation,
 
         EnumCount,
         InvalidEnum = EnumCount,
diff --git a/src/tests/DawnTest.cpp b/src/tests/DawnTest.cpp
index 92b0224..25654ba 100644
--- a/src/tests/DawnTest.cpp
+++ b/src/tests/DawnTest.cpp
@@ -137,6 +137,11 @@
             continue;
         }
 
+        if (strcmp("--skip-validation", argv[i]) == 0) {
+            mSkipDawnValidation = true;
+            continue;
+        }
+
         constexpr const char kVendorIdFilterArg[] = "--adapter-vendor-id=";
         if (strstr(argv[i], kVendorIdFilterArg) == argv[i]) {
             const char* vendorIdFilter = argv[i] + strlen(kVendorIdFilterArg);
@@ -156,6 +161,7 @@
                          " to disabled)\n"
                          "  -c, --begin-capture-on-startup: Begin debug capture on startup "
                          "(defaults to no capture)\n"
+                         "  --skip-validation: Skip Dawn validation\n"
                          "  --adapter-vendor-id: Select adapter by vendor id to run end2end tests"
                          "on multi-GPU systems \n"
                       << std::endl;
@@ -185,6 +191,9 @@
                  "EnableBackendValidation: "
               << (mEnableBackendValidation ? "true" : "false")
               << "\n"
+                 "SkipDawnValidation: "
+              << (mSkipDawnValidation ? "true" : "false")
+              << "\n"
                  "BeginCaptureOnStartup: "
               << (mBeginCaptureOnStartup ? "true" : "false")
               << "\n"
@@ -228,6 +237,10 @@
     return mEnableBackendValidation;
 }
 
+bool DawnTestEnvironment::IsDawnValidationSkipped() const {
+    return mSkipDawnValidation;
+}
+
 dawn_native::Instance* DawnTestEnvironment::GetInstance() const {
     return mInstance.get();
 }
@@ -353,6 +366,10 @@
     return gTestEnv->IsBackendValidationEnabled();
 }
 
+bool DawnTestBase::IsDawnValidationSkipped() const {
+    return gTestEnv->IsDawnValidationSkipped();
+}
+
 bool DawnTestBase::HasVendorIdFilter() const {
     return gTestEnv->HasVendorIdFilter();
 }
@@ -431,6 +448,13 @@
     deviceDescriptor.forceEnabledToggles = mParam.forceEnabledWorkarounds;
     deviceDescriptor.forceDisabledToggles = mParam.forceDisabledWorkarounds;
     deviceDescriptor.requiredExtensions = GetRequiredExtensions();
+
+    static constexpr char kSkipValidationToggle[] = "skip_validation";
+    if (gTestEnv->IsDawnValidationSkipped()) {
+        ASSERT(gTestEnv->GetInstance()->GetToggleInfo(kSkipValidationToggle) != nullptr);
+        deviceDescriptor.forceEnabledToggles.push_back(kSkipValidationToggle);
+    }
+
     backendDevice = mBackendAdapter.CreateDevice(&deviceDescriptor);
     ASSERT_NE(nullptr, backendDevice);
 
diff --git a/src/tests/DawnTest.h b/src/tests/DawnTest.h
index c271bb0..96ff946 100644
--- a/src/tests/DawnTest.h
+++ b/src/tests/DawnTest.h
@@ -134,6 +134,7 @@
 
     bool UsesWire() const;
     bool IsBackendValidationEnabled() const;
+    bool IsDawnValidationSkipped() const;
     dawn_native::Instance* GetInstance() const;
     bool HasVendorIdFilter() const;
     uint32_t GetVendorIdFilter() const;
@@ -146,6 +147,7 @@
 
     bool mUseWire = false;
     bool mEnableBackendValidation = false;
+    bool mSkipDawnValidation = false;
     bool mBeginCaptureOnStartup = false;
     bool mHasVendorIdFilter = false;
     uint32_t mVendorIdFilter = 0;
@@ -179,6 +181,7 @@
 
     bool UsesWire() const;
     bool IsBackendValidationEnabled() const;
+    bool IsDawnValidationSkipped() const;
 
     void StartExpectDeviceError();
     bool EndExpectDeviceError();
diff --git a/src/tests/end2end/DestroyTests.cpp b/src/tests/end2end/DestroyTests.cpp
index 916fb55..50f36fe 100644
--- a/src/tests/end2end/DestroyTests.cpp
+++ b/src/tests/end2end/DestroyTests.cpp
@@ -23,6 +23,7 @@
   protected:
     void TestSetUp() override {
         DawnTest::TestSetUp();
+        DAWN_SKIP_TEST_IF(IsDawnValidationSkipped());
 
         renderPass = utils::CreateBasicRenderPass(device, kRTSize, kRTSize);
 
diff --git a/src/tests/end2end/ObjectCachingTests.cpp b/src/tests/end2end/ObjectCachingTests.cpp
index 4bd1910..27aab13 100644
--- a/src/tests/end2end/ObjectCachingTests.cpp
+++ b/src/tests/end2end/ObjectCachingTests.cpp
@@ -81,6 +81,8 @@
 
 // Test that an error object doesn't try to uncache itself
 TEST_P(ObjectCachingTest, ErrorObjectDoesntUncache) {
+    DAWN_SKIP_TEST_IF(IsDawnValidationSkipped());
+
     ASSERT_DEVICE_ERROR(
         wgpu::BindGroupLayout bgl = utils::MakeBindGroupLayout(
             device, {{0, wgpu::ShaderStage::Fragment, wgpu::BindingType::UniformBuffer},