Dawn: Implement adapter toggles and promote UseDXC as adapter toggle

This CL implement adapter toggles by accepting DawnTogglesDescriptor in
instance.EnumerateAdapters and APIRequestAdapter, and also promote
UseDXC as an adapter toggle. This CL also make adapters report supported
features based on its own toggles state, while validate device required
features using device's toggles state. In this case, a device may
support more features than its adapter reported to support (i.e. those
features enabled by device's overridden toggles).

Bug: dawn:1495
Change-Id: I08cefc14c636d749520b11bf6db8dd13b2cdce7d
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/136481
Reviewed-by: Austin Eng <enga@chromium.org>
Commit-Queue: Zhaoming Jiang <zhaoming.jiang@intel.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
diff --git a/dawn.json b/dawn.json
index a975648..8a25394 100644
--- a/dawn.json
+++ b/dawn.json
@@ -173,7 +173,7 @@
         "tags": ["dawn", "native"],
         "category": "structure",
         "chained": "in",
-        "chain roots": ["instance descriptor", "device descriptor"],
+        "chain roots": ["instance descriptor", "request adapter options", "device descriptor"],
         "members": [
             {"name": "enabled toggles count", "type": "size_t", "default": 0},
             {"name": "enabled toggles", "type": "char", "annotation": "const*const*", "length": "enabled toggles count"},
diff --git a/docs/dawn/features/adapter_options.md b/docs/dawn/features/adapter_options.md
index 56c209f..ea5d652 100644
--- a/docs/dawn/features/adapter_options.md
+++ b/docs/dawn/features/adapter_options.md
@@ -7,6 +7,8 @@
 features may not be suitable for general use yet. Currently, they are used in Dawn's testing, and
 in Chromium-specific integration with Dawn.
 
+`DawnTogglesDescriptor` can also be chained on `RequestAdapterOptions` to provide the required adapter toggles. However, the final adapter toggles state also depends on instance toggles inheritance and adapter toggles validation/default-setting.
+
 `dawn::native::Instance::EnumerateAdapters` is a Dawn native-only API that may be used to synchronously
 get a list of adapters according to the RequestAdapterOptions. The members are treated as follows:
  - `RequestAdapterOptions::compatibleSurface` is ignored.
@@ -26,3 +28,9 @@
 ### `RequestAdapterOptionsLUID`
 
 When discovering adapters on D3D11 and D3D12, Dawn only discovers adapters matching the provided `RequestAdapterOptionsLUID::adapterLUID`. This extension struct does nothing on other backends.
+
+### `DawnTogglesDescriptor`
+
+When discovering adapters, Dawn will use chained `DawnTogglesDescriptor` as required adapter
+toggles. The final toggles state of each result adapter depends on the inheritance of instance
+toggles state, the backend-specific validation and the backend-specific default setting.
diff --git a/include/dawn/native/DawnNative.h b/include/dawn/native/DawnNative.h
index 7d354c9..81db699 100644
--- a/include/dawn/native/DawnNative.h
+++ b/include/dawn/native/DawnNative.h
@@ -181,7 +181,8 @@
 
     // Discovers and returns a vector of adapters.
     // All systems adapters that can be found are returned if no options are passed.
-    // Otherwise, returns adapters based on the `options`.
+    // Otherwise, returns adapters based on the `options`. Adapter toggles descriptor can chained
+    // after options.
     std::vector<Adapter> EnumerateAdapters(const WGPURequestAdapterOptions* options) const;
     std::vector<Adapter> EnumerateAdapters(
         const wgpu::RequestAdapterOptions* options = nullptr) const;
diff --git a/src/dawn/native/Adapter.cpp b/src/dawn/native/Adapter.cpp
index f79e1d4..2e17706 100644
--- a/src/dawn/native/Adapter.cpp
+++ b/src/dawn/native/Adapter.cpp
@@ -27,20 +27,17 @@
 
 namespace dawn::native {
 
-AdapterBase::AdapterBase(Ref<PhysicalDeviceBase> physicalDevice, FeatureLevel featureLevel)
-    : AdapterBase(physicalDevice,
-                  featureLevel,
-                  TogglesState(ToggleStage::Adapter)
-                      .InheritFrom(physicalDevice->GetInstance()->GetTogglesState())) {}
-
 AdapterBase::AdapterBase(Ref<PhysicalDeviceBase> physicalDevice,
                          FeatureLevel featureLevel,
-                         const TogglesState& adapterToggles)
+                         const TogglesState& requiredAdapterToggles)
     : mPhysicalDevice(std::move(physicalDevice)),
       mFeatureLevel(featureLevel),
-      mTogglesState(adapterToggles) {
+      mTogglesState(requiredAdapterToggles) {
     ASSERT(mPhysicalDevice->SupportsFeatureLevel(featureLevel));
     ASSERT(mTogglesState.GetStage() == ToggleStage::Adapter);
+    // Cache the supported features of this adapter. Note that with device toggles overriding, a
+    // device created by this adapter may support features not in this set and vice versa.
+    mSupportedFeatures = mPhysicalDevice->GetSupportedFeatures(mTogglesState);
 }
 
 AdapterBase::~AdapterBase() = default;
@@ -49,6 +46,10 @@
     mUseTieredLimits = useTieredLimits;
 }
 
+FeaturesSet AdapterBase::GetSupportedFeatures() const {
+    return mSupportedFeatures;
+}
+
 PhysicalDeviceBase* AdapterBase::GetPhysicalDevice() {
     return mPhysicalDevice.Get();
 }
@@ -101,11 +102,11 @@
 }
 
 bool AdapterBase::APIHasFeature(wgpu::FeatureName feature) const {
-    return mPhysicalDevice->HasFeature(feature);
+    return mSupportedFeatures.IsEnabled(feature);
 }
 
 size_t AdapterBase::APIEnumerateFeatures(wgpu::FeatureName* features) const {
-    return mPhysicalDevice->EnumerateFeatures(features);
+    return mSupportedFeatures.EnumerateFeatures(features);
 }
 
 DeviceBase* AdapterBase::APICreateDevice(const DeviceDescriptor* descriptor) {
@@ -140,11 +141,12 @@
     // Backend-specific forced and default device toggles
     mPhysicalDevice->SetupBackendDeviceToggles(&deviceToggles);
 
-    // Validate all required features are supported by the adapter and suitable under given toggles.
-    // Note that certain toggles in device toggles state may be overriden by user and different from
-    // the adapter toggles state.
-    // TODO(dawn:1495): After implementing adapter toggles, decide whether we should validate
-    // supported features using adapter toggles or device toggles.
+    // Validate all required features are supported by the adapter and suitable under device
+    // toggles. Note that certain toggles in device toggles state may be overriden by user and
+    // different from the adapter toggles state, and in this case a device may support features
+    // that not supported by the adapter. We allow such toggles overriding for the convinience e.g.
+    // creating a deivce for internal usage with AllowUnsafeAPI enabled from an adapter that
+    // disabled AllowUnsafeAPIS.
     for (uint32_t i = 0; i < descriptor->requiredFeaturesCount; ++i) {
         wgpu::FeatureName feature = descriptor->requiredFeatures[i];
         DAWN_TRY(mPhysicalDevice->ValidateFeatureSupportedWithToggles(feature, deviceToggles));
diff --git a/src/dawn/native/Adapter.h b/src/dawn/native/Adapter.h
index 1b16546..081576e 100644
--- a/src/dawn/native/Adapter.h
+++ b/src/dawn/native/Adapter.h
@@ -30,10 +30,9 @@
 
 class AdapterBase : public RefCounted {
   public:
-    AdapterBase(Ref<PhysicalDeviceBase> physicalDevice, FeatureLevel featureLevel);
     AdapterBase(Ref<PhysicalDeviceBase> physicalDevice,
                 FeatureLevel featureLevel,
-                const TogglesState& adapterToggles);
+                const TogglesState& requiredAdapterToggles);
     ~AdapterBase() override;
 
     // WebGPU API
@@ -50,6 +49,8 @@
 
     void SetUseTieredLimits(bool useTieredLimits);
 
+    FeaturesSet GetSupportedFeatures() const;
+
     // Return the underlying PhysicalDevice.
     PhysicalDeviceBase* GetPhysicalDevice();
 
@@ -62,7 +63,11 @@
     Ref<PhysicalDeviceBase> mPhysicalDevice;
     FeatureLevel mFeatureLevel;
     bool mUseTieredLimits = false;
-    // Adapter toggles state, currently only inherited from instance toggles state.
+
+    // Supported features under adapter toggles.
+    FeaturesSet mSupportedFeatures;
+
+    // Adapter toggles state.
     TogglesState mTogglesState;
 };
 
diff --git a/src/dawn/native/DawnNative.cpp b/src/dawn/native/DawnNative.cpp
index 692a77e..7a1f008 100644
--- a/src/dawn/native/DawnNative.cpp
+++ b/src/dawn/native/DawnNative.cpp
@@ -84,7 +84,7 @@
 }
 
 std::vector<const char*> Adapter::GetSupportedFeatures() const {
-    FeaturesSet supportedFeaturesSet = mImpl->GetPhysicalDevice()->GetSupportedFeatures();
+    FeaturesSet supportedFeaturesSet = mImpl->GetSupportedFeatures();
     return supportedFeaturesSet.GetEnabledFeatureNames();
 }
 
diff --git a/src/dawn/native/Device.cpp b/src/dawn/native/Device.cpp
index 5d0b4a7..477b0a9 100644
--- a/src/dawn/native/Device.cpp
+++ b/src/dawn/native/Device.cpp
@@ -1410,8 +1410,9 @@
 
 void DeviceBase::ApplyFeatures(const DeviceDescriptor* deviceDescriptor) {
     ASSERT(deviceDescriptor);
+    // Validate all required features with device toggles.
     ASSERT(GetPhysicalDevice()->SupportsAllRequiredFeatures(
-        {deviceDescriptor->requiredFeatures, deviceDescriptor->requiredFeaturesCount}));
+        {deviceDescriptor->requiredFeatures, deviceDescriptor->requiredFeaturesCount}, mToggles));
 
     for (uint32_t i = 0; i < deviceDescriptor->requiredFeaturesCount; ++i) {
         mEnabledFeatures.EnableFeature(deviceDescriptor->requiredFeatures[i]);
diff --git a/src/dawn/native/Instance.cpp b/src/dawn/native/Instance.cpp
index 2b51648..22b66ab 100644
--- a/src/dawn/native/Instance.cpp
+++ b/src/dawn/native/Instance.cpp
@@ -312,19 +312,29 @@
     }
 }
 
-std::vector<Ref<AdapterBase>> InstanceBase::GetAdapters() const {
-    // Set up toggles state for default adapters, currently adapter don't have a toggles
-    // descriptor so just inherit from instance toggles.
-    // TODO(dawn:1495): Handle the adapter toggles descriptor after implemented.
-    TogglesState adapterToggles = TogglesState(ToggleStage::Adapter);
+Ref<AdapterBase> InstanceBase::CreateAdapter(
+    Ref<PhysicalDeviceBase> physicalDevice,
+    FeatureLevel featureLevel,
+    const DawnTogglesDescriptor* requiredAdapterToggles) const {
+    // Set up toggles state for default adapter from given toggles descriptor and inherit from
+    // instance toggles.
+    TogglesState adapterToggles =
+        TogglesState::CreateFromTogglesDescriptor(requiredAdapterToggles, ToggleStage::Adapter);
     adapterToggles.InheritFrom(mToggles);
+    // Set up forced and default adapter toggles for selected physical device.
+    physicalDevice->SetupBackendAdapterToggles(&adapterToggles);
 
+    return AcquireRef(new AdapterBase(std::move(physicalDevice), featureLevel, adapterToggles));
+}
+
+std::vector<Ref<AdapterBase>> InstanceBase::GetAdapters() const {
     std::vector<Ref<AdapterBase>> adapters;
     for (const auto& physicalDevice : mDeprecatedPhysicalDevices) {
         for (FeatureLevel featureLevel : {FeatureLevel::Compatibility, FeatureLevel::Core}) {
             if (physicalDevice->SupportsFeatureLevel(featureLevel)) {
-                adapters.push_back(
-                    AcquireRef(new AdapterBase(physicalDevice, featureLevel, adapterToggles)));
+                // GetAdapters is deprecated, just set up default toggles state. Use
+                // EnumerateAdapters instead.
+                adapters.push_back(CreateAdapter(physicalDevice, featureLevel, nullptr));
             }
         }
     }
@@ -350,24 +360,20 @@
 std::vector<Ref<AdapterBase>> InstanceBase::EnumerateAdapters(
     const RequestAdapterOptions* options) {
     if (options == nullptr) {
-        // Default path that returns all WebGPU core adapters on the system.
+        // Default path that returns all WebGPU core adapters on the system with default toggles.
         RequestAdapterOptions defaultOptions = {};
         return EnumerateAdapters(&defaultOptions);
     }
 
-    // Set up toggles state for default adapters, currently adapter don't have a toggles
-    // descriptor so just inherit from instance toggles.
-    // TODO(dawn:1495): Handle the adapter toggles descriptor after implemented.
-    TogglesState adapterToggles = TogglesState(ToggleStage::Adapter);
-    adapterToggles.InheritFrom(mToggles);
+    const DawnTogglesDescriptor* togglesDesc = nullptr;
+    FindInChain(options->nextInChain, &togglesDesc);
 
     FeatureLevel featureLevel =
         options->compatibilityMode ? FeatureLevel::Compatibility : FeatureLevel::Core;
     std::vector<Ref<AdapterBase>> adapters;
     for (const auto& physicalDevice : EnumeratePhysicalDevices(options)) {
         ASSERT(physicalDevice->SupportsFeatureLevel(featureLevel));
-        adapters.push_back(
-            AcquireRef(new AdapterBase(physicalDevice, featureLevel, adapterToggles)));
+        adapters.push_back(CreateAdapter(physicalDevice, featureLevel, togglesDesc));
     }
     return SortAdapters(std::move(adapters), options);
 }
diff --git a/src/dawn/native/Instance.h b/src/dawn/native/Instance.h
index 52bb963..3541426 100644
--- a/src/dawn/native/Instance.h
+++ b/src/dawn/native/Instance.h
@@ -65,6 +65,8 @@
     // Deprecated: Discover physical devices and save them on the instance.
     void DiscoverDefaultPhysicalDevices();
     bool DiscoverPhysicalDevices(const PhysicalDeviceDiscoveryOptionsBase* options);
+
+    // Deprecated. Use EnumerateAdapters instead.
     // Return adapters created on physical device discovered by the instance.
     std::vector<Ref<AdapterBase>> GetAdapters() const;
 
@@ -166,6 +168,12 @@
     std::vector<Ref<PhysicalDeviceBase>> EnumeratePhysicalDevices(
         const RequestAdapterOptions* options);
 
+    // Helper function that create adapter on given physical device handling required adapter
+    // toggles descriptor.
+    Ref<AdapterBase> CreateAdapter(Ref<PhysicalDeviceBase> physicalDevice,
+                                   FeatureLevel featureLevel,
+                                   const DawnTogglesDescriptor* requiredAdapterToggles) const;
+
     void ConsumeError(std::unique_ptr<ErrorData> error);
 
     std::unordered_set<std::string> warningMessages;
diff --git a/src/dawn/native/PhysicalDevice.cpp b/src/dawn/native/PhysicalDevice.cpp
index 8a390db..fa31b7b 100644
--- a/src/dawn/native/PhysicalDevice.cpp
+++ b/src/dawn/native/PhysicalDevice.cpp
@@ -51,14 +51,6 @@
     return {};
 }
 
-bool PhysicalDeviceBase::HasFeature(wgpu::FeatureName feature) const {
-    return mSupportedFeatures.IsEnabled(feature);
-}
-
-size_t PhysicalDeviceBase::EnumerateFeatures(wgpu::FeatureName* features) const {
-    return mSupportedFeatures.EnumerateFeatures(features);
-}
-
 ResultOrError<Ref<DeviceBase>> PhysicalDeviceBase::CreateDevice(AdapterBase* adapter,
                                                                 const DeviceDescriptor* descriptor,
                                                                 const TogglesState& deviceToggles) {
@@ -110,14 +102,36 @@
     return mInstance.Get();
 }
 
-FeaturesSet PhysicalDeviceBase::GetSupportedFeatures() const {
-    return mSupportedFeatures;
+bool PhysicalDeviceBase::IsFeatureSupportedWithToggles(wgpu::FeatureName feature,
+                                                       const TogglesState& toggles) const {
+    MaybeError validateResult = ValidateFeatureSupportedWithToggles(feature, toggles);
+    if (validateResult.IsError()) {
+        validateResult.AcquireError();
+        return false;
+    } else {
+        return true;
+    }
+}
+
+FeaturesSet PhysicalDeviceBase::GetSupportedFeatures(const TogglesState& toggles) const {
+    FeaturesSet supportedFeaturesWithToggles;
+    // Iterate each PhysicalDevice's supported feature and check if it is supported with given
+    // toggles
+    for (uint32_t i : IterateBitSet(mSupportedFeatures.featuresBitSet)) {
+        Feature feature = static_cast<Feature>(i);
+        wgpu::FeatureName featureName = FeatureEnumToAPIFeature(feature);
+        if (IsFeatureSupportedWithToggles(featureName, toggles)) {
+            supportedFeaturesWithToggles.EnableFeature(feature);
+        }
+    }
+    return supportedFeaturesWithToggles;
 }
 
 bool PhysicalDeviceBase::SupportsAllRequiredFeatures(
-    const ityp::span<size_t, const wgpu::FeatureName>& features) const {
+    const ityp::span<size_t, const wgpu::FeatureName>& features,
+    const TogglesState& toggles) const {
     for (wgpu::FeatureName f : features) {
-        if (!mSupportedFeatures.IsEnabled(f)) {
+        if (!IsFeatureSupportedWithToggles(f, toggles)) {
             return false;
         }
     }
diff --git a/src/dawn/native/PhysicalDevice.h b/src/dawn/native/PhysicalDevice.h
index 9736fde..753c4c6 100644
--- a/src/dawn/native/PhysicalDevice.h
+++ b/src/dawn/native/PhysicalDevice.h
@@ -42,9 +42,6 @@
 
     MaybeError Initialize();
 
-    bool HasFeature(wgpu::FeatureName feature) const;
-    size_t EnumerateFeatures(wgpu::FeatureName* features) const;
-
     ResultOrError<Ref<DeviceBase>> CreateDevice(AdapterBase* adapter,
                                                 const DeviceDescriptor* descriptor,
                                                 const TogglesState& deviceToggles);
@@ -65,9 +62,12 @@
 
     void ResetInternalDeviceForTesting();
 
-    FeaturesSet GetSupportedFeatures() const;
-    bool SupportsAllRequiredFeatures(
-        const ityp::span<size_t, const wgpu::FeatureName>& features) const;
+    // Get all features supported by the physical device and suitable with given toggles.
+    FeaturesSet GetSupportedFeatures(const TogglesState& toggles) const;
+    // Check if all given features are supported by the physical device and suitable with given
+    // toggles.
+    bool SupportsAllRequiredFeatures(const ityp::span<size_t, const wgpu::FeatureName>& features,
+                                     const TogglesState& toggles) const;
 
     const CombinedLimits& GetLimits() const;
 
@@ -76,11 +76,11 @@
     virtual bool SupportsFeatureLevel(FeatureLevel featureLevel) const = 0;
 
     // Backend-specific force-setting and defaulting device toggles
+    virtual void SetupBackendAdapterToggles(TogglesState* adapterToggles) const = 0;
+    // Backend-specific force-setting and defaulting device toggles
     virtual void SetupBackendDeviceToggles(TogglesState* deviceToggles) const = 0;
 
     // Check if a feature os supported by this adapter AND suitable with given toggles.
-    // TODO(dawn:1495): After implementing adapter toggles, remove this and use adapter toggles
-    // instead of device toggles to validate supported features.
     MaybeError ValidateFeatureSupportedWithToggles(wgpu::FeatureName feature,
                                                    const TogglesState& toggles) const;
 
@@ -94,6 +94,10 @@
     gpu_info::DriverVersion mDriverVersion;
     std::string mDriverDescription;
 
+    // Juat a wrapper of ValidateFeatureSupportedWithToggles, return true if a feature is supported
+    // by this adapter AND suitable with given toggles.
+    bool IsFeatureSupportedWithToggles(wgpu::FeatureName feature,
+                                       const TogglesState& toggles) const;
     // Mark a feature as enabled in mSupportedFeatures.
     void EnableFeature(Feature feature);
     // Used for the tests that intend to use an adapter without all features enabled.
diff --git a/src/dawn/native/Toggles.cpp b/src/dawn/native/Toggles.cpp
index fb4f845..abb3d31 100644
--- a/src/dawn/native/Toggles.cpp
+++ b/src/dawn/native/Toggles.cpp
@@ -165,7 +165,7 @@
      {"use_dxc",
       "Use DXC instead of FXC for compiling HLSL when both dxcompiler.dll and dxil.dll is "
       "available.",
-      "https://crbug.com/dawn/402", ToggleStage::Device}},
+      "https://crbug.com/dawn/402", ToggleStage::Adapter}},
     {Toggle::DisableRobustness,
      {"disable_robustness", "Disable robust buffer access", "https://crbug.com/dawn/480",
       ToggleStage::Device}},
diff --git a/src/dawn/native/d3d11/PhysicalDeviceD3D11.cpp b/src/dawn/native/d3d11/PhysicalDeviceD3D11.cpp
index b27ee36..99109d4 100644
--- a/src/dawn/native/d3d11/PhysicalDeviceD3D11.cpp
+++ b/src/dawn/native/d3d11/PhysicalDeviceD3D11.cpp
@@ -223,13 +223,16 @@
     return {};
 }
 
+void PhysicalDevice::SetupBackendAdapterToggles(TogglesState* adpterToggles) const {
+    // D3D11 must use FXC, not DXC.
+    adpterToggles->ForceSet(Toggle::UseDXC, false);
+}
+
 void PhysicalDevice::SetupBackendDeviceToggles(TogglesState* deviceToggles) const {
     // D3D11 can only clear RTV with float values.
     deviceToggles->Default(Toggle::ApplyClearBigIntegerColorValueWithDraw, true);
     // TODO(dawn:1848): Support depth-stencil texture write.
     deviceToggles->Default(Toggle::UseBlitForBufferToStencilTextureCopy, true);
-    // D3D11 must use FXC, not DXC.
-    deviceToggles->ForceSet(Toggle::UseDXC, false);
 }
 
 ResultOrError<Ref<DeviceBase>> PhysicalDevice::CreateDeviceImpl(AdapterBase* adapter,
diff --git a/src/dawn/native/d3d11/PhysicalDeviceD3D11.h b/src/dawn/native/d3d11/PhysicalDeviceD3D11.h
index be10f59..690ac55 100644
--- a/src/dawn/native/d3d11/PhysicalDeviceD3D11.h
+++ b/src/dawn/native/d3d11/PhysicalDeviceD3D11.h
@@ -42,6 +42,7 @@
   private:
     using Base = d3d::PhysicalDevice;
 
+    void SetupBackendAdapterToggles(TogglesState* adapterToggles) const override;
     void SetupBackendDeviceToggles(TogglesState* deviceToggles) const override;
 
     ResultOrError<Ref<DeviceBase>> CreateDeviceImpl(AdapterBase* adapter,
diff --git a/src/dawn/native/d3d12/PhysicalDeviceD3D12.cpp b/src/dawn/native/d3d12/PhysicalDeviceD3D12.cpp
index eefd395..ce5c296 100644
--- a/src/dawn/native/d3d12/PhysicalDeviceD3D12.cpp
+++ b/src/dawn/native/d3d12/PhysicalDeviceD3D12.cpp
@@ -457,6 +457,14 @@
     infoQueue->PopStorageFilter();
 }
 
+void PhysicalDevice::SetupBackendAdapterToggles(TogglesState* adapterToggles) const {
+    // Check DXC for use_dxc toggle, and default to use FXC
+    if (!GetBackend()->IsDXCAvailable()) {
+        adapterToggles->ForceSet(Toggle::UseDXC, false);
+    }
+    adapterToggles->Default(Toggle::UseDXC, false);
+}
+
 void PhysicalDevice::SetupBackendDeviceToggles(TogglesState* deviceToggles) const {
     const bool useResourceHeapTier2 = (GetDeviceInfo().resourceHeapTier >= 2);
     deviceToggles->Default(Toggle::UseD3D12ResourceHeapTier2, useResourceHeapTier2);
@@ -473,14 +481,6 @@
         Toggle::D3D12UseTempBufferInDepthStencilTextureAndBufferCopyWithNonZeroBufferOffset,
         GetDeviceInfo().programmableSamplePositionsTier == 0);
 
-    // Check DXC for use_dxc toggle, and default to use FXC
-    // TODO(dawn:1495): When implementing adapter toggles, promote UseDXC as adapter toggle, and do
-    // the validation when creating adapters.
-    if (!GetBackend()->IsDXCAvailable()) {
-        deviceToggles->ForceSet(Toggle::UseDXC, false);
-    }
-    deviceToggles->Default(Toggle::UseDXC, false);
-
     // Disable optimizations when using FXC
     // See https://crbug.com/dawn/1203
     deviceToggles->Default(Toggle::FxcOptimizations, false);
diff --git a/src/dawn/native/d3d12/PhysicalDeviceD3D12.h b/src/dawn/native/d3d12/PhysicalDeviceD3D12.h
index c1348da..a60c742 100644
--- a/src/dawn/native/d3d12/PhysicalDeviceD3D12.h
+++ b/src/dawn/native/d3d12/PhysicalDeviceD3D12.h
@@ -41,6 +41,7 @@
   private:
     using Base = d3d::PhysicalDevice;
 
+    void SetupBackendAdapterToggles(TogglesState* adapterToggles) const override;
     void SetupBackendDeviceToggles(TogglesState* deviceToggles) const override;
 
     ResultOrError<Ref<DeviceBase>> CreateDeviceImpl(AdapterBase* adapter,
diff --git a/src/dawn/native/metal/BackendMTL.mm b/src/dawn/native/metal/BackendMTL.mm
index e4808d8..ddc09bf 100644
--- a/src/dawn/native/metal/BackendMTL.mm
+++ b/src/dawn/native/metal/BackendMTL.mm
@@ -269,6 +269,8 @@
         return Device::Create(adapter, mDevice, descriptor, deviceToggles);
     }
 
+    void SetupBackendAdapterToggles(TogglesState* adapterToggles) const override {}
+
     void SetupBackendDeviceToggles(TogglesState* deviceToggles) const override {
         {
             bool haveStoreAndMSAAResolve = false;
diff --git a/src/dawn/native/null/DeviceNull.cpp b/src/dawn/native/null/DeviceNull.cpp
index 1fe813a..c85dfb7 100644
--- a/src/dawn/native/null/DeviceNull.cpp
+++ b/src/dawn/native/null/DeviceNull.cpp
@@ -67,6 +67,8 @@
     return {};
 }
 
+void PhysicalDevice::SetupBackendAdapterToggles(TogglesState* adpterToggles) const {}
+
 void PhysicalDevice::SetupBackendDeviceToggles(TogglesState* deviceToggles) const {}
 
 ResultOrError<Ref<DeviceBase>> PhysicalDevice::CreateDeviceImpl(AdapterBase* adapter,
diff --git a/src/dawn/native/null/DeviceNull.h b/src/dawn/native/null/DeviceNull.h
index f7f6c4b..1800bc5 100644
--- a/src/dawn/native/null/DeviceNull.h
+++ b/src/dawn/native/null/DeviceNull.h
@@ -193,6 +193,7 @@
     MaybeError ValidateFeatureSupportedWithTogglesImpl(wgpu::FeatureName feature,
                                                        const TogglesState& toggles) const override;
 
+    void SetupBackendAdapterToggles(TogglesState* adapterToggles) const override;
     void SetupBackendDeviceToggles(TogglesState* deviceToggles) const override;
     ResultOrError<Ref<DeviceBase>> CreateDeviceImpl(AdapterBase* adapter,
                                                     const DeviceDescriptor* descriptor,
diff --git a/src/dawn/native/opengl/PhysicalDeviceGL.cpp b/src/dawn/native/opengl/PhysicalDeviceGL.cpp
index da501ae..badc5c5 100644
--- a/src/dawn/native/opengl/PhysicalDeviceGL.cpp
+++ b/src/dawn/native/opengl/PhysicalDeviceGL.cpp
@@ -226,6 +226,8 @@
     return {};
 }
 
+void PhysicalDevice::SetupBackendAdapterToggles(TogglesState* adpterToggles) const {}
+
 void PhysicalDevice::SetupBackendDeviceToggles(TogglesState* deviceToggles) const {
     const OpenGLFunctions& gl = mFunctions;
 
diff --git a/src/dawn/native/opengl/PhysicalDeviceGL.h b/src/dawn/native/opengl/PhysicalDeviceGL.h
index a28fc4f..a0b9e12 100644
--- a/src/dawn/native/opengl/PhysicalDeviceGL.h
+++ b/src/dawn/native/opengl/PhysicalDeviceGL.h
@@ -44,6 +44,7 @@
     MaybeError ValidateFeatureSupportedWithTogglesImpl(wgpu::FeatureName feature,
                                                        const TogglesState& toggles) const override;
 
+    void SetupBackendAdapterToggles(TogglesState* adapterToggles) const override;
     void SetupBackendDeviceToggles(TogglesState* deviceToggles) const override;
     ResultOrError<Ref<DeviceBase>> CreateDeviceImpl(AdapterBase* adapter,
                                                     const DeviceDescriptor* descriptor,
diff --git a/src/dawn/native/vulkan/PhysicalDeviceVk.cpp b/src/dawn/native/vulkan/PhysicalDeviceVk.cpp
index 2eaf57e..4982a48 100644
--- a/src/dawn/native/vulkan/PhysicalDeviceVk.cpp
+++ b/src/dawn/native/vulkan/PhysicalDeviceVk.cpp
@@ -462,6 +462,8 @@
     return true;
 }
 
+void PhysicalDevice::SetupBackendAdapterToggles(TogglesState* adpterToggles) const {}
+
 void PhysicalDevice::SetupBackendDeviceToggles(TogglesState* deviceToggles) const {
     // TODO(crbug.com/dawn/857): tighten this workaround when this issue is fixed in both
     // Vulkan SPEC and drivers.
diff --git a/src/dawn/native/vulkan/PhysicalDeviceVk.h b/src/dawn/native/vulkan/PhysicalDeviceVk.h
index eadd4fd..d6a0f12 100644
--- a/src/dawn/native/vulkan/PhysicalDeviceVk.h
+++ b/src/dawn/native/vulkan/PhysicalDeviceVk.h
@@ -55,6 +55,7 @@
     MaybeError ValidateFeatureSupportedWithTogglesImpl(wgpu::FeatureName feature,
                                                        const TogglesState& toggles) const override;
 
+    void SetupBackendAdapterToggles(TogglesState* adapterToggles) const override;
     void SetupBackendDeviceToggles(TogglesState* deviceToggles) const override;
     ResultOrError<Ref<DeviceBase>> CreateDeviceImpl(AdapterBase* adapter,
                                                     const DeviceDescriptor* descriptor,
diff --git a/src/dawn/tests/DawnTest.cpp b/src/dawn/tests/DawnTest.cpp
index 54f3ffd..0de3fca 100644
--- a/src/dawn/tests/DawnTest.cpp
+++ b/src/dawn/tests/DawnTest.cpp
@@ -706,7 +706,17 @@
                                       WGPURequestAdapterCallback callback, void* userdata) {
         ASSERT(gCurrentTest);
 
+        // Use the required toggles of test case when creating adapter.
+        const auto& enabledToggles = gCurrentTest->mParam.forceEnabledWorkarounds;
+        const auto& disabledToggles = gCurrentTest->mParam.forceDisabledWorkarounds;
+        wgpu::DawnTogglesDescriptor adapterToggles;
+        adapterToggles.enabledTogglesCount = enabledToggles.size();
+        adapterToggles.enabledToggles = enabledToggles.data();
+        adapterToggles.disabledTogglesCount = disabledToggles.size();
+        adapterToggles.disabledToggles = disabledToggles.data();
+
         wgpu::RequestAdapterOptions adapterOptions;
+        adapterOptions.nextInChain = &adapterToggles;
         adapterOptions.backendType = gCurrentTest->mParam.adapterProperties.backendType;
         adapterOptions.compatibilityMode = gCurrentTest->mParam.adapterProperties.compatibilityMode;
 
diff --git a/src/dawn/tests/unittests/FeatureTests.cpp b/src/dawn/tests/unittests/FeatureTests.cpp
index 1bdce4b..6d39385 100644
--- a/src/dawn/tests/unittests/FeatureTests.cpp
+++ b/src/dawn/tests/unittests/FeatureTests.cpp
@@ -30,7 +30,9 @@
           mInstanceBase(native::InstanceBase::Create()),
           mPhysicalDevice(mInstanceBase.Get()),
           mUnsafePhysicalDevice(mInstanceBase.Get()),
-          mAdapterBase(&mPhysicalDevice, native::FeatureLevel::Core),
+          mAdapterBase(&mPhysicalDevice,
+                       native::FeatureLevel::Core,
+                       native::TogglesState(native::ToggleStage::Adapter)),
           mUnsafeAdapterBase(&mUnsafePhysicalDevice,
                              native::FeatureLevel::Core,
                              native::TogglesState(native::ToggleStage::Adapter)
diff --git a/src/dawn/tests/unittests/GetProcAddressTests.cpp b/src/dawn/tests/unittests/GetProcAddressTests.cpp
index 8b83137..522269d 100644
--- a/src/dawn/tests/unittests/GetProcAddressTests.cpp
+++ b/src/dawn/tests/unittests/GetProcAddressTests.cpp
@@ -58,7 +58,8 @@
         : testing::TestWithParam<DawnFlavor>(),
           mNativeInstance(native::InstanceBase::Create()),
           mAdapterBase(AcquireRef(new native::null::PhysicalDevice(mNativeInstance.Get())),
-                       native::FeatureLevel::Core) {}
+                       native::FeatureLevel::Core,
+                       native::TogglesState(native::ToggleStage::Adapter)) {}
 
     void SetUp() override {
         switch (GetParam()) {
diff --git a/src/dawn/tests/unittests/PerThreadProcTests.cpp b/src/dawn/tests/unittests/PerThreadProcTests.cpp
index bf318c1..bd33879 100644
--- a/src/dawn/tests/unittests/PerThreadProcTests.cpp
+++ b/src/dawn/tests/unittests/PerThreadProcTests.cpp
@@ -31,7 +31,8 @@
     PerThreadProcTests()
         : mNativeInstance(native::InstanceBase::Create()),
           mAdapterBase(AcquireRef(new native::null::PhysicalDevice(mNativeInstance.Get())),
-                       native::FeatureLevel::Core) {}
+                       native::FeatureLevel::Core,
+                       native::TogglesState(native::ToggleStage::Adapter)) {}
     ~PerThreadProcTests() override = default;
 
   protected:
diff --git a/src/dawn/tests/unittests/ToggleTests.cpp b/src/dawn/tests/unittests/ToggleTests.cpp
index 014538d..c87deea 100644
--- a/src/dawn/tests/unittests/ToggleTests.cpp
+++ b/src/dawn/tests/unittests/ToggleTests.cpp
@@ -36,13 +36,35 @@
 using testing::SaveArg;
 using testing::StrEq;
 
-class InstanceToggleTest : public testing::Test {
+class ToggleTest : public testing::Test {
+  public:
+    // Helper function for getting the null adapter with given toggles.
+    native::Adapter CreateNullAdapter(native::Instance* instance,
+                                      const wgpu::DawnTogglesDescriptor* toggles) {
+        wgpu::RequestAdapterOptions options;
+        options.backendType = wgpu::BackendType::Null;
+        options.nextInChain = toggles;
+
+        // Enumerate null adapter, should have one result.
+        auto adapters = instance->EnumerateAdapters(&options);
+        EXPECT_EQ(adapters.size(), 1u);
+        // Pick the returned null adapter.
+        native::Adapter nullAdapter = adapters[0];
+        EXPECT_NE(nullAdapter.Get(), nullptr);
+        EXPECT_EQ(native::FromAPI(nullAdapter.Get())->GetPhysicalDevice()->GetBackendType(),
+                  wgpu::BackendType::Null);
+
+        return nullAdapter;
+    }
+
   protected:
     void SetUp() override { dawnProcSetProcs(&native::GetProcs()); }
 
     void TearDown() override { dawnProcSetProcs(nullptr); }
 };
 
+using InstanceToggleTest = ToggleTest;
+
 // Test that instance toggles are set by requirement or default as expected.
 TEST_F(InstanceToggleTest, InstanceTogglesSet) {
     auto validateInstanceToggles = [](const native::Instance* nativeInstance,
@@ -131,11 +153,9 @@
         native::InstanceBase* instance = native::FromAPI(nativeInstance->Get());
         const native::TogglesState& instanceTogglesState = instance->GetTogglesState();
 
-        native::RequestAdapterOptions options = {};
-        options.backendType = wgpu::BackendType::Null;
-
         // Get the null adapter with default toggles.
-        Ref<native::AdapterBase> nullAdapter = instance->EnumerateAdapters(&options)[0];
+        Ref<native::AdapterBase> nullAdapter =
+            native::FromAPI(CreateNullAdapter(nativeInstance, nullptr).Get());
 
         auto& adapterTogglesState = nullAdapter->GetTogglesState();
 
@@ -196,5 +216,428 @@
     }
 }
 
+using AdapterToggleTest = ToggleTest;
+
+// Test that adapter toggles are set and/or overridden by requirement or default as expected, and
+// get inherited to devices it creates.
+TEST_F(AdapterToggleTest, AdapterTogglesSetAndInheritToDevice) {
+    // Create an instance with default toggles, where AllowUnsafeAPIs is disabled.
+    std::unique_ptr<native::Instance> instance;
+    instance = std::make_unique<native::Instance>();
+    // AllowUnsafeAPIs should be disabled by default.
+    native::InstanceBase* instanceBase = native::FromAPI(instance->Get());
+    ASSERT_FALSE(instanceBase->GetTogglesState().IsEnabled(native::Toggle::AllowUnsafeAPIs));
+
+    // Validate an adapter has expected toggles state.
+    auto ValidateAdapterToggles = [](const native::AdapterBase* adapterBase,
+                                     std::initializer_list<const char*> enableToggles,
+                                     std::initializer_list<const char*> disableToggles) {
+        const native::TogglesState& adapterTogglesState = adapterBase->GetTogglesState();
+        std::vector<const char*> enabledToggles = adapterTogglesState.GetEnabledToggleNames();
+        std::vector<const char*> disabledToggles = adapterTogglesState.GetDisabledToggleNames();
+        EXPECT_EQ(disabledToggles.size(), disableToggles.size());
+        EXPECT_EQ(enabledToggles.size(), enableToggles.size());
+        for (auto* enableToggle : enableToggles) {
+            EXPECT_THAT(enabledToggles, Contains(StrEq(enableToggle)));
+        }
+        for (auto* disableToggle : disableToggles) {
+            EXPECT_THAT(disabledToggles, Contains(StrEq(disableToggle)));
+        }
+    };
+
+    // Validate an adapter's toggles get inherited to the device it creates.
+    auto ValidateAdapterTogglesInheritedToDevice = [](native::AdapterBase* adapter) {
+        auto& adapterTogglesState = adapter->GetTogglesState();
+
+        // Creater a default device from the adapter.
+        Ref<native::DeviceBase> device = AcquireRef(adapter->APICreateDevice());
+
+        // Check adapter toggles are inherited by the device.
+        native::TogglesInfo togglesInfo;
+        static_assert(std::is_same_v<std::underlying_type_t<native::Toggle>, int>);
+        for (int i = 0; i < static_cast<int>(native::Toggle::EnumCount); i++) {
+            native::Toggle toggle = static_cast<native::Toggle>(i);
+            if (togglesInfo.GetToggleInfo(toggle)->stage > native::ToggleStage::Adapter) {
+                continue;
+            }
+            EXPECT_EQ(adapterTogglesState.IsEnabled(toggle), device->IsToggleEnabled(toggle));
+        }
+    };
+
+    // Do the test by creating an adapter with given toggles descriptor and validate its toggles
+    // state is as expected and get inherited to devices.
+    auto CreateAdapterAndValidateToggles =
+        [this, &instance, ValidateAdapterToggles, ValidateAdapterTogglesInheritedToDevice](
+            const wgpu::DawnTogglesDescriptor* requiredAdapterToggles,
+            std::initializer_list<const char*> expectedEnabledToggles,
+            std::initializer_list<const char*> expectedDisabledToggles) {
+            native::Adapter adapter = CreateNullAdapter(instance.get(), requiredAdapterToggles);
+            ValidateAdapterToggles(native::FromAPI(adapter.Get()), expectedEnabledToggles,
+                                   expectedDisabledToggles);
+            ValidateAdapterTogglesInheritedToDevice(native::FromAPI(adapter.Get()));
+        };
+
+    const char* allowUnsafeApisToggle = "allow_unsafe_apis";
+    const char* useDXCToggle = "use_dxc";
+
+    // Create adapter with no toggles descriptor
+    {
+        // The created adapter should inherit disabled AllowUnsafeAPIs toggle from instance.
+        CreateAdapterAndValidateToggles(nullptr, {}, {allowUnsafeApisToggle});
+    }
+
+    // Create adapter with empty toggles descriptor
+    {
+        wgpu::DawnTogglesDescriptor adapterTogglesDesc = {};
+
+        // The created adapter should inherit disabled AllowUnsafeAPIs toggle from instance.
+        CreateAdapterAndValidateToggles(&adapterTogglesDesc, {}, {allowUnsafeApisToggle});
+    }
+
+    // Create adapter with UseDXC enabled in toggles descriptor
+    {
+        wgpu::DawnTogglesDescriptor adapterTogglesDesc = {};
+        adapterTogglesDesc.enabledTogglesCount = 1;
+        adapterTogglesDesc.enabledToggles = &useDXCToggle;
+
+        // The created adapter should enable required UseDXC toggle and inherit disabled
+        // AllowUnsafeAPIs toggle from instance.
+        CreateAdapterAndValidateToggles(&adapterTogglesDesc, {useDXCToggle},
+                                        {allowUnsafeApisToggle});
+    }
+
+    // Create adapter with explicitly overriding AllowUnsafeAPIs in toggles descriptor
+    {
+        wgpu::DawnTogglesDescriptor adapterTogglesDesc = {};
+        adapterTogglesDesc.enabledTogglesCount = 1;
+        adapterTogglesDesc.enabledToggles = &allowUnsafeApisToggle;
+
+        // The created adapter should enable overridden AllowUnsafeAPIs toggle.
+        CreateAdapterAndValidateToggles(&adapterTogglesDesc, {allowUnsafeApisToggle}, {});
+    }
+
+    // Create adapter with UseDXC enabled and explicitly overriding AllowUnsafeAPIs in toggles
+    // descriptor
+    {
+        std::vector<const char*> enableAdapterToggles = {useDXCToggle, allowUnsafeApisToggle};
+        wgpu::DawnTogglesDescriptor adapterTogglesDesc = {};
+        adapterTogglesDesc.enabledTogglesCount = enableAdapterToggles.size();
+        adapterTogglesDesc.enabledToggles = enableAdapterToggles.data();
+
+        // The created adapter should enable required UseDXC and overridden AllowUnsafeAPIs toggle.
+        CreateAdapterAndValidateToggles(&adapterTogglesDesc, {useDXCToggle, allowUnsafeApisToggle},
+                                        {});
+    }
+}
+
+class DeviceToggleTest : public ToggleTest {
+  public:
+    // Create a device with given toggles descriptor from the given adapter, and validate its
+    // toggles state.
+    void CreateDeviceAndValidateToggles(
+        native::AdapterBase* adapter,
+        const wgpu::DawnTogglesDescriptor* requiredDeviceToggles,
+        std::initializer_list<const char*> expectedEnabledToggles,
+        std::initializer_list<const char*> expectedDisabledToggles) {
+        native::DeviceDescriptor desc{};
+        desc.nextInChain = requiredDeviceToggles;
+
+        // Creater a device with given toggles descriptor from the adapter.
+        Ref<native::DeviceBase> device = AcquireRef(adapter->APICreateDevice(&desc));
+
+        // Check device toggles state is as expected.
+        native::TogglesInfo togglesInfo;
+        auto deviceEnabledToggles = device->GetTogglesUsed();
+        for (auto* enableToggle : expectedEnabledToggles) {
+            EXPECT_THAT(deviceEnabledToggles, Contains(StrEq(enableToggle)));
+            native::Toggle toggle = togglesInfo.ToggleNameToEnum(enableToggle);
+            ASSERT(toggle != native::Toggle::InvalidEnum);
+            EXPECT_TRUE(device->IsToggleEnabled(toggle));
+        }
+        for (auto* enableToggle : expectedDisabledToggles) {
+            EXPECT_THAT(deviceEnabledToggles, Not(Contains(StrEq(enableToggle))));
+            native::Toggle toggle = togglesInfo.ToggleNameToEnum(enableToggle);
+            ASSERT(toggle != native::Toggle::InvalidEnum);
+            EXPECT_FALSE(device->IsToggleEnabled(toggle));
+        }
+    }
+};
+
+// Test that device toggles are set by requirement or default as expected.
+TEST_F(DeviceToggleTest, DeviceSetToggles) {
+    // Create an instance with default toggles.
+    std::unique_ptr<native::Instance> instance;
+    instance = std::make_unique<native::Instance>();
+
+    // Create a null adapter from the instance.
+    native::Adapter nullAdapter = CreateNullAdapter(instance.get(), nullptr);
+    Ref<native::AdapterBase> adapter = native::FromAPI(nullAdapter.Get());
+
+    // DumpShader is a device toggle.
+    const char* dumpShaderToggle = "dump_shaders";
+
+    // Create device with no toggles descriptor.
+    {
+        // DumpShader toggles is not set and treated as disabled in device.
+        CreateDeviceAndValidateToggles(adapter.Get(), nullptr, {}, {dumpShaderToggle});
+    }
+
+    // Create device with a device toggle required enabled. This should always work.
+    {
+        wgpu::DawnTogglesDescriptor deviceTogglesDesc = {};
+        deviceTogglesDesc.enabledTogglesCount = 1;
+        deviceTogglesDesc.enabledToggles = &dumpShaderToggle;
+
+        // The device created from all adapter should have DumpShader device toggle enabled.
+        CreateDeviceAndValidateToggles(adapter.Get(), &deviceTogglesDesc, {dumpShaderToggle}, {});
+    }
+
+    // Create device with a device toggle required disabled. This should always work.
+    {
+        wgpu::DawnTogglesDescriptor deviceTogglesDesc = {};
+        deviceTogglesDesc.disabledTogglesCount = 1;
+        deviceTogglesDesc.disabledToggles = &dumpShaderToggle;
+
+        // The device created from all adapter should have DumpShader device toggle enabled.
+        CreateDeviceAndValidateToggles(adapter.Get(), &deviceTogglesDesc, {}, {dumpShaderToggle});
+    }
+}
+
+// Test that device can override non-forced instance toggles by requirement as expected.
+TEST_F(DeviceToggleTest, DeviceOverridingInstanceToggle) {
+    // Create an instance with default toggles, where AllowUnsafeAPIs is disabled.
+    std::unique_ptr<native::Instance> instance;
+    instance = std::make_unique<native::Instance>();
+    // AllowUnsafeAPIs should be disabled by default.
+    native::InstanceBase* instanceBase = native::FromAPI(instance->Get());
+    ASSERT_FALSE(instanceBase->GetTogglesState().IsEnabled(native::Toggle::AllowUnsafeAPIs));
+
+    // Create a null adapter from the instance. AllowUnsafeAPIs should be inherited disabled.
+    native::Adapter nullAdapter = CreateNullAdapter(instance.get(), nullptr);
+    Ref<native::AdapterBase> adapter = native::FromAPI(nullAdapter.Get());
+
+    native::PhysicalDeviceBase* nullPhysicalDevice = adapter->GetPhysicalDevice();
+    native::FeatureLevel featureLevel = adapter->GetFeatureLevel();
+
+    // Create null adapters with the AllowUnsafeAPIs toggle set/forced to enabled/disabled, using
+    // the same physical device and feature level as the known null adapter.
+    auto CreateAdapterWithAllowUnsafeAPIsToggle = [&adapter, nullPhysicalDevice, featureLevel](
+                                                      bool isAllowUnsafeAPIsEnabled,
+                                                      bool isAllowUnsafeAPIsForced) {
+        native::TogglesState adapterTogglesState = adapter->GetTogglesState();
+        adapterTogglesState.SetForTesting(native::Toggle::AllowUnsafeAPIs, isAllowUnsafeAPIsEnabled,
+                                          isAllowUnsafeAPIsForced);
+
+        Ref<native::AdapterBase> resultAdapter;
+        resultAdapter = AcquireRef<native::AdapterBase>(
+            new native::AdapterBase(nullPhysicalDevice, featureLevel, adapterTogglesState));
+
+        // AllowUnsafeAPIs should be set as expected.
+        EXPECT_TRUE(resultAdapter->GetTogglesState().IsSet(native::Toggle::AllowUnsafeAPIs));
+        EXPECT_EQ(resultAdapter->GetTogglesState().IsEnabled(native::Toggle::AllowUnsafeAPIs),
+                  isAllowUnsafeAPIsEnabled);
+
+        return resultAdapter;
+    };
+
+    Ref<native::AdapterBase> adapterEnableAllowUnsafeAPIs =
+        CreateAdapterWithAllowUnsafeAPIsToggle(true, false);
+    Ref<native::AdapterBase> adapterDisableAllowUnsafeAPIs =
+        CreateAdapterWithAllowUnsafeAPIsToggle(false, false);
+    Ref<native::AdapterBase> adapterForcedEnableAllowUnsafeAPIs =
+        CreateAdapterWithAllowUnsafeAPIsToggle(true, true);
+    Ref<native::AdapterBase> adapterForcedDisableAllowUnsafeAPIs =
+        CreateAdapterWithAllowUnsafeAPIsToggle(false, true);
+
+    // AllowUnsafeAPIs is an instance toggle, and can be overridden by device.
+    const char* allowUnsafeApisToggle = "allow_unsafe_apis";
+
+    // Create device with no toggles descriptor will inherite the adapter toggle.
+    {
+        // The device created from default adapter should inherit disabled AllowUnsafeAPIs toggle
+        // from adapter.
+        CreateDeviceAndValidateToggles(adapter.Get(), nullptr, {}, {allowUnsafeApisToggle});
+        // The device created from AllowUnsafeAPIs enabled/disabled adapter should inherit it.
+        CreateDeviceAndValidateToggles(adapterEnableAllowUnsafeAPIs.Get(), nullptr,
+                                       {allowUnsafeApisToggle}, {});
+        CreateDeviceAndValidateToggles(adapterDisableAllowUnsafeAPIs.Get(), nullptr, {},
+                                       {allowUnsafeApisToggle});
+        // The device created from AllowUnsafeAPIs forced adapter should inherit forced
+        // enabled/disabled toggle.
+        CreateDeviceAndValidateToggles(adapterForcedEnableAllowUnsafeAPIs.Get(), nullptr,
+                                       {allowUnsafeApisToggle}, {});
+        CreateDeviceAndValidateToggles(adapterForcedDisableAllowUnsafeAPIs.Get(), nullptr, {},
+                                       {allowUnsafeApisToggle});
+    }
+
+    // Create device trying to override instance toggle to enable. This should work as long as the
+    // toggle is not forced.
+    {
+        wgpu::DawnTogglesDescriptor deviceTogglesDesc = {};
+        deviceTogglesDesc.enabledTogglesCount = 1;
+        deviceTogglesDesc.enabledToggles = &allowUnsafeApisToggle;
+
+        // The device created from default adapter should have AllowUnsafeAPIs device toggle
+        // enabled.
+        CreateDeviceAndValidateToggles(adapter.Get(), &deviceTogglesDesc, {allowUnsafeApisToggle},
+                                       {});
+        // The device created from UseDXC enabled/disabled adapter should have AllowUnsafeAPIs
+        // device toggle overridden to enabled.
+        CreateDeviceAndValidateToggles(adapterEnableAllowUnsafeAPIs.Get(), &deviceTogglesDesc,
+                                       {allowUnsafeApisToggle}, {});
+        CreateDeviceAndValidateToggles(adapterDisableAllowUnsafeAPIs.Get(), &deviceTogglesDesc,
+                                       {allowUnsafeApisToggle}, {});
+        // The device created from UseAllowUnsafeAPIs forced enabled adapter should have
+        // AllowUnsafeAPIs device toggle enabled.
+        CreateDeviceAndValidateToggles(adapterForcedEnableAllowUnsafeAPIs.Get(), &deviceTogglesDesc,
+                                       {allowUnsafeApisToggle}, {});
+        // The device created from AllowUnsafeAPIs forced disabled adapter should have
+        // AllowUnsafeAPIs device toggle disabled, since it can not override the forced toggle.
+        CreateDeviceAndValidateToggles(adapterForcedDisableAllowUnsafeAPIs.Get(),
+                                       &deviceTogglesDesc, {}, {allowUnsafeApisToggle});
+    }
+
+    // Create device trying to override instance toggle to disable. This should work as long as the
+    // toggle is not forced.
+    {
+        wgpu::DawnTogglesDescriptor deviceTogglesDesc = {};
+        deviceTogglesDesc.disabledTogglesCount = 1;
+        deviceTogglesDesc.disabledToggles = &allowUnsafeApisToggle;
+
+        // The device created from default adapter should have UseDXC device toggle enabled.
+        CreateDeviceAndValidateToggles(adapter.Get(), &deviceTogglesDesc, {},
+                                       {allowUnsafeApisToggle});
+        // The device created from UseDXC enabled/disabled adapter should have UseDXC device toggle
+        // overridden to disabled.
+        CreateDeviceAndValidateToggles(adapterEnableAllowUnsafeAPIs.Get(), &deviceTogglesDesc, {},
+                                       {allowUnsafeApisToggle});
+        CreateDeviceAndValidateToggles(adapterDisableAllowUnsafeAPIs.Get(), &deviceTogglesDesc, {},
+                                       {allowUnsafeApisToggle});
+        // The device created from UseDXC forced enabled adapter should have UseDXC device toggle
+        // enabled, since it can not override the forced toggle.
+        CreateDeviceAndValidateToggles(adapterForcedEnableAllowUnsafeAPIs.Get(), &deviceTogglesDesc,
+                                       {allowUnsafeApisToggle}, {});
+        // The device created from UseDXC forced disabled adapter should have UseDXC device toggle
+        // disabled.
+        CreateDeviceAndValidateToggles(adapterForcedDisableAllowUnsafeAPIs.Get(),
+                                       &deviceTogglesDesc, {}, {allowUnsafeApisToggle});
+    }
+}
+
+// Test that device can override non-forced adapter toggles by requirement as expected.
+TEST_F(DeviceToggleTest, DeviceOverridingAdapterToggle) {
+    // Create an instance with default toggles, where AllowUnsafeAPIs is disabled.
+    std::unique_ptr<native::Instance> instance;
+    instance = std::make_unique<native::Instance>();
+    // AllowUnsafeAPIs should be disabled by default.
+    native::InstanceBase* instanceBase = native::FromAPI(instance->Get());
+    ASSERT_FALSE(instanceBase->GetTogglesState().IsEnabled(native::Toggle::AllowUnsafeAPIs));
+
+    // Create a null adapter from the instance. AllowUnsafeAPIs should be inherited disabled.
+    native::Adapter nullAdapter = CreateNullAdapter(instance.get(), nullptr);
+    Ref<native::AdapterBase> adapter = native::FromAPI(nullAdapter.Get());
+    // The null adapter will not set or force-set the UseDXC toggle by default.
+    ASSERT_FALSE(adapter->GetTogglesState().IsSet(native::Toggle::UseDXC));
+
+    native::PhysicalDeviceBase* nullPhysicalDevice = adapter->GetPhysicalDevice();
+    native::FeatureLevel featureLevel = adapter->GetFeatureLevel();
+
+    // Create null adapters with the UseDXC toggle set/forced to enabled/disabled, using the same
+    // physical device and feature level as the known null adapter.
+    auto CreateAdapterWithDXCToggle = [&adapter, nullPhysicalDevice, featureLevel](
+                                          bool isUseDXCEnabled, bool isUseDXCForced) {
+        native::TogglesState adapterTogglesState = adapter->GetTogglesState();
+        adapterTogglesState.SetForTesting(native::Toggle::UseDXC, isUseDXCEnabled, isUseDXCForced);
+
+        Ref<native::AdapterBase> resultAdapter;
+        resultAdapter = AcquireRef<native::AdapterBase>(
+            new native::AdapterBase(nullPhysicalDevice, featureLevel, adapterTogglesState));
+
+        // AllowUnsafeAPIs should be inherited disabled by default.
+        EXPECT_TRUE(resultAdapter->GetTogglesState().IsSet(native::Toggle::AllowUnsafeAPIs));
+        EXPECT_FALSE(resultAdapter->GetTogglesState().IsEnabled(native::Toggle::AllowUnsafeAPIs));
+
+        // The adapter should have UseDXC toggle set to given state.
+        EXPECT_TRUE(resultAdapter->GetTogglesState().IsSet(native::Toggle::UseDXC));
+        EXPECT_EQ(resultAdapter->GetTogglesState().IsEnabled(native::Toggle::UseDXC),
+                  isUseDXCEnabled);
+
+        return resultAdapter;
+    };
+
+    Ref<native::AdapterBase> adapterEnableDXC = CreateAdapterWithDXCToggle(true, false);
+    Ref<native::AdapterBase> adapterDisableDXC = CreateAdapterWithDXCToggle(false, false);
+    Ref<native::AdapterBase> adapterForcedEnableDXC = CreateAdapterWithDXCToggle(true, true);
+    Ref<native::AdapterBase> adapterForcedDisableDXC = CreateAdapterWithDXCToggle(false, true);
+
+    // UseDXC is an adapter toggle, and can be overridden by device.
+    const char* useDXCToggle = "use_dxc";
+
+    // Create device with no toggles descriptor.
+    {
+        // The device created from default adapter should inherit enabled/disabled toggles from
+        // adapter. All other toggles that are not set are also treated as disabled in device.
+        CreateDeviceAndValidateToggles(adapter.Get(), nullptr, {}, {useDXCToggle});
+        // The device created from UseDXC enabled/disabled adapter should inherit forced
+        // enabled/disabled UseDXC toggle.
+        CreateDeviceAndValidateToggles(adapterEnableDXC.Get(), nullptr, {useDXCToggle}, {});
+        CreateDeviceAndValidateToggles(adapterDisableDXC.Get(), nullptr, {}, {useDXCToggle});
+        // The device created from UseDXC forced adapter should inherit forced enabled/disabled
+        // UseDXC toggle.
+        CreateDeviceAndValidateToggles(adapterForcedEnableDXC.Get(), nullptr, {useDXCToggle}, {});
+        CreateDeviceAndValidateToggles(adapterForcedDisableDXC.Get(), nullptr, {}, {useDXCToggle});
+    }
+
+    // Create device trying to override adapter toggle to enable. This should work as long as the
+    // toggle is not forced.
+    {
+        wgpu::DawnTogglesDescriptor deviceTogglesDesc = {};
+        deviceTogglesDesc.enabledTogglesCount = 1;
+        deviceTogglesDesc.enabledToggles = &useDXCToggle;
+
+        // The device created from default adapter should have UseDXC device toggle enabled.
+        CreateDeviceAndValidateToggles(adapter.Get(), &deviceTogglesDesc, {useDXCToggle}, {});
+        // The device created from UseDXC enabled/disabled adapter should have UseDXC device toggle
+        // overridden to enabled.
+        CreateDeviceAndValidateToggles(adapterEnableDXC.Get(), &deviceTogglesDesc, {useDXCToggle},
+                                       {});
+        CreateDeviceAndValidateToggles(adapterDisableDXC.Get(), &deviceTogglesDesc, {useDXCToggle},
+                                       {});
+        // The device created from UseDXC forced enabled adapter should have UseDXC device toggle
+        // enabled.
+        CreateDeviceAndValidateToggles(adapterForcedEnableDXC.Get(), &deviceTogglesDesc,
+                                       {useDXCToggle}, {});
+        // The device created from UseDXC forced disabled adapter should have UseDXC device toggle
+        // disabled, since it can not override the forced toggle.
+        CreateDeviceAndValidateToggles(adapterForcedDisableDXC.Get(), &deviceTogglesDesc, {},
+                                       {useDXCToggle});
+    }
+
+    // Create device trying to override adapter toggle to disable. This should work as long as the
+    // toggle is not forced.
+    {
+        wgpu::DawnTogglesDescriptor deviceTogglesDesc = {};
+        deviceTogglesDesc.disabledTogglesCount = 1;
+        deviceTogglesDesc.disabledToggles = &useDXCToggle;
+
+        // The device created from default adapter should have UseDXC device toggle enabled.
+        CreateDeviceAndValidateToggles(adapter.Get(), &deviceTogglesDesc, {}, {useDXCToggle});
+        // The device created from UseDXC enabled/disabled adapter should have UseDXC device toggle
+        // overridden to disabled.
+        CreateDeviceAndValidateToggles(adapterEnableDXC.Get(), &deviceTogglesDesc, {},
+                                       {useDXCToggle});
+        CreateDeviceAndValidateToggles(adapterDisableDXC.Get(), &deviceTogglesDesc, {},
+                                       {useDXCToggle});
+        // The device created from UseDXC forced enabled adapter should have UseDXC device toggle
+        // enabled, since it can not override the forced toggle.
+        CreateDeviceAndValidateToggles(adapterForcedEnableDXC.Get(), &deviceTogglesDesc,
+                                       {useDXCToggle}, {});
+        // The device created from UseDXC forced disabled adapter should have UseDXC device toggle
+        // disabled.
+        CreateDeviceAndValidateToggles(adapterForcedDisableDXC.Get(), &deviceTogglesDesc, {},
+                                       {useDXCToggle});
+    }
+}
+
 }  // anonymous namespace
 }  // namespace dawn