Add Backend Validation Levels Option to Dawn Tests

Refactors DawnTest's backend validation options to use an enum, as well
as adds the 'partial' option enable backend validation with a
reduced performance overhead to address TDR issues on the bots.

Bug: dawn:598
Change-Id: I759eff03bd117f1f20ad82aa2b71a87834f42b1d
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/40000
Commit-Queue: Brandon Jones <brandon1.jones@intel.com>
Reviewed-by: Austin Eng <enga@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
diff --git a/src/dawn_native/DawnNative.cpp b/src/dawn_native/DawnNative.cpp
index 35ed9be..b7b46ad 100644
--- a/src/dawn_native/DawnNative.cpp
+++ b/src/dawn_native/DawnNative.cpp
@@ -151,11 +151,13 @@
     }
 
     void Instance::EnableBackendValidation(bool enableBackendValidation) {
-        mImpl->EnableBackendValidation(enableBackendValidation);
+        if (enableBackendValidation) {
+            mImpl->SetBackendValidationLevel(BackendValidationLevel::Full);
+        }
     }
 
-    void Instance::EnableGPUBasedBackendValidation(bool enableGPUBasedBackendValidation) {
-        mImpl->EnableGPUBasedBackendValidation(enableGPUBasedBackendValidation);
+    void Instance::SetBackendValidationLevel(BackendValidationLevel level) {
+        mImpl->SetBackendValidationLevel(level);
     }
 
     void Instance::EnableBeginCaptureOnStartup(bool beginCaptureOnStartup) {
diff --git a/src/dawn_native/Instance.cpp b/src/dawn_native/Instance.cpp
index 85e9226..2e3e897 100644
--- a/src/dawn_native/Instance.cpp
+++ b/src/dawn_native/Instance.cpp
@@ -195,20 +195,16 @@
         return false;
     }
 
-    void InstanceBase::EnableBackendValidation(bool enableBackendValidation) {
-        mEnableBackendValidation = enableBackendValidation;
-    }
-
     bool InstanceBase::IsBackendValidationEnabled() const {
-        return mEnableBackendValidation;
+        return mBackendValidationLevel != BackendValidationLevel::Disabled;
     }
 
-    void InstanceBase::EnableGPUBasedBackendValidation(bool enableGPUBasedBackendValidation) {
-        mEnableGPUValidation = enableGPUBasedBackendValidation;
+    void InstanceBase::SetBackendValidationLevel(BackendValidationLevel level) {
+        mBackendValidationLevel = level;
     }
 
-    bool InstanceBase::IsGPUBasedBackendValidationEnabled() const {
-        return mEnableGPUValidation;
+    BackendValidationLevel InstanceBase::GetBackendValidationLevel() const {
+        return mBackendValidationLevel;
     }
 
     void InstanceBase::EnableBeginCaptureOnStartup(bool beginCaptureOnStartup) {
diff --git a/src/dawn_native/Instance.h b/src/dawn_native/Instance.h
index 14d4eef..bf67a94 100644
--- a/src/dawn_native/Instance.h
+++ b/src/dawn_native/Instance.h
@@ -57,11 +57,9 @@
         ExtensionsSet ExtensionNamesToExtensionsSet(
             const std::vector<const char*>& requiredExtensions);
 
-        void EnableBackendValidation(bool enableBackendValidation);
         bool IsBackendValidationEnabled() const;
-
-        void EnableGPUBasedBackendValidation(bool enableGPUBasedBackendValidation);
-        bool IsGPUBasedBackendValidationEnabled() const;
+        void SetBackendValidationLevel(BackendValidationLevel level);
+        BackendValidationLevel GetBackendValidationLevel() const;
 
         void EnableBeginCaptureOnStartup(bool beginCaptureOnStartup);
         bool IsBeginCaptureOnStartupEnabled() const;
@@ -89,9 +87,8 @@
         bool mBackendsConnected = false;
         bool mDiscoveredDefaultAdapters = false;
 
-        bool mEnableBackendValidation = false;
         bool mBeginCaptureOnStartup = false;
-        bool mEnableGPUValidation = false;
+        BackendValidationLevel mBackendValidationLevel = BackendValidationLevel::Disabled;
 
         dawn_platform::Platform* mPlatform = nullptr;
 
diff --git a/src/dawn_native/d3d12/BackendD3D12.cpp b/src/dawn_native/d3d12/BackendD3D12.cpp
index 8d61208..a162dbe 100644
--- a/src/dawn_native/d3d12/BackendD3D12.cpp
+++ b/src/dawn_native/d3d12/BackendD3D12.cpp
@@ -25,23 +25,25 @@
     namespace {
 
         ResultOrError<ComPtr<IDXGIFactory4>> CreateFactory(const PlatformFunctions* functions,
-                                                           bool enableBackendValidation,
-                                                           bool beginCaptureOnStartup,
-                                                           bool enableGPUBasedBackendValidation) {
+                                                           BackendValidationLevel validationLevel,
+                                                           bool beginCaptureOnStartup) {
             ComPtr<IDXGIFactory4> factory;
 
             uint32_t dxgiFactoryFlags = 0;
 
             // Enable the debug layer (requires the Graphics Tools "optional feature").
             {
-                if (enableBackendValidation) {
-                    ComPtr<ID3D12Debug1> debugController;
+                if (validationLevel != BackendValidationLevel::Disabled) {
+                    ComPtr<ID3D12Debug3> debugController;
                     if (SUCCEEDED(
                             functions->d3d12GetDebugInterface(IID_PPV_ARGS(&debugController)))) {
                         ASSERT(debugController != nullptr);
                         debugController->EnableDebugLayer();
-                        debugController->SetEnableGPUBasedValidation(
-                            enableGPUBasedBackendValidation);
+                        debugController->SetEnableGPUBasedValidation(true);
+                        if (validationLevel == BackendValidationLevel::Partial) {
+                            debugController->SetGPUBasedValidationFlags(
+                                D3D12_GPU_BASED_VALIDATION_FLAGS_DISABLE_STATE_TRACKING);
+                        }
 
                         // Enable additional debug layers.
                         dxgiFactoryFlags |= DXGI_CREATE_FACTORY_DEBUG;
@@ -97,9 +99,8 @@
         const auto instance = GetInstance();
 
         DAWN_TRY_ASSIGN(mFactory,
-                        CreateFactory(mFunctions.get(), instance->IsBackendValidationEnabled(),
-                                      instance->IsBeginCaptureOnStartupEnabled(),
-                                      instance->IsGPUBasedBackendValidationEnabled()));
+                        CreateFactory(mFunctions.get(), instance->GetBackendValidationLevel(),
+                                      instance->IsBeginCaptureOnStartupEnabled()));
 
         return {};
     }
diff --git a/src/include/dawn_native/DawnNative.h b/src/include/dawn_native/DawnNative.h
index 31286a6..3e8e6c0 100644
--- a/src/include/dawn_native/DawnNative.h
+++ b/src/include/dawn_native/DawnNative.h
@@ -129,6 +129,8 @@
         AdapterDiscoveryOptionsBase(WGPUBackendType type);
     };
 
+    enum BackendValidationLevel { Full, Partial, Disabled };
+
     // Represents a connection to dawn_native and is used for dependency injection, discovering
     // system adapters and injecting custom adapters (like a Swiftshader Vulkan adapter).
     //
@@ -155,15 +157,13 @@
 
         const ToggleInfo* GetToggleInfo(const char* toggleName);
 
-        // Enable backend's validation layers if it has.
+        // Enables backend validation layers
         void EnableBackendValidation(bool enableBackendValidation);
+        void SetBackendValidationLevel(BackendValidationLevel validationLevel);
 
         // Enable debug capture on Dawn startup
         void EnableBeginCaptureOnStartup(bool beginCaptureOnStartup);
 
-        // Enable GPU based backend validation if it has.
-        void EnableGPUBasedBackendValidation(bool enableGPUBasedBackendValidation);
-
         void SetPlatform(dawn_platform::Platform* platform);
 
         // Returns the underlying WGPUInstance object.
diff --git a/src/tests/DawnTest.cpp b/src/tests/DawnTest.cpp
index 1a483dd..793d8c0 100644
--- a/src/tests/DawnTest.cpp
+++ b/src/tests/DawnTest.cpp
@@ -212,7 +212,7 @@
 DawnTestEnvironment::DawnTestEnvironment(int argc, char** argv) {
     ParseArgs(argc, argv);
 
-    if (mEnableBackendValidation) {
+    if (mBackendValidationLevel != dawn_native::BackendValidationLevel::Disabled) {
         mPlatformDebugLogger =
             std::unique_ptr<utils::PlatformDebugLogger>(utils::CreatePlatformDebugLogger());
     }
@@ -240,9 +240,24 @@
             continue;
         }
 
-        if (strcmp("-d", argv[i]) == 0 || strcmp("--enable-backend-validation", argv[i]) == 0) {
-            mEnableBackendValidation = true;
-            continue;
+        constexpr const char kEnableBackendValidationSwitch[] = "--enable-backend-validation";
+        argLen = sizeof(kEnableBackendValidationSwitch) - 1;
+        if (strncmp(argv[i], kEnableBackendValidationSwitch, argLen) == 0) {
+            const char* level = argv[i] + argLen;
+            if (level[0] != '\0') {
+                if (strcmp(level, "=full") == 0) {
+                    mBackendValidationLevel = dawn_native::BackendValidationLevel::Full;
+                } else if (strcmp(level, "=partial") == 0) {
+                    mBackendValidationLevel = dawn_native::BackendValidationLevel::Partial;
+                } else if (strcmp(level, "=disabled") == 0) {
+                    mBackendValidationLevel = dawn_native::BackendValidationLevel::Disabled;
+                } else {
+                    dawn::ErrorLog() << "Invalid backend validation level" << level;
+                    UNREACHABLE();
+                }
+            } else {
+                mBackendValidationLevel = dawn_native::BackendValidationLevel::Full;
+            }
         }
 
         if (strcmp("-c", argv[i]) == 0 || strcmp("--begin-capture-on-startup", argv[i]) == 0) {
@@ -317,15 +332,18 @@
         if (strcmp("-h", argv[i]) == 0 || strcmp("--help", argv[i]) == 0) {
             dawn::InfoLog()
                 << "\n\nUsage: " << argv[0]
-                << " [GTEST_FLAGS...] [-w] [-d] [-c]\n"
+                << " [GTEST_FLAGS...] [-w] [-c]\n"
                    "    [--enable-toggles=toggles] [--disable-toggles=toggles]\n"
-                   "    [--adapter-vendor-id=x]"
-                   " [--exclusive-device-type-preference=integrated,cpu,discrete]\n\n"
+                   "    [--adapter-vendor-id=x] "
+                   "[--enable-backend-validation[=full,partial,disabled]]\n"
+                   "    [--exclusive-device-type-preference=integrated,cpu,discrete]\n\n"
                    "  -w, --use-wire: Run the tests through the wire (defaults to no wire)\n"
-                   "  -d, --enable-backend-validation: Enable backend validation (defaults"
-                   " to disabled)\n"
                    "  -c, --begin-capture-on-startup: Begin debug capture on startup "
                    "(defaults to no capture)\n"
+                   "  --enable-backend-validation: Enables backend validation. Defaults to 'full'\n"
+                   "    to enable all available backend validation. Set to 'partial' to\n"
+                   "    enable a subset of backend validation with less performance overhead.\n"
+                   "    Set to 'disabled' to run with no validation (same as no flag).\n"
                    "  --enable-toggles: Comma-delimited list of Dawn toggles to enable.\n"
                    "    ex.) skip_validation,use_tint_generator,disable_robustness,turn_off_vsync\n"
                    "  --disable-toggles: Comma-delimited list of Dawn toggles to disable\n"
@@ -341,10 +359,8 @@
 
 std::unique_ptr<dawn_native::Instance> DawnTestEnvironment::CreateInstanceAndDiscoverAdapters() {
     auto instance = std::make_unique<dawn_native::Instance>();
-    instance->EnableBackendValidation(mEnableBackendValidation);
-    instance->EnableGPUBasedBackendValidation(mEnableBackendValidation);
     instance->EnableBeginCaptureOnStartup(mBeginCaptureOnStartup);
-
+    instance->SetBackendValidationLevel(mBackendValidationLevel);
     instance->DiscoverDefaultAdapters();
 
 #ifdef DAWN_ENABLE_BACKEND_OPENGL
@@ -498,8 +514,21 @@
            "UseWire: "
         << (mUseWire ? "true" : "false")
         << "\n"
-           "EnableBackendValidation: "
-        << (mEnableBackendValidation ? "true" : "false");
+           "BackendValidation: ";
+
+    switch (mBackendValidationLevel) {
+        case dawn_native::BackendValidationLevel::Full:
+            log << "full";
+            break;
+        case dawn_native::BackendValidationLevel::Partial:
+            log << "partial";
+            break;
+        case dawn_native::BackendValidationLevel::Disabled:
+            log << "disabled";
+            break;
+        default:
+            UNREACHABLE();
+    }
 
     if (GetEnabledToggles().size() > 0) {
         log << "\n"
@@ -563,8 +592,8 @@
     return mUseWire;
 }
 
-bool DawnTestEnvironment::IsBackendValidationEnabled() const {
-    return mEnableBackendValidation;
+dawn_native::BackendValidationLevel DawnTestEnvironment::GetBackendValidationLevel() const {
+    return mBackendValidationLevel;
 }
 
 dawn_native::Instance* DawnTestEnvironment::GetInstance() const {
@@ -700,7 +729,7 @@
 }
 
 bool DawnTestBase::IsBackendValidationEnabled() const {
-    return gTestEnv->IsBackendValidationEnabled();
+    return gTestEnv->GetBackendValidationLevel() != dawn_native::BackendValidationLevel::Disabled;
 }
 
 bool DawnTestBase::HasWGSL() const {
diff --git a/src/tests/DawnTest.h b/src/tests/DawnTest.h
index b185c04..7224fa6 100644
--- a/src/tests/DawnTest.h
+++ b/src/tests/DawnTest.h
@@ -206,7 +206,7 @@
     void TearDown() override;
 
     bool UsesWire() const;
-    bool IsBackendValidationEnabled() const;
+    dawn_native::BackendValidationLevel GetBackendValidationLevel() const;
     dawn_native::Instance* GetInstance() const;
     bool HasVendorIdFilter() const;
     uint32_t GetVendorIdFilter() const;
@@ -227,7 +227,8 @@
     void PrintTestConfigurationAndAdapterInfo(dawn_native::Instance* instance) const;
 
     bool mUseWire = false;
-    bool mEnableBackendValidation = false;
+    dawn_native::BackendValidationLevel mBackendValidationLevel =
+        dawn_native::BackendValidationLevel::Disabled;
     bool mBeginCaptureOnStartup = false;
     bool mHasVendorIdFilter = false;
     uint32_t mVendorIdFilter = 0;