[WebGPU backend] Add --webgpu-inner-backend flag to end2end tests

Provide some way to control the inner backend of webgpu backend
to help reproduce issues in end2end tests,
especially for webgpu-on-vulkan-swiftshader on local machines
with physical gpu device.

Bug: 462536666
Change-Id: Iacd80472df36780600087e1d9a0338626d3e8882
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/275494
Commit-Queue: Shrek Shao <shrekshao@google.com>
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
diff --git a/src/dawn/native/webgpu/PhysicalDeviceWGPU.cpp b/src/dawn/native/webgpu/PhysicalDeviceWGPU.cpp
index b7f79b3..476ffce 100644
--- a/src/dawn/native/webgpu/PhysicalDeviceWGPU.cpp
+++ b/src/dawn/native/webgpu/PhysicalDeviceWGPU.cpp
@@ -59,7 +59,8 @@
     mArchitectureName = ToString(info.architecture);
     mVendorId = info.vendorID;
     mDeviceId = info.deviceID;
-    mName = absl::StrFormat("WebGPU backend on %s", FromAPI(info.backendType));
+    mName = absl::StrFormat("WebGPU backend on %s %s", FromAPI(info.backendType),
+                            ToString(info.device));
     mAdapterType = FromAPI(info.adapterType);
     mDriverDescription = ToString(info.description);
     mSubgroupMinSize = info.subgroupMinSize;
diff --git a/src/dawn/tests/DawnTest.cpp b/src/dawn/tests/DawnTest.cpp
index dad7286..34e367c 100644
--- a/src/dawn/tests/DawnTest.cpp
+++ b/src/dawn/tests/DawnTest.cpp
@@ -370,6 +370,41 @@
             mHasBackendTypeFilter = true;
             continue;
         }
+
+        constexpr const char kWebGPUInnerBackendTypeArg[] = "--webgpu-inner-backend=";
+        argLen = sizeof(kWebGPUInnerBackendTypeArg) - 1;
+        if (strncmp(argv[i], kWebGPUInnerBackendTypeArg, argLen) == 0) {
+            const char* param = argv[i] + argLen;
+            if (strcmp("undefined", param) == 0) {
+                mWebGPUInnerBackendTypeFilter = wgpu::BackendType::Undefined;
+            } else if (strcmp("d3d11", param) == 0) {
+                mWebGPUInnerBackendTypeFilter = wgpu::BackendType::D3D11;
+            } else if (strcmp("d3d12", param) == 0) {
+                mWebGPUInnerBackendTypeFilter = wgpu::BackendType::D3D12;
+            } else if (strcmp("metal", param) == 0) {
+                mWebGPUInnerBackendTypeFilter = wgpu::BackendType::Metal;
+            } else if (strcmp("null", param) == 0) {
+                mWebGPUInnerBackendTypeFilter = wgpu::BackendType::Null;
+            } else if (strcmp("opengl", param) == 0) {
+                mWebGPUInnerBackendTypeFilter = wgpu::BackendType::OpenGL;
+            } else if (strcmp("opengles", param) == 0) {
+                mWebGPUInnerBackendTypeFilter = wgpu::BackendType::OpenGLES;
+            } else if (strcmp("vulkan", param) == 0) {
+                mWebGPUInnerBackendTypeFilter = wgpu::BackendType::Vulkan;
+            } else if (strcmp("fallback", param) == 0) {
+                mWebGPUInnerBackendTypeFilter = wgpu::BackendType::Undefined;
+                mWebGPUInnerForceFallbackAdapter = true;
+            } else {
+                ErrorLog()
+                    << "Invalid inner backend \"" << param
+                    << "\". Valid backends are: undefined, d3d11, d3d12, metal, null, opengl, "
+                       "opengles, vulkan, fallback.";
+                DAWN_UNREACHABLE();
+            }
+            mHasWebGPUInnerBackendTypeFilter = true;
+            continue;
+        }
+
         if (strcmp("-h", argv[i]) == 0 || strcmp("--help", argv[i]) == 0) {
             InfoLog()
                 << "\n\nUsage: " << argv[0]
@@ -394,7 +429,10 @@
                    "  --adapter-vendor-id: Select adapter by vendor id to run end2end tests"
                    "on multi-GPU systems \n"
                    "  --backend: Select adapter by backend type. Valid backends are: d3d12, metal, "
-                   "null, opengl, opengles, vulkan\n"
+                   "null, opengl, opengles, vulkan, webgpu\n"
+                   "  --webgpu-inner-backend: Select inner backend for WebGPU backend. "
+                   "Valid backends are: undefined, d3d11, d3d12, metal, null, opengl, opengles, "
+                   "vulkan, fallback\n"
                    "  --exclusive-device-type-preference: Comma-delimited list of preferred device "
                    "types. For each backend, tests will run only on adapters that match the first "
                    "available device type\n"
@@ -496,13 +534,17 @@
     std::set<std::tuple<wgpu::BackendType, std::string, bool>> adapterNameSet;
     for (wgpu::FeatureLevel featureLevel :
          {wgpu::FeatureLevel::Core, wgpu::FeatureLevel::Compatibility}) {
-        wgpu::RequestAdapterOptions adapterOptions;
+        wgpu::RequestAdapterOptions adapterOptions = {};
         adapterOptions.featureLevel = featureLevel;
 
         auto adapters = instance->EnumerateAdapters(&adapterOptions);
 
         // Include enumerating WebGPU-on-WebGPU backends.
         wgpu::RequestAdapterWebGPUBackendOptions webgpuBackendOptions = {};
+        if (HasWebGPUInnerBackendTypeFilter()) {
+            adapterOptions.backendType = GetWebGPUInnerBackendTypeFilter();
+            adapterOptions.forceFallbackAdapter = GetWebGPUInnerForceFallbackAdapter();
+        }
         adapterOptions.nextInChain = &webgpuBackendOptions;
 
         {
@@ -751,6 +793,18 @@
     return mBackendTypeFilter;
 }
 
+bool DawnTestEnvironment::HasWebGPUInnerBackendTypeFilter() const {
+    return mHasWebGPUInnerBackendTypeFilter;
+}
+
+wgpu::BackendType DawnTestEnvironment::GetWebGPUInnerBackendTypeFilter() const {
+    return mWebGPUInnerBackendTypeFilter;
+}
+
+bool DawnTestEnvironment::GetWebGPUInnerForceFallbackAdapter() const {
+    return mWebGPUInnerForceFallbackAdapter;
+}
+
 const char* DawnTestEnvironment::GetWireTraceDir() const {
     if (mWireTraceDir.length() == 0) {
         return nullptr;
@@ -793,6 +847,13 @@
         wgpu::RequestAdapterWebGPUBackendOptions webgpuBackendOptions = {};
         if (gCurrentTest->mParam.adapterProperties.backendType == wgpu::BackendType::WebGPU) {
             adapterOptions.backendType = wgpu::BackendType::Undefined;
+
+            if (gTestEnv->HasWebGPUInnerBackendTypeFilter()) {
+                adapterOptions.backendType = gTestEnv->GetWebGPUInnerBackendTypeFilter();
+                adapterOptions.forceFallbackAdapter =
+                    gTestEnv->GetWebGPUInnerForceFallbackAdapter();
+            }
+
             webgpuBackendOptions.nextInChain = adapterOptions.nextInChain;
             adapterOptions.nextInChain = &webgpuBackendOptions;
         } else {
diff --git a/src/dawn/tests/DawnTest.h b/src/dawn/tests/DawnTest.h
index af666d4..db28be0 100644
--- a/src/dawn/tests/DawnTest.h
+++ b/src/dawn/tests/DawnTest.h
@@ -210,6 +210,9 @@
     uint32_t GetVendorIdFilter() const;
     bool HasBackendTypeFilter() const;
     wgpu::BackendType GetBackendTypeFilter() const;
+    bool HasWebGPUInnerBackendTypeFilter() const;
+    wgpu::BackendType GetWebGPUInnerBackendTypeFilter() const;
+    bool GetWebGPUInnerForceFallbackAdapter() const;
     const char* GetWireTraceDir() const;
 
     const std::vector<std::string>& GetEnabledToggles() const;
@@ -241,6 +244,9 @@
     uint32_t mVendorIdFilter = 0;
     bool mHasBackendTypeFilter = false;
     wgpu::BackendType mBackendTypeFilter;
+    bool mHasWebGPUInnerBackendTypeFilter = false;
+    wgpu::BackendType mWebGPUInnerBackendTypeFilter = wgpu::BackendType::Undefined;
+    bool mWebGPUInnerForceFallbackAdapter = false;
     std::string mWireTraceDir;
     bool mRunSuppressedTests = false;
     bool mIsTestLauncherBotMode = false;
diff --git a/src/dawn/tests/end2end/AdapterEnumerationTests.cpp b/src/dawn/tests/end2end/AdapterEnumerationTests.cpp
index ffc629c..54cf325 100644
--- a/src/dawn/tests/end2end/AdapterEnumerationTests.cpp
+++ b/src/dawn/tests/end2end/AdapterEnumerationTests.cpp
@@ -360,6 +360,22 @@
         }
     }
 
+    // Test selecting a force fallback adapter.
+    {
+        adapterOptions.backendType = wgpu::BackendType::Undefined;
+        adapterOptions.forceFallbackAdapter = true;
+        const auto& adapters = instance.EnumerateAdapters(&adapterOptions);
+        for (const auto& nativeAdapter : adapters) {
+            wgpu::Adapter adapter = wgpu::Adapter(nativeAdapter.Get());
+            wgpu::AdapterInfo info;
+            adapter.GetInfo(&info);
+
+            EXPECT_EQ(info.backendType, wgpu::BackendType::WebGPU);
+            EXPECT_NE(std::string_view(info.device.data, info.device.length).find("SwiftShader"),
+                      std::string_view::npos);
+        }
+    }
+
     // Test selecting WebGPUBackend on WebGPUBackend gives nothing.
     {
         adapterOptions.backendType = wgpu::BackendType::WebGPU;