Add backend and toggle options to ManualSurfaceTests

Bug: 346802084
Bug: 42241992
Change-Id: I66da6dc06eefbb0e28f9363b8a84387a0ace262f
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/194561
Reviewed-by: Austin Eng <enga@chromium.org>
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
diff --git a/src/dawn/samples/ManualSurfaceTest.cpp b/src/dawn/samples/ManualSurfaceTest.cpp
index c9ef652..4e686a6 100644
--- a/src/dawn/samples/ManualSurfaceTest.cpp
+++ b/src/dawn/samples/ManualSurfaceTest.cpp
@@ -78,6 +78,7 @@
 //    - Check with GLFW transparency on / off.
 
 #include <algorithm>
+#include <iostream>
 #include <memory>
 #include <string>
 #include <unordered_map>
@@ -90,6 +91,7 @@
 #include "dawn/dawn_proc.h"
 #include "dawn/native/DawnNative.h"
 #include "dawn/utils/ComboRenderPipelineDescriptor.h"
+#include "dawn/utils/CommandLineParser.h"
 #include "dawn/utils/WGPUHelpers.h"
 #include "dawn/webgpu_cpp.h"
 #include "dawn/webgpu_cpp_print.h"
@@ -136,7 +138,7 @@
 static std::unordered_map<GLFWwindow*, std::unique_ptr<WindowData>> windows;
 static uint64_t windowSerial = 0;
 
-static std::unique_ptr<dawn::native::Instance> instance;
+static wgpu::Instance instance;
 static wgpu::Adapter adapter;
 static wgpu::Device device;
 static wgpu::Queue queue;
@@ -200,7 +202,7 @@
     GLFWwindow* window = glfwCreateWindow(400, 400, "", nullptr, nullptr);
     glfwSetKeyCallback(window, OnKeyPress);
 
-    wgpu::Surface surface = wgpu::glfw::CreateSurfaceForWindow(instance->Get(), window);
+    wgpu::Surface surface = wgpu::glfw::CreateSurfaceForWindow(instance, window);
     wgpu::SurfaceCapabilities caps;
     surface.GetCapabilities(adapter, &caps);
 
@@ -343,7 +345,41 @@
 }
 
 int main(int argc, const char* argv[]) {
-    // Setup GLFW
+    // Parse command line options.
+    dawn::utils::CommandLineParser parser;
+    auto& helpOpt = parser.AddHelp();
+    auto& enableTogglesOpt = parser.AddStringList("enable-toggles", "Toggles to enable in Dawn")
+                                 .ShortName('e')
+                                 .Parameter("comma separated list");
+    auto& disableTogglesOpt = parser.AddStringList("disable-toggles", "Toggles to disable in Dawn")
+                                  .ShortName('d')
+                                  .Parameter("comma separated list");
+    auto& backendOpt =
+        parser
+            .AddEnum<wgpu::BackendType>({{"d3d11", wgpu::BackendType::D3D11},
+                                         {"d3d12", wgpu::BackendType::D3D12},
+                                         {"metal", wgpu::BackendType::Metal},
+                                         {"null", wgpu::BackendType::Null},
+                                         {"opengl", wgpu::BackendType::OpenGL},
+                                         {"opengles", wgpu::BackendType::OpenGLES},
+                                         {"vulkan", wgpu::BackendType::Vulkan}},
+                                        "backend", "The backend to get an adapter from")
+            .ShortName('b')
+            .Default(wgpu::BackendType::Undefined);
+
+    auto parserResult = parser.Parse(argc, argv);
+    if (!parserResult.success) {
+        std::cerr << parserResult.errorMessage << "\n";
+        return 1;
+    }
+
+    if (helpOpt.GetValue()) {
+        std::cout << "Usage: " << argv[0] << " <options>\n\noptions\n";
+        parser.PrintHelp(std::cout);
+        return 0;
+    }
+
+    // Setup GLFW, Dawn procs
     glfwSetErrorCallback([](int code, const char* message) {
         dawn::ErrorLog() << "GLFW error " << code << " " << message;
     });
@@ -351,19 +387,74 @@
         return 1;
     }
 
-    // Choose an adapter we like.
-    // TODO(dawn:269): allow switching the window between devices.
     DawnProcTable procs = dawn::native::GetProcs();
     dawnProcSetProcs(&procs);
 
-    instance = std::make_unique<dawn::native::Instance>();
+    // Make an instance with the toggles.
+    std::vector<const char*> enableToggleNames;
+    std::vector<const char*> disabledToggleNames;
+    for (auto toggle : enableTogglesOpt.GetValue()) {
+        enableToggleNames.push_back(toggle.c_str());
+    }
 
-    dawn::native::Adapter chosenAdapter = instance->EnumerateAdapters()[0];
-    DAWN_ASSERT(chosenAdapter);
-    adapter = wgpu::Adapter(chosenAdapter.Get());
+    for (auto toggle : disableTogglesOpt.GetValue()) {
+        disabledToggleNames.push_back(toggle.c_str());
+    }
+    wgpu::DawnTogglesDescriptor toggles;
+    toggles.enabledToggles = enableToggleNames.data();
+    toggles.enabledToggleCount = enableToggleNames.size();
+    toggles.disabledToggles = disabledToggleNames.data();
+    toggles.disabledToggleCount = disabledToggleNames.size();
+
+    wgpu::InstanceDescriptor instanceDescriptor{};
+    instanceDescriptor.nextInChain = &toggles;
+    instanceDescriptor.features.timedWaitAnyEnable = true;
+    instance = wgpu::CreateInstance(&instanceDescriptor);
+
+    // Choose an adapter we like.
+    // TODO(dawn:269): allow switching the window between devices.
+    wgpu::RequestAdapterOptions options = {};
+    options.backendType = backendOpt.GetValue();
+    if (options.backendType != wgpu::BackendType::Undefined) {
+        options.compatibilityMode = dawn::utils::BackendRequiresCompat(options.backendType);
+    }
+
+    wgpu::Future adapterFuture = instance.RequestAdapter(
+        &options, wgpu::CallbackMode::WaitAnyOnly,
+        [&](wgpu::RequestAdapterStatus status, wgpu::Adapter adapterIn, const char* message) {
+            if (status != wgpu::RequestAdapterStatus::Success) {
+                dawn::ErrorLog() << "Failed to get an adapter: " << message;
+                return;
+            }
+            adapter = adapterIn;
+        });
+    instance.WaitAny(adapterFuture, UINT64_MAX);
+
+    if (adapter == nullptr) {
+        return 1;
+    }
+
+    wgpu::AdapterInfo adapterInfo;
+    adapter.GetInfo(&adapterInfo);
+    std::cout << "Using adapter \"" << adapterInfo.device << "\" on " << adapterInfo.backendType
+              << ".\n";
 
     // Setup the device on that adapter.
-    device = wgpu::Device::Acquire(chosenAdapter.CreateDevice());
+    wgpu::Future deviceFuture = adapter.RequestDevice(
+        nullptr, wgpu::CallbackMode::WaitAnyOnly,
+        [&](wgpu::RequestDeviceStatus status, wgpu::Device deviceIn, const char* message) {
+            if (status != wgpu::RequestDeviceStatus::Success) {
+                dawn::ErrorLog() << "Failed to get a device:" << message;
+                return;
+            }
+            device = deviceIn;
+        });
+    instance.WaitAny(deviceFuture, UINT64_MAX);
+
+    if (device == nullptr) {
+        return 1;
+    }
+
     device.SetUncapturedErrorCallback(
         [](WGPUErrorType errorType, const char* message, void*) {
             const char* errorTypeName = "";
@@ -395,7 +486,7 @@
 
     while (windows.size() != 0) {
         glfwPollEvents();
-        wgpuInstanceProcessEvents(instance->Get());
+        instance.ProcessEvents();
 
         for (auto it = windows.begin(); it != windows.end();) {
             GLFWwindow* window = it->first;
diff --git a/src/dawn/tests/unittests/CommandLineParserTests.cpp b/src/dawn/tests/unittests/CommandLineParserTests.cpp
index 9d8cc62..5640b93 100644
--- a/src/dawn/tests/unittests/CommandLineParserTests.cpp
+++ b/src/dawn/tests/unittests/CommandLineParserTests.cpp
@@ -429,7 +429,7 @@
 }
 
 // Tests for the generation of the help strings for the options.
-TEST(CommandLineParserTest, OptionHelp) {
+TEST(CommandLineParserTest, PrintHelp) {
     // A test with a few options, checks that they are sorted.
     {
         CLP opts;
@@ -438,7 +438,7 @@
         opts.AddString("baz");
 
         std::stringstream s;
-        opts.AddHelp(s);
+        opts.PrintHelp(s);
         EXPECT_EQ(s.str(), R"(--bar <value>
 --baz <value>
 --foo <value>
@@ -451,7 +451,7 @@
         opts.AddString("foo").Parameter("bar");
 
         std::stringstream s;
-        opts.AddHelp(s);
+        opts.PrintHelp(s);
         EXPECT_EQ(s.str(), R"(--foo <bar>
 )");
     }
@@ -462,7 +462,7 @@
         opts.AddBool("foo", "enable fooing");
 
         std::stringstream s;
-        opts.AddHelp(s);
+        opts.PrintHelp(s);
         EXPECT_EQ(s.str(), R"(--foo  enable fooing
 )");
     }
@@ -479,7 +479,7 @@
         opts.AddEnum(conversions, "cell", "which story to get");
 
         std::stringstream s;
-        opts.AddHelp(s);
+        opts.PrintHelp(s);
         EXPECT_EQ(s.str(), R"(--cell <pop|six|uh-uh>  which story to get
 )");
     }
@@ -490,12 +490,27 @@
         opts.AddString("foo").ShortName('f');
 
         std::stringstream s;
-        opts.AddHelp(s);
+        opts.PrintHelp(s);
         EXPECT_EQ(s.str(), R"(--foo <value>
 -f  alias for --foo
 )");
     }
 }
 
+// Tests that AddHelp() add the correct option.
+TEST(CommandLineParserTest, HelpOption) {
+    CLP opts;
+    CLP::BoolOption& helpOpt = opts.AddHelp();
+
+    std::stringstream s;
+    opts.PrintHelp(s);
+    EXPECT_EQ(s.str(), R"(--help  Shows the help
+-h  alias for --help
+)");
+
+    ExpectSuccess(opts.Parse(Split("-h")));
+    EXPECT_TRUE(helpOpt.GetValue());
+}
+
 }  // anonymous namespace
 }  // namespace dawn
diff --git a/src/dawn/utils/CommandLineParser.cpp b/src/dawn/utils/CommandLineParser.cpp
index b8c0c2d..eca9e03 100644
--- a/src/dawn/utils/CommandLineParser.cpp
+++ b/src/dawn/utils/CommandLineParser.cpp
@@ -198,6 +198,10 @@
     return absl::StrJoin(names, separator);
 }
 
+CommandLineParser::BoolOption& CommandLineParser::AddHelp() {
+    return AddBool("help", "Shows the help").ShortName('h');
+}
+
 // static
 const CommandLineParser::ParseOptions CommandLineParser::kDefaultParseOptions = {};
 
@@ -307,7 +311,7 @@
     return Parse(args, parseOptions);
 }
 
-void CommandLineParser::AddHelp(std::ostream& s) {
+void CommandLineParser::PrintHelp(std::ostream& s) {
     // Sort options in alphabetical order using a trick that std::tuple is sorted lexicographically.
     std::vector<std::tuple<std::string_view, OptionBase*>> sortedOptions;
     for (auto& option : mOptions) {
diff --git a/src/dawn/utils/CommandLineParser.h b/src/dawn/utils/CommandLineParser.h
index 457b07d..a8759b9 100644
--- a/src/dawn/utils/CommandLineParser.h
+++ b/src/dawn/utils/CommandLineParser.h
@@ -45,7 +45,7 @@
 //   CommandLineParser parser;
 //   auto& dryRun = parser.AddBool("dry-run", "fake operations").ShortName('d');
 //   auto& input = parser.AddString("input", "the input file to process").ShortName('i');
-//   auto& help = opts.AddBool("help", "Shows the help").ShortName('h');
+//   auto& help = opts.AddHelp();
 //
 //   auto result = parser.Parse(argc, argv);
 //   if (!result.success) {
@@ -55,7 +55,7 @@
 //
 //   if (help.GetValue()) {
 //       std::cout << "Usage: " << argv[0] << " <options>\n\noptions\n";
-//       parser.AddHelp(std::cout);
+//       parser.PrintHelp(std::cout);
 //       return 0;
 //   }
 //
@@ -196,6 +196,9 @@
         return AddOption(std::make_unique<EnumOption<E>>(std::move(conversions), name, desc));
     }
 
+    // Helper to add a --help option.
+    BoolOption& AddHelp();
+
     // Helper structs for the Parse calls.
     struct ParseResult {
         bool success;
@@ -219,7 +222,7 @@
                       const ParseOptions& parseOptions = kDefaultParseOptions);
 
     // Generate summary of options for a --help and add it to the stream.
-    void AddHelp(std::ostream& s);
+    void PrintHelp(std::ostream& s);
 
   private:
     template <typename T>
diff --git a/src/dawn/utils/WGPUHelpers.cpp b/src/dawn/utils/WGPUHelpers.cpp
index 7086096..297fee4 100644
--- a/src/dawn/utils/WGPUHelpers.cpp
+++ b/src/dawn/utils/WGPUHelpers.cpp
@@ -452,4 +452,21 @@
     return info;
 }
 
+bool BackendRequiresCompat(wgpu::BackendType backend) {
+    switch (backend) {
+        case wgpu::BackendType::D3D12:
+        case wgpu::BackendType::Metal:
+        case wgpu::BackendType::Vulkan:
+        case wgpu::BackendType::WebGPU:
+        case wgpu::BackendType::Null:
+            return false;
+        case wgpu::BackendType::D3D11:
+        case wgpu::BackendType::OpenGL:
+        case wgpu::BackendType::OpenGLES:
+            return true;
+        case wgpu::BackendType::Undefined:
+            DAWN_UNREACHABLE();
+    }
+}
+
 }  // namespace dawn::utils
diff --git a/src/dawn/utils/WGPUHelpers.h b/src/dawn/utils/WGPUHelpers.h
index fcd8f42..1d341bd 100644
--- a/src/dawn/utils/WGPUHelpers.h
+++ b/src/dawn/utils/WGPUHelpers.h
@@ -207,6 +207,8 @@
 ColorSpaceConversionInfo GetYUVBT709ToRGBSRGBColorSpaceConversionInfo();
 ColorSpaceConversionInfo GetNoopRGBColorSpaceConversionInfo();
 
+bool BackendRequiresCompat(wgpu::BackendType backend);
+
 }  // namespace dawn::utils
 
 #endif  // SRC_DAWN_UTILS_WGPUHELPERS_H_