dawn.node: Try to add support for compatibility mode

Also adds support for forceFallbackAdapter.

Change-Id: I088fba5b556ac5a5198bdc3c73673784eeea5cc8
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/147201
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Stephen White <senorblanco@chromium.org>
Reviewed-by: Ben Clayton <bclayton@google.com>
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
diff --git a/src/dawn/node/binding/GPU.cpp b/src/dawn/node/binding/GPU.cpp
index eaf78ab..8c3d2bc 100644
--- a/src/dawn/node/binding/GPU.cpp
+++ b/src/dawn/node/binding/GPU.cpp
@@ -114,59 +114,48 @@
     auto promise =
         interop::Promise<std::optional<interop::Interface<interop::GPUAdapter>>>(env, PROMISE_INFO);
 
-    if (options.forceFallbackAdapter) {
-        // Software adapters are not currently supported.
-        promise.Resolve({});
-        return promise;
-    }
-
     RequestAdapterOptions nativeOptions;
+    nativeOptions.forceFallbackAdapter = options.forceFallbackAdapter;
+    nativeOptions.compatibilityMode = options.compatibilityMode;
+
+    // Convert the power preference.
+    nativeOptions.powerPreference = PowerPreference::Undefined;
     if (options.powerPreference.has_value()) {
-        // TODO(dneto): Assign power preference
+        switch (options.powerPreference.value()) {
+            case interop::GPUPowerPreference::kLowPower:
+                nativeOptions.powerPreference = PowerPreference::LowPower;
+                break;
+            case interop::GPUPowerPreference::kHighPerformance:
+                nativeOptions.powerPreference = PowerPreference::HighPerformance;
+                break;
+        }
     }
 
-    // Propagate toggles.
-    TogglesLoader togglesLoader(flags_);
-    DawnTogglesDescriptor togglesDescriptor = togglesLoader.GetDescriptor();
-    nativeOptions.nextInChain = &togglesDescriptor;
-
-    auto adapters = instance_.EnumerateAdapters(&nativeOptions);
-    if (adapters.empty()) {
-        promise.Resolve({});
-        return promise;
-    }
-
+    // Choose the backend to use.
 #if defined(_WIN32)
-    constexpr auto defaultBackendType = wgpu::BackendType::D3D12;
+    constexpr auto kDefaultBackendType = wgpu::BackendType::D3D12;
 #elif defined(__linux__)
-    constexpr auto defaultBackendType = wgpu::BackendType::Vulkan;
+    constexpr auto kDefaultBackendType = wgpu::BackendType::Vulkan;
 #elif defined(__APPLE__)
-    constexpr auto defaultBackendType = wgpu::BackendType::Metal;
+    constexpr auto kDefaultBackendType = wgpu::BackendType::Metal;
 #else
 #error "Unsupported platform"
 #endif
+    nativeOptions.backendType = kDefaultBackendType;
 
-    // Check for backend override from env var / flag
+    // Check for backend override from env var / flag.
     std::string forceBackend;
     if (auto f = flags_.Get("backend")) {
         forceBackend = *f;
     } else if (std::string envVar = GetEnvVar("DAWNNODE_BACKEND"); !envVar.empty()) {
         forceBackend = envVar;
     }
-
-    // Check for specific adapter name
-    std::string adapterName;
-    if (auto f = flags_.Get("adapter")) {
-        adapterName = *f;
-    }
-
     std::transform(forceBackend.begin(), forceBackend.end(), forceBackend.begin(),
                    [](char c) { return std::tolower(c); });
 
-    auto targetBackendType = defaultBackendType;
     if (!forceBackend.empty()) {
         if (auto parsed = ParseBackend(forceBackend)) {
-            targetBackendType = parsed.value();
+            nativeOptions.backendType = parsed.value();
         } else {
             std::stringstream msg;
             msg << "unrecognised backend '" + forceBackend + "'" << std::endl
@@ -182,13 +171,27 @@
         }
     }
 
+    // Propagate toggles.
+    TogglesLoader togglesLoader(flags_);
+    DawnTogglesDescriptor togglesDescriptor = togglesLoader.GetDescriptor();
+    nativeOptions.nextInChain = &togglesDescriptor;
+
+    auto adapters = instance_.EnumerateAdapters(&nativeOptions);
+    if (adapters.empty()) {
+        promise.Resolve({});
+        return promise;
+    }
+
+    // Check for specific adapter name
+    std::string adapterName;
+    if (auto f = flags_.Get("adapter")) {
+        adapterName = *f;
+    }
+
     dawn::native::Adapter* adapter = nullptr;
     for (auto& a : adapters) {
         wgpu::AdapterProperties props;
         a.GetProperties(&props);
-        if (props.backendType != targetBackendType) {
-            continue;
-        }
         if (!adapterName.empty() && props.name &&
             std::string(props.name).find(adapterName) == std::string::npos) {
             continue;
diff --git a/src/dawn/node/binding/GPUAdapter.cpp b/src/dawn/node/binding/GPUAdapter.cpp
index de7d365..303ca38 100644
--- a/src/dawn/node/binding/GPUAdapter.cpp
+++ b/src/dawn/node/binding/GPUAdapter.cpp
@@ -99,6 +99,12 @@
     return adapterProperties.adapterType == WGPUAdapterType_CPU;
 }
 
+bool GPUAdapter::getIsCompatibilityMode(Napi::Env) {
+    WGPUAdapterProperties adapterProperties = {};
+    adapter_.GetProperties(&adapterProperties);
+    return adapterProperties.compatibilityMode;
+}
+
 interop::Promise<interop::Interface<interop::GPUDevice>> GPUAdapter::requestDevice(
     Napi::Env env,
     interop::GPUDeviceDescriptor descriptor) {
diff --git a/src/dawn/node/binding/GPUAdapter.h b/src/dawn/node/binding/GPUAdapter.h
index 60b8436..8f0fdc4 100644
--- a/src/dawn/node/binding/GPUAdapter.h
+++ b/src/dawn/node/binding/GPUAdapter.h
@@ -41,6 +41,7 @@
     interop::Interface<interop::GPUSupportedFeatures> getFeatures(Napi::Env) override;
     interop::Interface<interop::GPUSupportedLimits> getLimits(Napi::Env) override;
     bool getIsFallbackAdapter(Napi::Env) override;
+    bool getIsCompatibilityMode(Napi::Env) override;
 
   private:
     dawn::native::Adapter adapter_;
diff --git a/src/dawn/node/interop/DawnExtensions.idl b/src/dawn/node/interop/DawnExtensions.idl
index a24a9bb..da97b08 100644
--- a/src/dawn/node/interop/DawnExtensions.idl
+++ b/src/dawn/node/interop/DawnExtensions.idl
@@ -19,3 +19,11 @@
     "chromium-experimental-subgroups",
     "chromium-experimental-subgroup-uniform-control-flow",
 };
+
+dictionary GPURequestAdapterOptions {
+    boolean compatibilityMode = false;
+};
+
+interface GPUAdapter {
+    readonly attribute boolean isCompatibilityMode;
+};
diff --git a/tools/src/cmd/idlgen/main.go b/tools/src/cmd/idlgen/main.go
index 2fd039c..451206a 100644
--- a/tools/src/cmd/idlgen/main.go
+++ b/tools/src/cmd/idlgen/main.go
@@ -206,6 +206,7 @@
 		mixins := map[string]*ast.Mixin{}
 		includes := []*ast.Includes{}
 		enums := map[string]*ast.Enum{}
+		dicts := map[string]*ast.Dictionary{}
 		for _, d := range in.Declarations {
 			switch d := d.(type) {
 			case *ast.Interface:
@@ -233,6 +234,16 @@
 					enums[d.Name] = d
 					s.declarations[d.Name] = d
 				}
+			case *ast.Dictionary:
+				if e, ok := dicts[d.Name]; ok {
+					// Merge partial dictionaries into one dictionary
+					e.Members = append(e.Members, d.Members...)
+				} else {
+					clone := *d
+					d := &clone
+					dicts[d.Name] = d
+					s.declarations[d.Name] = d
+				}
 			default:
 				if name := nameOf(d); name != "" {
 					s.declarations[nameOf(d)] = d