Implement upstream RequestDevice, add native-only CreateDevice

This CL implements RequestDevice and also has changes for
Dawn to internally use wgpu::FeatureName enums, instead of
strings. Some of the string handling is kept for now to
support the deprecated creation path. GetFeatureInfo is added
to the instance to get a name and description of the feature,
for reporting in about://gpu.

Dawn device toggles are now passed in an extension struct off
of the device descriptor. This is only supported in dawn_native,
and not dawn_wire, for now, since dawn_wire doesn't have a way
to serialize lists of null-terminated const char*.

To enable the client to check whether the toggle descriptor is
supported, a `dawn-native` feature is added which is supported
all the time with dawn_native, but not supported with dawn_wire.

Feature `dawn-native` also enables a synchronous version of
CreateDevice for convenience.

Bug: dawn:160
Change-Id: Ifc195e7ea808c6c319021528ef4b36bd65583bff
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/72020
Reviewed-by: Loko Kung <lokokung@google.com>
Commit-Queue: Austin Eng <enga@chromium.org>
diff --git a/dawn.json b/dawn.json
index a575dcb..6e9882b 100644
--- a/dawn.json
+++ b/dawn.json
@@ -113,6 +113,14 @@
                     {"name": "callback", "type": "request device callback"},
                     {"name": "userdata", "type": "void", "annotation": "*"}
                 ]
+            },
+            {
+                "name": "create device",
+                "tags": ["dawn"],
+                "returns": "device",
+                "args": [
+                    {"name": "descriptor", "type": "device descriptor", "annotation": "const*", "optional": "true"}
+                ]
             }
         ]
     },
@@ -148,6 +156,17 @@
             {"name": "required limits", "type": "required limits", "annotation": "const*", "optional": true}
         ]
     },
+    "dawn toggles device descriptor": {
+        "tags": ["dawn", "native"],
+        "category": "structure",
+        "chained": "in",
+        "members": [
+            {"name": "force enabled toggles count", "type": "uint32_t", "default": 0},
+            {"name": "force enabled toggles", "type": "char", "annotation": "const*const*", "length": "force enabled toggles count"},
+            {"name": "force disabled toggles count", "type": "uint32_t", "default": 0},
+            {"name": "force disabled toggles", "type": "char", "annotation": "const*const*", "length": "force disabled toggles count"}
+        ]
+    },
     "address mode": {
         "category": "enum",
         "values": [
@@ -1164,6 +1183,7 @@
             {"name": "depth32 float stencil8", "type": "bool", "default": "false"},
             {"name": "invalid feature", "type": "bool", "default": "false"},
             {"name": "dawn internal usages", "type": "bool", "default": "false"},
+            {"name": "dawn native", "type": "bool", "default": "false"},
             {"name": "limits", "type": "supported limits"}
         ]
     },
@@ -1313,7 +1333,8 @@
             {"value": 1000, "name": "depth clamping", "tags": ["emscripten", "dawn"]},
             {"value": 1001, "name": "dawn shader float 16", "tags": ["dawn"]},
             {"value": 1002, "name": "dawn internal usages", "tags": ["dawn"]},
-            {"value": 1003, "name": "dawn multi planar formats", "tags": ["dawn"]}
+            {"value": 1003, "name": "dawn multi planar formats", "tags": ["dawn"]},
+            {"value": 1004, "name": "dawn native", "tags": ["dawn", "native"]}
         ]
     },
     "filter mode": {
@@ -2347,7 +2368,8 @@
             {"value": 10, "name": "external texture binding layout", "tags": ["dawn"]},
             {"value": 11, "name": "surface descriptor from windows swap chain panel", "tags": ["dawn"]},
             {"value": 1000, "name": "dawn texture internal usage descriptor", "tags": ["dawn"]},
-            {"value": 1001, "name": "primitive depth clamping state", "tags": ["dawn", "emscripten"]}
+            {"value": 1001, "name": "primitive depth clamping state", "tags": ["dawn", "emscripten"]},
+            {"value": 1002, "name": "dawn toggles device descriptor", "tags": ["dawn", "native"]}
         ]
     },
     "texture": {
diff --git a/dawn_wire.json b/dawn_wire.json
index 497a0eb..869f74b 100644
--- a/dawn_wire.json
+++ b/dawn_wire.json
@@ -179,6 +179,7 @@
             "SurfaceDescriptorFromWindowsSwapChainPanel"
         ],
         "client_side_commands": [
+            "AdapterCreateDevice",
             "AdapterGetProperties",
             "AdapterGetLimits",
             "AdapterHasFeature",
diff --git a/docs/features/dawn_native.md b/docs/features/dawn_native.md
new file mode 100644
index 0000000..c1e212d
--- /dev/null
+++ b/docs/features/dawn_native.md
@@ -0,0 +1,13 @@
+# Dawn Native
+
+The `dawn-native` feature enables additional functionality that is supported only
+when the WebGPU implementation is `dawn_native`.
+
+Additional functionality:
+ - `wgpu::DawnTogglesDeviceDescriptor` may be chained on `wgpu::DeviceDescriptor` on device creation to enable Dawn-specific toggles on the device.
+
+ - Synchronous `adapter.CreateDevice(const wgpu::DeviceDescriptor*)` may be called.
+
+Notes:
+ - Enabling this feature in the `wgpu::DeviceDescriptor` does nothing, but
+its presence in the Adapter's set of supported features means that the additional functionality is supported.
diff --git a/generator/dawn_json_generator.py b/generator/dawn_json_generator.py
index 5c17d77..fa8a1ee 100644
--- a/generator/dawn_json_generator.py
+++ b/generator/dawn_json_generator.py
@@ -405,8 +405,10 @@
     return result
 
 
-def parse_json(json, enabled_tags):
-    is_enabled = lambda json_data: item_is_enabled(enabled_tags, json_data)
+def parse_json(json, enabled_tags, disabled_tags=None):
+    is_enabled = lambda json_data: item_is_enabled(
+        enabled_tags, json_data) and not item_is_disabled(
+            disabled_tags, json_data)
     category_to_parser = {
         'bitmask': BitmaskType,
         'enum': EnumType,
@@ -426,7 +428,7 @@
         by_category[name] = []
 
     for (name, json_data) in json.items():
-        if name[0] == '_' or not item_is_enabled(enabled_tags, json_data):
+        if name[0] == '_' or not is_enabled(json_data):
             continue
         category = json_data['category']
         parsed = category_to_parser[category](is_enabled, name, json_data)
@@ -464,12 +466,14 @@
         'types': types,
         'by_category': by_category,
         'enabled_tags': enabled_tags,
+        'disabled_tags': disabled_tags,
     }
     return {
         'metadata': Metadata(json['_metadata']),
         'types': types,
         'by_category': by_category,
         'enabled_tags': enabled_tags,
+        'disabled_tags': disabled_tags,
         'c_methods': lambda typ: c_methods(api_params, typ),
         'c_methods_sorted_by_name': get_c_methods_sorted_by_name(api_params),
     }
@@ -617,6 +621,8 @@
         return typ + ' * ' + name
     elif arg.annotation == 'const*':
         return typ + ' const * ' + name
+    elif arg.annotation == 'const*const*':
+        return 'const ' + typ + '* const * ' + name
     else:
         assert False
 
@@ -632,6 +638,14 @@
     return any(tag in enabled_tags for tag in tags)
 
 
+def item_is_disabled(disabled_tags, json_data):
+    if disabled_tags is None: return False
+    tags = json_data.get('tags')
+    if tags is None: return False
+
+    return any(tag in disabled_tags for tag in tags)
+
+
 def as_cppEnum(value_name):
     assert not value_name.native
     if value_name.concatcase()[0].isdigit():
@@ -672,6 +686,7 @@
             Method(Name('release'), params['types']['void'], [],
                    {'tags': ['dawn', 'emscripten']}),
         ] if item_is_enabled(params['enabled_tags'], x.json_data)
+        and not item_is_disabled(params['disabled_tags'], x.json_data)
     ]
 
 
@@ -925,10 +940,14 @@
                            frontend_params))
 
         if 'dawn_wire' in targets:
-            additional_params = compute_wire_params(params_dawn, wire_json)
+            params_dawn_wire = parse_json(loaded_json,
+                                          enabled_tags=['dawn', 'deprecated'],
+                                          disabled_tags=['native'])
+            additional_params = compute_wire_params(params_dawn_wire,
+                                                    wire_json)
 
             wire_params = [
-                RENDER_PARAMS_BASE, params_dawn, {
+                RENDER_PARAMS_BASE, params_dawn_wire, {
                     'as_wireType': lambda type : as_wireType(metadata, type),
                     'as_annotated_wireType': \
                         lambda arg: annotated(as_wireType(metadata, arg.type), arg),
diff --git a/generator/templates/dawn_wire/WireCmd.cpp b/generator/templates/dawn_wire/WireCmd.cpp
index 7bc148f..e473192 100644
--- a/generator/templates/dawn_wire/WireCmd.cpp
+++ b/generator/templates/dawn_wire/WireCmd.cpp
@@ -179,6 +179,7 @@
             {% endif %}
             {
                 {% if member.annotation != "value" %}
+                    {{ assert(member.annotation != "const*const*") }}
                     auto memberLength = {{member_length(member, "record.")}};
                     result += memberLength * {{member_transfer_sizeof(member)}};
                     //* Structures might contain more pointers so we need to add their extra size as well.
@@ -258,6 +259,7 @@
 
         //* Allocate space and write the non-value arguments in it.
         {% for member in members if member.annotation != "value" and member.length != "strlen" and not member.skip_serialize %}
+            {{ assert(member.annotation != "const*const*") }}
             {% set memberName = as_varName(member.name) %}
 
             {% if member.type.category != "object" and member.optional %}
@@ -367,6 +369,7 @@
 
         //* Get extra buffer data, and copy pointed to values in extra allocated space.
         {% for member in members if member.annotation != "value" and member.length != "strlen" %}
+            {{ assert(member.annotation != "const*const*") }}
             {% set memberName = as_varName(member.name) %}
 
             {% if member.type.category != "object" and member.optional %}
diff --git a/src/dawn_native/Adapter.cpp b/src/dawn_native/Adapter.cpp
index 7ef85c1..a30c553 100644
--- a/src/dawn_native/Adapter.cpp
+++ b/src/dawn_native/Adapter.cpp
@@ -15,12 +15,15 @@
 #include "dawn_native/Adapter.h"
 
 #include "common/Constants.h"
+#include "dawn_native/Device.h"
 #include "dawn_native/Instance.h"
+#include "dawn_native/ValidationUtils_autogen.h"
 
 namespace dawn_native {
 
     AdapterBase::AdapterBase(InstanceBase* instance, wgpu::BackendType backend)
         : mInstance(instance), mBackend(backend) {
+        mSupportedFeatures.EnableFeature(Feature::DawnNative);
         mSupportedFeatures.EnableFeature(Feature::DawnInternalUsages);
     }
 
@@ -90,10 +93,36 @@
         return mSupportedFeatures.EnumerateFeatures(features);
     }
 
+    DeviceBase* AdapterBase::APICreateDevice(const DeviceDescriptor* descriptor) {
+        DeviceDescriptor defaultDesc = {};
+        if (descriptor == nullptr) {
+            descriptor = &defaultDesc;
+        }
+        auto result = CreateDeviceInternal(descriptor);
+        if (result.IsError()) {
+            mInstance->ConsumedError(result.AcquireError());
+            return nullptr;
+        }
+        return result.AcquireSuccess().Detach();
+    }
+
     void AdapterBase::APIRequestDevice(const DeviceDescriptor* descriptor,
                                        WGPURequestDeviceCallback callback,
                                        void* userdata) {
-        callback(WGPURequestDeviceStatus_Error, nullptr, "Not implemented", userdata);
+        auto result = CreateDeviceInternal(descriptor);
+
+        if (result.IsError()) {
+            std::unique_ptr<ErrorData> errorData = result.AcquireError();
+            callback(WGPURequestDeviceStatus_Error, nullptr,
+                     errorData->GetFormattedMessage().c_str(), userdata);
+            return;
+        }
+
+        Ref<DeviceBase> device = result.AcquireSuccess();
+
+        WGPURequestDeviceStatus status =
+            device == nullptr ? WGPURequestDeviceStatus_Unknown : WGPURequestDeviceStatus_Success;
+        callback(status, ToAPI(device.Detach()), nullptr, userdata);
     }
 
     wgpu::BackendType AdapterBase::GetBackendType() const {
@@ -120,14 +149,10 @@
         return mSupportedFeatures;
     }
 
-    bool AdapterBase::SupportsAllRequestedFeatures(
-        const std::vector<const char*>& requestedFeatures) const {
-        for (const char* featureStr : requestedFeatures) {
-            Feature featureEnum = mInstance->FeatureNameToEnum(featureStr);
-            if (featureEnum == Feature::InvalidEnum) {
-                return false;
-            }
-            if (!mSupportedFeatures.IsEnabled(featureEnum)) {
+    bool AdapterBase::SupportsAllRequiredFeatures(
+        const ityp::span<size_t, const wgpu::FeatureName>& features) const {
+        for (wgpu::FeatureName f : features) {
+            if (!mSupportedFeatures.IsEnabled(f)) {
                 return false;
             }
         }
@@ -163,57 +188,27 @@
         return true;
     }
 
-    DeviceBase* AdapterBase::CreateDevice(const DawnDeviceDescriptor* descriptor) {
-        DeviceBase* result = nullptr;
+    ResultOrError<Ref<DeviceBase>> AdapterBase::CreateDeviceInternal(
+        const DeviceDescriptor* descriptor) {
+        ASSERT(descriptor != nullptr);
 
-        if (mInstance->ConsumedError(CreateDeviceInternal(&result, descriptor))) {
-            return nullptr;
+        for (uint32_t i = 0; i < descriptor->requiredFeaturesCount; ++i) {
+            wgpu::FeatureName f = descriptor->requiredFeatures[i];
+            DAWN_TRY(ValidateFeatureName(f));
+            DAWN_INVALID_IF(!mSupportedFeatures.IsEnabled(f),
+                            "Requested feature %s is not supported.", f);
         }
 
-        return result;
-    }
-
-    void AdapterBase::RequestDevice(const DawnDeviceDescriptor* descriptor,
-                                    WGPURequestDeviceCallback callback,
-                                    void* userdata) {
-        DeviceBase* device = nullptr;
-        MaybeError err = CreateDeviceInternal(&device, descriptor);
-
-        if (err.IsError()) {
-            std::unique_ptr<ErrorData> errorData = err.AcquireError();
-            callback(WGPURequestDeviceStatus_Error, ToAPI(device),
-                     errorData->GetFormattedMessage().c_str(), userdata);
-            return;
-        }
-        WGPURequestDeviceStatus status =
-            device == nullptr ? WGPURequestDeviceStatus_Unknown : WGPURequestDeviceStatus_Success;
-        callback(status, ToAPI(device), nullptr, userdata);
-    }
-
-    MaybeError AdapterBase::CreateDeviceInternal(DeviceBase** result,
-                                                 const DawnDeviceDescriptor* descriptor) {
-        if (descriptor != nullptr) {
-            for (const char* featureStr : descriptor->requiredFeatures) {
-                Feature featureEnum = mInstance->FeatureNameToEnum(featureStr);
-                DAWN_INVALID_IF(featureEnum == Feature::InvalidEnum,
-                                "Requested feature %s is unknown.", featureStr);
-                DAWN_INVALID_IF(!mSupportedFeatures.IsEnabled(featureEnum),
-                                "Requested feature %s is disabled.", featureStr);
-            }
-        }
-
-        if (descriptor != nullptr && descriptor->requiredLimits != nullptr) {
+        if (descriptor->requiredLimits != nullptr) {
             DAWN_TRY_CONTEXT(
                 ValidateLimits(mUseTieredLimits ? ApplyLimitTiers(mLimits.v1) : mLimits.v1,
-                               FromAPI(descriptor->requiredLimits)->limits),
+                               descriptor->requiredLimits->limits),
                 "validating required limits");
 
             DAWN_INVALID_IF(descriptor->requiredLimits->nextInChain != nullptr,
                             "nextInChain is not nullptr.");
         }
-
-        DAWN_TRY_ASSIGN(*result, CreateDeviceImpl(descriptor));
-        return {};
+        return CreateDeviceImpl(descriptor);
     }
 
     void AdapterBase::SetUseTieredLimits(bool useTieredLimits) {
diff --git a/src/dawn_native/Adapter.h b/src/dawn_native/Adapter.h
index a8a5fdb..b8dc2d7 100644
--- a/src/dawn_native/Adapter.h
+++ b/src/dawn_native/Adapter.h
@@ -18,6 +18,7 @@
 #include "dawn_native/DawnNative.h"
 
 #include "common/RefCounted.h"
+#include "common/ityp_span.h"
 #include "dawn_native/Error.h"
 #include "dawn_native/Features.h"
 #include "dawn_native/Limits.h"
@@ -44,6 +45,7 @@
         void APIRequestDevice(const DeviceDescriptor* descriptor,
                               WGPURequestDeviceCallback callback,
                               void* userdata);
+        DeviceBase* APICreateDevice(const DeviceDescriptor* descriptor = nullptr);
 
         wgpu::BackendType GetBackendType() const;
         wgpu::AdapterType GetAdapterType() const;
@@ -51,16 +53,11 @@
         const PCIInfo& GetPCIInfo() const;
         InstanceBase* GetInstance() const;
 
-        DeviceBase* CreateDevice(const DawnDeviceDescriptor* descriptor = nullptr);
-
-        void RequestDevice(const DawnDeviceDescriptor* descriptor,
-                           WGPURequestDeviceCallback callback,
-                           void* userdata);
-
         void ResetInternalDeviceForTesting();
 
         FeaturesSet GetSupportedFeatures() const;
-        bool SupportsAllRequestedFeatures(const std::vector<const char*>& requestedFeatures) const;
+        bool SupportsAllRequiredFeatures(
+            const ityp::span<size_t, const wgpu::FeatureName>& features) const;
         WGPUDeviceProperties GetAdapterProperties() const;
 
         bool GetLimits(SupportedLimits* limits) const;
@@ -76,8 +73,8 @@
         FeaturesSet mSupportedFeatures;
 
       private:
-        virtual ResultOrError<DeviceBase*> CreateDeviceImpl(
-            const DawnDeviceDescriptor* descriptor) = 0;
+        virtual ResultOrError<Ref<DeviceBase>> CreateDeviceImpl(
+            const DeviceDescriptor* descriptor) = 0;
 
         virtual MaybeError InitializeImpl() = 0;
 
@@ -87,8 +84,7 @@
         // Check base WebGPU limits and populate supported limits.
         virtual MaybeError InitializeSupportedLimitsImpl(CombinedLimits* limits) = 0;
 
-        MaybeError CreateDeviceInternal(DeviceBase** result,
-                                        const DawnDeviceDescriptor* descriptor);
+        ResultOrError<Ref<DeviceBase>> CreateDeviceInternal(const DeviceDescriptor* descriptor);
 
         virtual MaybeError ResetInternalDeviceForTestingImpl();
         InstanceBase* mInstance = nullptr;
diff --git a/src/dawn_native/DawnNative.cpp b/src/dawn_native/DawnNative.cpp
index c10fe00..86a6bb4 100644
--- a/src/dawn_native/DawnNative.cpp
+++ b/src/dawn_native/DawnNative.cpp
@@ -14,6 +14,7 @@
 
 #include "dawn_native/DawnNative.h"
 
+#include "common/Log.h"
 #include "dawn_native/BindGroupLayout.h"
 #include "dawn_native/Buffer.h"
 #include "dawn_native/Device.h"
@@ -25,6 +26,41 @@
 
 namespace dawn_native {
 
+    namespace {
+        struct ComboDeprecatedDawnDeviceDescriptor : DeviceDescriptor {
+            ComboDeprecatedDawnDeviceDescriptor(const DawnDeviceDescriptor* deviceDescriptor) {
+                dawn::WarningLog() << "DawnDeviceDescriptor is deprecated. Please use "
+                                      "WGPUDeviceDescriptor instead.";
+
+                DeviceDescriptor* desc = this;
+
+                if (deviceDescriptor != nullptr) {
+                    desc->nextInChain = &mTogglesDesc;
+                    mTogglesDesc.forceEnabledToggles = deviceDescriptor->forceEnabledToggles.data();
+                    mTogglesDesc.forceEnabledTogglesCount =
+                        deviceDescriptor->forceEnabledToggles.size();
+                    mTogglesDesc.forceDisabledToggles =
+                        deviceDescriptor->forceDisabledToggles.data();
+                    mTogglesDesc.forceDisabledTogglesCount =
+                        deviceDescriptor->forceDisabledToggles.size();
+
+                    desc->requiredLimits =
+                        reinterpret_cast<const RequiredLimits*>(deviceDescriptor->requiredLimits);
+
+                    FeaturesInfo featuresInfo;
+                    for (const char* featureStr : deviceDescriptor->requiredFeatures) {
+                        mRequiredFeatures.push_back(featuresInfo.FeatureNameToAPIEnum(featureStr));
+                    }
+                    desc->requiredFeatures = mRequiredFeatures.data();
+                    desc->requiredFeaturesCount = mRequiredFeatures.size();
+                }
+            }
+
+            DawnTogglesDeviceDescriptor mTogglesDesc = {};
+            std::vector<wgpu::FeatureName> mRequiredFeatures = {};
+        };
+    }  // namespace
+
     const DawnProcTable& GetProcsAutogen();
 
     const DawnProcTable& GetProcs() {
@@ -98,6 +134,10 @@
         return mImpl->GetPCIInfo();
     }
 
+    WGPUAdapter Adapter::Get() const {
+        return ToAPI(mImpl);
+    }
+
     std::vector<const char*> Adapter::GetSupportedFeatures() const {
         FeaturesSet supportedFeaturesSet = mImpl->GetSupportedFeatures();
         return supportedFeaturesSet.GetEnabledFeatureNames();
@@ -124,13 +164,19 @@
     }
 
     WGPUDevice Adapter::CreateDevice(const DawnDeviceDescriptor* deviceDescriptor) {
-        return ToAPI(mImpl->CreateDevice(deviceDescriptor));
+        ComboDeprecatedDawnDeviceDescriptor desc(deviceDescriptor);
+        return ToAPI(mImpl->APICreateDevice(&desc));
+    }
+
+    WGPUDevice Adapter::CreateDevice(const WGPUDeviceDescriptor* deviceDescriptor) {
+        return ToAPI(mImpl->APICreateDevice(FromAPI(deviceDescriptor)));
     }
 
     void Adapter::RequestDevice(const DawnDeviceDescriptor* descriptor,
                                 WGPURequestDeviceCallback callback,
                                 void* userdata) {
-        mImpl->RequestDevice(descriptor, callback, userdata);
+        ComboDeprecatedDawnDeviceDescriptor desc(descriptor);
+        mImpl->APIRequestDevice(&desc, callback, userdata);
     }
 
     void Adapter::ResetInternalDeviceForTesting() {
@@ -176,6 +222,10 @@
         return mImpl->GetToggleInfo(toggleName);
     }
 
+    const FeatureInfo* Instance::GetFeatureInfo(WGPUFeatureName feature) {
+        return mImpl->GetFeatureInfo(static_cast<wgpu::FeatureName>(feature));
+    }
+
     void Instance::EnableBackendValidation(bool enableBackendValidation) {
         if (enableBackendValidation) {
             mImpl->SetBackendValidationLevel(BackendValidationLevel::Full);
diff --git a/src/dawn_native/Device.cpp b/src/dawn_native/Device.cpp
index 127b29f..90af4cf 100644
--- a/src/dawn_native/Device.cpp
+++ b/src/dawn_native/Device.cpp
@@ -21,6 +21,7 @@
 #include "dawn_native/BindGroup.h"
 #include "dawn_native/BindGroupLayout.h"
 #include "dawn_native/Buffer.h"
+#include "dawn_native/ChainUtils_autogen.h"
 #include "dawn_native/CommandBuffer.h"
 #include "dawn_native/CommandEncoder.h"
 #include "dawn_native/CompilationMessages.h"
@@ -172,15 +173,19 @@
 
     // DeviceBase
 
-    DeviceBase::DeviceBase(AdapterBase* adapter, const DawnDeviceDescriptor* descriptor)
+    DeviceBase::DeviceBase(AdapterBase* adapter, const DeviceDescriptor* descriptor)
         : mInstance(adapter->GetInstance()), mAdapter(adapter), mNextPipelineCompatibilityToken(1) {
-        if (descriptor != nullptr) {
-            ApplyToggleOverrides(descriptor);
-            ApplyFeatures(descriptor);
-        }
+        ASSERT(descriptor != nullptr);
 
-        if (descriptor != nullptr && descriptor->requiredLimits != nullptr) {
-            mLimits.v1 = ReifyDefaultLimits(FromAPI(descriptor->requiredLimits)->limits);
+        const DawnTogglesDeviceDescriptor* togglesDesc = nullptr;
+        FindInChain(descriptor->nextInChain, &togglesDesc);
+        if (togglesDesc != nullptr) {
+            ApplyToggleOverrides(togglesDesc);
+        }
+        ApplyFeatures(descriptor);
+
+        if (descriptor->requiredLimits != nullptr) {
+            mLimits.v1 = ReifyDefaultLimits(descriptor->requiredLimits->limits);
         } else {
             GetDefaultLimits(&mLimits.v1);
         }
@@ -1140,16 +1145,14 @@
         return result.Detach();
     }
 
-    void DeviceBase::ApplyFeatures(const DawnDeviceDescriptor* deviceDescriptor) {
+    void DeviceBase::ApplyFeatures(const DeviceDescriptor* deviceDescriptor) {
         ASSERT(deviceDescriptor);
-        ASSERT(GetAdapter()->SupportsAllRequestedFeatures(deviceDescriptor->requiredFeatures));
+        ASSERT(GetAdapter()->SupportsAllRequiredFeatures(
+            {deviceDescriptor->requiredFeatures, deviceDescriptor->requiredFeaturesCount}));
 
-        mEnabledFeatures = GetAdapter()->GetInstance()->FeatureNamesToFeaturesSet(
-            deviceDescriptor->requiredFeatures);
-    }
-
-    std::vector<const char*> DeviceBase::GetEnabledFeatures() const {
-        return mEnabledFeatures.GetEnabledFeatureNames();
+        for (uint32_t i = 0; i < deviceDescriptor->requiredFeaturesCount; ++i) {
+            mEnabledFeatures.EnableFeature(deviceDescriptor->requiredFeatures[i]);
+        }
     }
 
     bool DeviceBase::IsFeatureEnabled(Feature feature) const {
@@ -1600,18 +1603,20 @@
         SetToggle(Toggle::DisallowUnsafeAPIs, true);
     }
 
-    void DeviceBase::ApplyToggleOverrides(const DawnDeviceDescriptor* deviceDescriptor) {
-        ASSERT(deviceDescriptor);
+    void DeviceBase::ApplyToggleOverrides(const DawnTogglesDeviceDescriptor* togglesDescriptor) {
+        ASSERT(togglesDescriptor != nullptr);
 
-        for (const char* toggleName : deviceDescriptor->forceEnabledToggles) {
-            Toggle toggle = GetAdapter()->GetInstance()->ToggleNameToEnum(toggleName);
+        for (uint32_t i = 0; i < togglesDescriptor->forceEnabledTogglesCount; ++i) {
+            Toggle toggle = GetAdapter()->GetInstance()->ToggleNameToEnum(
+                togglesDescriptor->forceEnabledToggles[i]);
             if (toggle != Toggle::InvalidEnum) {
                 mEnabledToggles.Set(toggle, true);
                 mOverridenToggles.Set(toggle, true);
             }
         }
-        for (const char* toggleName : deviceDescriptor->forceDisabledToggles) {
-            Toggle toggle = GetAdapter()->GetInstance()->ToggleNameToEnum(toggleName);
+        for (uint32_t i = 0; i < togglesDescriptor->forceDisabledTogglesCount; ++i) {
+            Toggle toggle = GetAdapter()->GetInstance()->ToggleNameToEnum(
+                togglesDescriptor->forceDisabledToggles[i]);
             if (toggle != Toggle::InvalidEnum) {
                 mEnabledToggles.Set(toggle, false);
                 mOverridenToggles.Set(toggle, true);
diff --git a/src/dawn_native/Device.h b/src/dawn_native/Device.h
index 298d0b4..1925478 100644
--- a/src/dawn_native/Device.h
+++ b/src/dawn_native/Device.h
@@ -56,7 +56,7 @@
 
     class DeviceBase : public RefCounted {
       public:
-        DeviceBase(AdapterBase* adapter, const DawnDeviceDescriptor* descriptor);
+        DeviceBase(AdapterBase* adapter, const DeviceDescriptor* descriptor);
         virtual ~DeviceBase();
 
         void HandleError(InternalErrorType type, const char* message);
@@ -312,7 +312,6 @@
         void TrackObject(ApiObjectBase* object);
         std::mutex* GetObjectListMutex(ObjectType type);
 
-        std::vector<const char*> GetEnabledFeatures() const;
         std::vector<const char*> GetTogglesUsed() const;
         bool IsFeatureEnabled(Feature feature) const;
         bool IsToggleEnabled(Toggle toggle) const;
@@ -442,8 +441,8 @@
             WGPUCreateRenderPipelineAsyncCallback callback,
             void* userdata);
 
-        void ApplyToggleOverrides(const DawnDeviceDescriptor* deviceDescriptor);
-        void ApplyFeatures(const DawnDeviceDescriptor* deviceDescriptor);
+        void ApplyToggleOverrides(const DawnTogglesDeviceDescriptor* togglesDescriptor);
+        void ApplyFeatures(const DeviceDescriptor* deviceDescriptor);
 
         void SetDefaultToggles();
 
diff --git a/src/dawn_native/Features.cpp b/src/dawn_native/Features.cpp
index 037d8f4..913706c 100644
--- a/src/dawn_native/Features.cpp
+++ b/src/dawn_native/Features.cpp
@@ -83,7 +83,12 @@
               {"multiplanar-formats",
                "Import and use multi-planar texture formats with per plane views",
                "https://bugs.chromium.org/p/dawn/issues/detail?id=551"},
-              &WGPUDeviceProperties::multiPlanarFormats}}};
+              &WGPUDeviceProperties::multiPlanarFormats},
+             {Feature::DawnNative,
+              {"dawn-native", "WebGPU is running on top of dawn_native.",
+               "https://dawn.googlesource.com/dawn/+/refs/heads/main/docs/features/"
+               "dawn_native.md"},
+              &WGPUDeviceProperties::dawnNative}}};
 
         Feature FromAPIFeature(wgpu::FeatureName feature) {
             switch (feature) {
@@ -112,6 +117,8 @@
                     return Feature::DawnInternalUsages;
                 case wgpu::FeatureName::DawnMultiPlanarFormats:
                     return Feature::MultiPlanarFormats;
+                case wgpu::FeatureName::DawnNative:
+                    return Feature::DawnNative;
 
                 case wgpu::FeatureName::IndirectFirstInstance:
                     return Feature::InvalidEnum;
@@ -143,6 +150,8 @@
                     return wgpu::FeatureName::DawnInternalUsages;
                 case Feature::MultiPlanarFormats:
                     return wgpu::FeatureName::DawnMultiPlanarFormats;
+                case Feature::DawnNative:
+                    return wgpu::FeatureName::DawnNative;
 
                 case Feature::EnumCount:
                     UNREACHABLE();
@@ -157,6 +166,10 @@
         featuresBitSet.set(featureIndex);
     }
 
+    void FeaturesSet::EnableFeature(wgpu::FeatureName feature) {
+        EnableFeature(FromAPIFeature(feature));
+    }
+
     bool FeaturesSet::IsEnabled(Feature feature) const {
         ASSERT(feature != Feature::InvalidEnum);
         const size_t featureIndex = static_cast<size_t>(feature);
@@ -184,8 +197,13 @@
 
         uint32_t index = 0;
         for (uint32_t i : IterateBitSet(featuresBitSet)) {
-            const char* featureName = FeatureEnumToName(static_cast<Feature>(i));
-            enabledFeatureNames[index] = featureName;
+            Feature feature = static_cast<Feature>(i);
+            ASSERT(feature != Feature::InvalidEnum);
+
+            const FeatureEnumAndInfo& featureNameAndInfo = kFeatureNameAndInfoList[i];
+            ASSERT(featureNameAndInfo.feature == feature);
+
+            enabledFeatureNames[index] = featureNameAndInfo.info.name;
             ++index;
         }
         return enabledFeatureNames;
@@ -199,13 +217,9 @@
         }
     }
 
-    const char* FeatureEnumToName(Feature feature) {
+    wgpu::FeatureName FeatureEnumToAPIFeature(Feature feature) {
         ASSERT(feature != Feature::InvalidEnum);
-
-        const FeatureEnumAndInfo& featureNameAndInfo =
-            kFeatureNameAndInfoList[static_cast<size_t>(feature)];
-        ASSERT(featureNameAndInfo.feature == feature);
-        return featureNameAndInfo.info.name;
+        return ToAPIFeature(feature);
     }
 
     FeaturesInfo::FeaturesInfo() {
@@ -216,14 +230,12 @@
         }
     }
 
-    const FeatureInfo* FeaturesInfo::GetFeatureInfo(const char* featureName) const {
-        ASSERT(featureName);
-
-        const auto& iter = mFeatureNameToEnumMap.find(featureName);
-        if (iter != mFeatureNameToEnumMap.cend()) {
-            return &kFeatureNameAndInfoList[static_cast<size_t>(iter->second)].info;
+    const FeatureInfo* FeaturesInfo::GetFeatureInfo(wgpu::FeatureName feature) const {
+        Feature f = FromAPIFeature(feature);
+        if (f == Feature::InvalidEnum) {
+            return nullptr;
         }
-        return nullptr;
+        return &kFeatureNameAndInfoList[static_cast<size_t>(f)].info;
     }
 
     Feature FeaturesInfo::FeatureNameToEnum(const char* featureName) const {
@@ -253,16 +265,13 @@
         return Feature::InvalidEnum;
     }
 
-    FeaturesSet FeaturesInfo::FeatureNamesToFeaturesSet(
-        const std::vector<const char*>& requiredFeatures) const {
-        FeaturesSet featuresSet;
-
-        for (const char* featureName : requiredFeatures) {
-            Feature featureEnum = FeatureNameToEnum(featureName);
-            ASSERT(featureEnum != Feature::InvalidEnum);
-            featuresSet.EnableFeature(featureEnum);
+    wgpu::FeatureName FeaturesInfo::FeatureNameToAPIEnum(const char* featureName) const {
+        Feature f = FeatureNameToEnum(featureName);
+        if (f != Feature::InvalidEnum) {
+            return ToAPIFeature(f);
         }
-        return featuresSet;
+        // Pass something invalid.
+        return static_cast<wgpu::FeatureName>(-1);
     }
 
 }  // namespace dawn_native
diff --git a/src/dawn_native/Features.h b/src/dawn_native/Features.h
index 6dd2afc..07a1e6d 100644
--- a/src/dawn_native/Features.h
+++ b/src/dawn_native/Features.h
@@ -39,6 +39,7 @@
         // Dawn-specific
         DawnInternalUsages,
         MultiPlanarFormats,
+        DawnNative,
 
         EnumCount,
         InvalidEnum = EnumCount,
@@ -51,6 +52,7 @@
         std::bitset<static_cast<size_t>(Feature::EnumCount)> featuresBitSet;
 
         void EnableFeature(Feature feature);
+        void EnableFeature(wgpu::FeatureName feature);
         bool IsEnabled(Feature feature) const;
         bool IsEnabled(wgpu::FeatureName feature) const;
         // Returns |count|, the number of features. Writes out all |count| values if |features| is
@@ -60,7 +62,7 @@
         void InitializeDeviceProperties(WGPUDeviceProperties* properties) const;
     };
 
-    const char* FeatureEnumToName(Feature feature);
+    wgpu::FeatureName FeatureEnumToAPIFeature(Feature feature);
 
     class FeaturesInfo {
       public:
@@ -68,10 +70,9 @@
 
         // Used to query the details of an feature. Return nullptr if featureName is not a valid
         // name of an feature supported in Dawn
-        const FeatureInfo* GetFeatureInfo(const char* featureName) const;
+        const FeatureInfo* GetFeatureInfo(wgpu::FeatureName feature) const;
         Feature FeatureNameToEnum(const char* featureName) const;
-        FeaturesSet FeatureNamesToFeaturesSet(
-            const std::vector<const char*>& requiredFeatures) const;
+        wgpu::FeatureName FeatureNameToAPIEnum(const char* featureName) const;
 
       private:
         std::unordered_map<std::string, Feature> mFeatureNameToEnumMap;
diff --git a/src/dawn_native/Instance.cpp b/src/dawn_native/Instance.cpp
index d8e107f..39648f3 100644
--- a/src/dawn_native/Instance.cpp
+++ b/src/dawn_native/Instance.cpp
@@ -142,17 +142,8 @@
         return mTogglesInfo.ToggleNameToEnum(toggleName);
     }
 
-    const FeatureInfo* InstanceBase::GetFeatureInfo(const char* featureName) {
-        return mFeaturesInfo.GetFeatureInfo(featureName);
-    }
-
-    Feature InstanceBase::FeatureNameToEnum(const char* featureName) {
-        return mFeaturesInfo.FeatureNameToEnum(featureName);
-    }
-
-    FeaturesSet InstanceBase::FeatureNamesToFeaturesSet(
-        const std::vector<const char*>& requiredFeatures) {
-        return mFeaturesInfo.FeatureNamesToFeaturesSet(requiredFeatures);
+    const FeatureInfo* InstanceBase::GetFeatureInfo(wgpu::FeatureName feature) {
+        return mFeaturesInfo.GetFeatureInfo(feature);
     }
 
     const std::vector<std::unique_ptr<AdapterBase>>& InstanceBase::GetAdapters() const {
diff --git a/src/dawn_native/Instance.h b/src/dawn_native/Instance.h
index a36255a..488a30e 100644
--- a/src/dawn_native/Instance.h
+++ b/src/dawn_native/Instance.h
@@ -64,9 +64,7 @@
 
         // Used to query the details of an feature. Return nullptr if featureName is not a valid
         // name of an feature supported in Dawn.
-        const FeatureInfo* GetFeatureInfo(const char* featureName);
-        Feature FeatureNameToEnum(const char* featureName);
-        FeaturesSet FeatureNamesToFeaturesSet(const std::vector<const char*>& requiredFeatures);
+        const FeatureInfo* GetFeatureInfo(wgpu::FeatureName feature);
 
         bool IsBackendValidationEnabled() const;
         void SetBackendValidationLevel(BackendValidationLevel level);
diff --git a/src/dawn_native/d3d12/AdapterD3D12.cpp b/src/dawn_native/d3d12/AdapterD3D12.cpp
index ca845f3..6e40c7a 100644
--- a/src/dawn_native/d3d12/AdapterD3D12.cpp
+++ b/src/dawn_native/d3d12/AdapterD3D12.cpp
@@ -394,7 +394,7 @@
         infoQueue->PopStorageFilter();
     }
 
-    ResultOrError<DeviceBase*> Adapter::CreateDeviceImpl(const DawnDeviceDescriptor* descriptor) {
+    ResultOrError<Ref<DeviceBase>> Adapter::CreateDeviceImpl(const DeviceDescriptor* descriptor) {
         return Device::Create(this, descriptor);
     }
 
diff --git a/src/dawn_native/d3d12/AdapterD3D12.h b/src/dawn_native/d3d12/AdapterD3D12.h
index 4f40447..4bb5a02 100644
--- a/src/dawn_native/d3d12/AdapterD3D12.h
+++ b/src/dawn_native/d3d12/AdapterD3D12.h
@@ -40,8 +40,8 @@
         const gpu_info::D3DDriverVersion& GetDriverVersion() const;
 
       private:
-        ResultOrError<DeviceBase*> CreateDeviceImpl(
-            const DawnDeviceDescriptor* descriptor) override;
+        ResultOrError<Ref<DeviceBase>> CreateDeviceImpl(
+            const DeviceDescriptor* descriptor) override;
         MaybeError ResetInternalDeviceForTestingImpl() override;
 
         bool AreTimestampQueriesSupported() const;
diff --git a/src/dawn_native/d3d12/DeviceD3D12.cpp b/src/dawn_native/d3d12/DeviceD3D12.cpp
index 2104789..94697e2 100644
--- a/src/dawn_native/d3d12/DeviceD3D12.cpp
+++ b/src/dawn_native/d3d12/DeviceD3D12.cpp
@@ -56,11 +56,11 @@
     static constexpr uint64_t kMaxDebugMessagesToPrint = 5;
 
     // static
-    ResultOrError<Device*> Device::Create(Adapter* adapter,
-                                          const DawnDeviceDescriptor* descriptor) {
+    ResultOrError<Ref<Device>> Device::Create(Adapter* adapter,
+                                              const DeviceDescriptor* descriptor) {
         Ref<Device> device = AcquireRef(new Device(adapter, descriptor));
         DAWN_TRY(device->Initialize());
-        return device.Detach();
+        return device;
     }
 
     MaybeError Device::Initialize() {
diff --git a/src/dawn_native/d3d12/DeviceD3D12.h b/src/dawn_native/d3d12/DeviceD3D12.h
index e6b7234..6036e41 100644
--- a/src/dawn_native/d3d12/DeviceD3D12.h
+++ b/src/dawn_native/d3d12/DeviceD3D12.h
@@ -41,8 +41,8 @@
     // Definition of backend types
     class Device final : public DeviceBase {
       public:
-        static ResultOrError<Device*> Create(Adapter* adapter,
-                                             const DawnDeviceDescriptor* descriptor);
+        static ResultOrError<Ref<Device>> Create(Adapter* adapter,
+                                                 const DeviceDescriptor* descriptor);
         ~Device() override;
 
         MaybeError Initialize();
diff --git a/src/dawn_native/metal/BackendMTL.mm b/src/dawn_native/metal/BackendMTL.mm
index 632aa8a..8b0194b 100644
--- a/src/dawn_native/metal/BackendMTL.mm
+++ b/src/dawn_native/metal/BackendMTL.mm
@@ -277,8 +277,8 @@
         }
 
       private:
-        ResultOrError<DeviceBase*> CreateDeviceImpl(
-            const DawnDeviceDescriptor* descriptor) override {
+        ResultOrError<Ref<DeviceBase>> CreateDeviceImpl(
+            const DeviceDescriptor* descriptor) override {
             return Device::Create(this, mDevice, descriptor);
         }
 
diff --git a/src/dawn_native/metal/DeviceMTL.h b/src/dawn_native/metal/DeviceMTL.h
index 6f5153b..14c179f 100644
--- a/src/dawn_native/metal/DeviceMTL.h
+++ b/src/dawn_native/metal/DeviceMTL.h
@@ -38,9 +38,9 @@
 
     class Device final : public DeviceBase {
       public:
-        static ResultOrError<Device*> Create(AdapterBase* adapter,
-                                             NSPRef<id<MTLDevice>> mtlDevice,
-                                             const DawnDeviceDescriptor* descriptor);
+        static ResultOrError<Ref<Device>> Create(AdapterBase* adapter,
+                                                 NSPRef<id<MTLDevice>> mtlDevice,
+                                                 const DeviceDescriptor* descriptor);
         ~Device() override;
 
         MaybeError Initialize();
@@ -77,7 +77,7 @@
       private:
         Device(AdapterBase* adapter,
                NSPRef<id<MTLDevice>> mtlDevice,
-               const DawnDeviceDescriptor* descriptor);
+               const DeviceDescriptor* descriptor);
 
         ResultOrError<Ref<BindGroupBase>> CreateBindGroupImpl(
             const BindGroupDescriptor* descriptor) override;
diff --git a/src/dawn_native/metal/DeviceMTL.mm b/src/dawn_native/metal/DeviceMTL.mm
index c79cff4..f02d096 100644
--- a/src/dawn_native/metal/DeviceMTL.mm
+++ b/src/dawn_native/metal/DeviceMTL.mm
@@ -106,17 +106,17 @@
     }  // namespace
 
     // static
-    ResultOrError<Device*> Device::Create(AdapterBase* adapter,
-                                          NSPRef<id<MTLDevice>> mtlDevice,
-                                          const DawnDeviceDescriptor* descriptor) {
+    ResultOrError<Ref<Device>> Device::Create(AdapterBase* adapter,
+                                              NSPRef<id<MTLDevice>> mtlDevice,
+                                              const DeviceDescriptor* descriptor) {
         Ref<Device> device = AcquireRef(new Device(adapter, std::move(mtlDevice), descriptor));
         DAWN_TRY(device->Initialize());
-        return device.Detach();
+        return device;
     }
 
     Device::Device(AdapterBase* adapter,
                    NSPRef<id<MTLDevice>> mtlDevice,
-                   const DawnDeviceDescriptor* descriptor)
+                   const DeviceDescriptor* descriptor)
         : DeviceBase(adapter, descriptor), mMtlDevice(std::move(mtlDevice)), mCompletedSerial(0) {
     }
 
diff --git a/src/dawn_native/null/DeviceNull.cpp b/src/dawn_native/null/DeviceNull.cpp
index b7146b9..58a783c 100644
--- a/src/dawn_native/null/DeviceNull.cpp
+++ b/src/dawn_native/null/DeviceNull.cpp
@@ -38,8 +38,11 @@
     }
 
     // Used for the tests that intend to use an adapter without all features enabled.
-    void Adapter::SetSupportedFeatures(const std::vector<const char*>& requiredFeatures) {
-        mSupportedFeatures = GetInstance()->FeatureNamesToFeaturesSet(requiredFeatures);
+    void Adapter::SetSupportedFeatures(const std::vector<wgpu::FeatureName>& requiredFeatures) {
+        mSupportedFeatures = {};
+        for (wgpu::FeatureName f : requiredFeatures) {
+            mSupportedFeatures.EnableFeature(f);
+        }
     }
 
     MaybeError Adapter::InitializeImpl() {
@@ -57,7 +60,7 @@
         return {};
     }
 
-    ResultOrError<DeviceBase*> Adapter::CreateDeviceImpl(const DawnDeviceDescriptor* descriptor) {
+    ResultOrError<Ref<DeviceBase>> Adapter::CreateDeviceImpl(const DeviceDescriptor* descriptor) {
         return Device::Create(this, descriptor);
     }
 
@@ -95,11 +98,11 @@
     // Device
 
     // static
-    ResultOrError<Device*> Device::Create(Adapter* adapter,
-                                          const DawnDeviceDescriptor* descriptor) {
+    ResultOrError<Ref<Device>> Device::Create(Adapter* adapter,
+                                              const DeviceDescriptor* descriptor) {
         Ref<Device> device = AcquireRef(new Device(adapter, descriptor));
         DAWN_TRY(device->Initialize());
-        return device.Detach();
+        return device;
     }
 
     Device::~Device() {
diff --git a/src/dawn_native/null/DeviceNull.h b/src/dawn_native/null/DeviceNull.h
index 380295b..ef2adfb 100644
--- a/src/dawn_native/null/DeviceNull.h
+++ b/src/dawn_native/null/DeviceNull.h
@@ -86,8 +86,8 @@
 
     class Device final : public DeviceBase {
       public:
-        static ResultOrError<Device*> Create(Adapter* adapter,
-                                             const DawnDeviceDescriptor* descriptor);
+        static ResultOrError<Ref<Device>> Create(Adapter* adapter,
+                                                 const DeviceDescriptor* descriptor);
         ~Device() override;
 
         MaybeError Initialize();
@@ -175,15 +175,15 @@
         bool SupportsExternalImages() const override;
 
         // Used for the tests that intend to use an adapter without all features enabled.
-        void SetSupportedFeatures(const std::vector<const char*>& requiredFeatures);
+        void SetSupportedFeatures(const std::vector<wgpu::FeatureName>& requiredFeatures);
 
       private:
         MaybeError InitializeImpl() override;
         MaybeError InitializeSupportedFeaturesImpl() override;
         MaybeError InitializeSupportedLimitsImpl(CombinedLimits* limits) override;
 
-        ResultOrError<DeviceBase*> CreateDeviceImpl(
-            const DawnDeviceDescriptor* descriptor) override;
+        ResultOrError<Ref<DeviceBase>> CreateDeviceImpl(
+            const DeviceDescriptor* descriptor) override;
     };
 
     // Helper class so |BindGroup| can allocate memory for its binding data,
diff --git a/src/dawn_native/opengl/BackendGL.cpp b/src/dawn_native/opengl/BackendGL.cpp
index 3c57200..611d258 100644
--- a/src/dawn_native/opengl/BackendGL.cpp
+++ b/src/dawn_native/opengl/BackendGL.cpp
@@ -254,8 +254,8 @@
             return {};
         }
 
-        ResultOrError<DeviceBase*> CreateDeviceImpl(
-            const DawnDeviceDescriptor* descriptor) override {
+        ResultOrError<Ref<DeviceBase>> CreateDeviceImpl(
+            const DeviceDescriptor* descriptor) override {
             // There is no limit on the number of devices created from this adapter because they can
             // all share the same backing OpenGL context.
             return Device::Create(this, descriptor, mFunctions);
diff --git a/src/dawn_native/opengl/DeviceGL.cpp b/src/dawn_native/opengl/DeviceGL.cpp
index 89bd9f8..0240e06 100644
--- a/src/dawn_native/opengl/DeviceGL.cpp
+++ b/src/dawn_native/opengl/DeviceGL.cpp
@@ -35,16 +35,16 @@
 namespace dawn_native { namespace opengl {
 
     // static
-    ResultOrError<Device*> Device::Create(AdapterBase* adapter,
-                                          const DawnDeviceDescriptor* descriptor,
-                                          const OpenGLFunctions& functions) {
+    ResultOrError<Ref<Device>> Device::Create(AdapterBase* adapter,
+                                              const DeviceDescriptor* descriptor,
+                                              const OpenGLFunctions& functions) {
         Ref<Device> device = AcquireRef(new Device(adapter, descriptor, functions));
         DAWN_TRY(device->Initialize());
-        return device.Detach();
+        return device;
     }
 
     Device::Device(AdapterBase* adapter,
-                   const DawnDeviceDescriptor* descriptor,
+                   const DeviceDescriptor* descriptor,
                    const OpenGLFunctions& functions)
         : DeviceBase(adapter, descriptor), gl(functions) {
     }
diff --git a/src/dawn_native/opengl/DeviceGL.h b/src/dawn_native/opengl/DeviceGL.h
index f131706..1bd8f31 100644
--- a/src/dawn_native/opengl/DeviceGL.h
+++ b/src/dawn_native/opengl/DeviceGL.h
@@ -37,9 +37,9 @@
 
     class Device final : public DeviceBase {
       public:
-        static ResultOrError<Device*> Create(AdapterBase* adapter,
-                                             const DawnDeviceDescriptor* descriptor,
-                                             const OpenGLFunctions& functions);
+        static ResultOrError<Ref<Device>> Create(AdapterBase* adapter,
+                                                 const DeviceDescriptor* descriptor,
+                                                 const OpenGLFunctions& functions);
         ~Device() override;
 
         MaybeError Initialize();
@@ -81,7 +81,7 @@
 
       private:
         Device(AdapterBase* adapter,
-               const DawnDeviceDescriptor* descriptor,
+               const DeviceDescriptor* descriptor,
                const OpenGLFunctions& functions);
 
         ResultOrError<Ref<BindGroupBase>> CreateBindGroupImpl(
diff --git a/src/dawn_native/vulkan/AdapterVk.cpp b/src/dawn_native/vulkan/AdapterVk.cpp
index 816efff..4f8b1c9 100644
--- a/src/dawn_native/vulkan/AdapterVk.cpp
+++ b/src/dawn_native/vulkan/AdapterVk.cpp
@@ -338,7 +338,7 @@
                                                          mVulkanInstance->GetFunctions());
     }
 
-    ResultOrError<DeviceBase*> Adapter::CreateDeviceImpl(const DawnDeviceDescriptor* descriptor) {
+    ResultOrError<Ref<DeviceBase>> Adapter::CreateDeviceImpl(const DeviceDescriptor* descriptor) {
         return Device::Create(this, descriptor);
     }
 
diff --git a/src/dawn_native/vulkan/AdapterVk.h b/src/dawn_native/vulkan/AdapterVk.h
index 7e9257c..6d93a07 100644
--- a/src/dawn_native/vulkan/AdapterVk.h
+++ b/src/dawn_native/vulkan/AdapterVk.h
@@ -46,8 +46,8 @@
         MaybeError InitializeSupportedFeaturesImpl() override;
         MaybeError InitializeSupportedLimitsImpl(CombinedLimits* limits) override;
 
-        ResultOrError<DeviceBase*> CreateDeviceImpl(
-            const DawnDeviceDescriptor* descriptor) override;
+        ResultOrError<Ref<DeviceBase>> CreateDeviceImpl(
+            const DeviceDescriptor* descriptor) override;
 
         VkPhysicalDevice mPhysicalDevice;
         Ref<VulkanInstance> mVulkanInstance;
diff --git a/src/dawn_native/vulkan/DeviceVk.cpp b/src/dawn_native/vulkan/DeviceVk.cpp
index de7c8d4..2c2c48b 100644
--- a/src/dawn_native/vulkan/DeviceVk.cpp
+++ b/src/dawn_native/vulkan/DeviceVk.cpp
@@ -45,14 +45,14 @@
 namespace dawn_native { namespace vulkan {
 
     // static
-    ResultOrError<Device*> Device::Create(Adapter* adapter,
-                                          const DawnDeviceDescriptor* descriptor) {
+    ResultOrError<Ref<Device>> Device::Create(Adapter* adapter,
+                                              const DeviceDescriptor* descriptor) {
         Ref<Device> device = AcquireRef(new Device(adapter, descriptor));
         DAWN_TRY(device->Initialize());
-        return device.Detach();
+        return device;
     }
 
-    Device::Device(Adapter* adapter, const DawnDeviceDescriptor* descriptor)
+    Device::Device(Adapter* adapter, const DeviceDescriptor* descriptor)
         : DeviceBase(adapter, descriptor) {
         InitTogglesFromDriver();
     }
diff --git a/src/dawn_native/vulkan/DeviceVk.h b/src/dawn_native/vulkan/DeviceVk.h
index 1c697a8..00f32c7 100644
--- a/src/dawn_native/vulkan/DeviceVk.h
+++ b/src/dawn_native/vulkan/DeviceVk.h
@@ -43,8 +43,8 @@
 
     class Device final : public DeviceBase {
       public:
-        static ResultOrError<Device*> Create(Adapter* adapter,
-                                             const DawnDeviceDescriptor* descriptor);
+        static ResultOrError<Ref<Device>> Create(Adapter* adapter,
+                                                 const DeviceDescriptor* descriptor);
         ~Device() override;
 
         MaybeError Initialize();
@@ -106,7 +106,7 @@
         float GetTimestampPeriodInNS() const override;
 
       private:
-        Device(Adapter* adapter, const DawnDeviceDescriptor* descriptor);
+        Device(Adapter* adapter, const DeviceDescriptor* descriptor);
 
         ResultOrError<Ref<BindGroupBase>> CreateBindGroupImpl(
             const BindGroupDescriptor* descriptor) override;
diff --git a/src/dawn_wire/SupportedFeatures.cpp b/src/dawn_wire/SupportedFeatures.cpp
index a1d4006..41c3a4a 100644
--- a/src/dawn_wire/SupportedFeatures.cpp
+++ b/src/dawn_wire/SupportedFeatures.cpp
@@ -22,6 +22,7 @@
         switch (feature) {
             case WGPUFeatureName_Undefined:
             case WGPUFeatureName_Force32:
+            case WGPUFeatureName_DawnNative:
                 return false;
             case WGPUFeatureName_Depth24UnormStencil8:
             case WGPUFeatureName_Depth32FloatStencil8:
diff --git a/src/dawn_wire/client/Adapter.cpp b/src/dawn_wire/client/Adapter.cpp
index fd5daf7..db9986f 100644
--- a/src/dawn_wire/client/Adapter.cpp
+++ b/src/dawn_wire/client/Adapter.cpp
@@ -14,6 +14,7 @@
 
 #include "dawn_wire/client/Adapter.h"
 
+#include "common/Log.h"
 #include "dawn_wire/client/Client.h"
 
 namespace dawn_wire { namespace client {
@@ -124,4 +125,9 @@
         return true;
     }
 
+    WGPUDevice Adapter::CreateDevice(const WGPUDeviceDescriptor*) {
+        dawn::ErrorLog() << "adapter.CreateDevice not supported with dawn_wire.";
+        return nullptr;
+    }
+
 }}  // namespace dawn_wire::client
diff --git a/src/dawn_wire/client/Adapter.h b/src/dawn_wire/client/Adapter.h
index e6f77dc..26c8222 100644
--- a/src/dawn_wire/client/Adapter.h
+++ b/src/dawn_wire/client/Adapter.h
@@ -50,6 +50,9 @@
                                      uint32_t featuresCount,
                                      const WGPUFeatureName* features);
 
+        // Unimplementable. Only availale in dawn_native.
+        WGPUDevice CreateDevice(const WGPUDeviceDescriptor*);
+
       private:
         LimitsAndFeatures mLimitsAndFeatures;
         WGPUAdapterProperties mProperties;
diff --git a/src/include/dawn_native/DawnNative.h b/src/include/dawn_native/DawnNative.h
index a73f4f2..fb2bd78 100644
--- a/src/include/dawn_native/DawnNative.h
+++ b/src/include/dawn_native/DawnNative.h
@@ -121,15 +121,17 @@
 
         explicit operator bool() const;
 
-        // Create a device on this adapter, note that the interface will change to include at least
-        // a device descriptor and a pointer to backend specific options.
-        // On an error, nullptr is returned.
-        WGPUDevice CreateDevice(const DawnDeviceDescriptor* deviceDescriptor = nullptr);
+        // Create a device on this adapter. On an error, nullptr is returned.
+        WGPUDevice CreateDevice(const DawnDeviceDescriptor* deviceDescriptor);
+        WGPUDevice CreateDevice(const WGPUDeviceDescriptor* deviceDescriptor = nullptr);
 
         void RequestDevice(const DawnDeviceDescriptor* descriptor,
                            WGPURequestDeviceCallback callback,
                            void* userdata);
 
+        // Returns the underlying WGPUAdapter object.
+        WGPUAdapter Get() const;
+
         // Reset the backend device object for testing purposes.
         void ResetInternalDeviceForTesting();
 
@@ -173,6 +175,7 @@
         std::vector<Adapter> GetAdapters() const;
 
         const ToggleInfo* GetToggleInfo(const char* toggleName);
+        const FeatureInfo* GetFeatureInfo(WGPUFeatureName feature);
 
         // Enables backend validation layers
         void EnableBackendValidation(bool enableBackendValidation);
diff --git a/src/tests/BUILD.gn b/src/tests/BUILD.gn
index 4eb64a3..6141875 100644
--- a/src/tests/BUILD.gn
+++ b/src/tests/BUILD.gn
@@ -227,6 +227,7 @@
     "unittests/TypedIntegerTests.cpp",
     "unittests/native/CommandBufferEncodingTests.cpp",
     "unittests/native/DestroyObjectTests.cpp",
+    "unittests/native/DeviceCreationTests.cpp",
     "unittests/validation/BindGroupValidationTests.cpp",
     "unittests/validation/BufferValidationTests.cpp",
     "unittests/validation/CommandBufferValidationTests.cpp",
diff --git a/src/tests/unittests/FeatureTests.cpp b/src/tests/unittests/FeatureTests.cpp
index 729dca6..4e1e797 100644
--- a/src/tests/unittests/FeatureTests.cpp
+++ b/src/tests/unittests/FeatureTests.cpp
@@ -26,10 +26,10 @@
           mAdapterBase(mInstanceBase.Get()) {
     }
 
-    std::vector<const char*> GetAllFeatureNames() {
-        std::vector<const char*> allFeatureNames(kTotalFeaturesCount);
+    std::vector<wgpu::FeatureName> GetAllFeatureNames() {
+        std::vector<wgpu::FeatureName> allFeatureNames(kTotalFeaturesCount);
         for (size_t i = 0; i < kTotalFeaturesCount; ++i) {
-            allFeatureNames[i] = FeatureEnumToName(static_cast<dawn_native::Feature>(i));
+            allFeatureNames[i] = FeatureEnumToAPIFeature(static_cast<dawn_native::Feature>(i));
         }
         return allFeatureNames;
     }
@@ -45,20 +45,23 @@
 // Test the creation of a device will fail if the requested feature is not supported on the
 // Adapter.
 TEST_F(FeatureTests, AdapterWithRequiredFeatureDisabled) {
-    const std::vector<const char*> kAllFeatureNames = GetAllFeatureNames();
+    const std::vector<wgpu::FeatureName> kAllFeatureNames = GetAllFeatureNames();
     for (size_t i = 0; i < kTotalFeaturesCount; ++i) {
         dawn_native::Feature notSupportedFeature = static_cast<dawn_native::Feature>(i);
 
-        std::vector<const char*> featureNamesWithoutOne = kAllFeatureNames;
+        std::vector<wgpu::FeatureName> featureNamesWithoutOne = kAllFeatureNames;
         featureNamesWithoutOne.erase(featureNamesWithoutOne.begin() + i);
 
         mAdapterBase.SetSupportedFeatures(featureNamesWithoutOne);
         dawn_native::Adapter adapterWithoutFeature(&mAdapterBase);
 
-        dawn_native::DawnDeviceDescriptor deviceDescriptor;
-        const char* featureName = FeatureEnumToName(notSupportedFeature);
-        deviceDescriptor.requiredFeatures = std::vector<const char*>(1, featureName);
-        WGPUDevice deviceWithFeature = adapterWithoutFeature.CreateDevice(&deviceDescriptor);
+        wgpu::DeviceDescriptor deviceDescriptor;
+        wgpu::FeatureName featureName = FeatureEnumToAPIFeature(notSupportedFeature);
+        deviceDescriptor.requiredFeatures = &featureName;
+        deviceDescriptor.requiredFeaturesCount = 1;
+
+        WGPUDevice deviceWithFeature = adapterWithoutFeature.CreateDevice(
+            reinterpret_cast<const WGPUDeviceDescriptor*>(&deviceDescriptor));
         ASSERT_EQ(nullptr, deviceWithFeature);
     }
 }
@@ -68,14 +71,18 @@
     dawn_native::Adapter adapter(&mAdapterBase);
     for (size_t i = 0; i < kTotalFeaturesCount; ++i) {
         dawn_native::Feature feature = static_cast<dawn_native::Feature>(i);
-        const char* featureName = FeatureEnumToName(feature);
+        wgpu::FeatureName featureName = FeatureEnumToAPIFeature(feature);
 
-        dawn_native::DawnDeviceDescriptor deviceDescriptor;
-        deviceDescriptor.requiredFeatures = {featureName};
-        dawn_native::DeviceBase* deviceBase =
-            dawn_native::FromAPI(adapter.CreateDevice(&deviceDescriptor));
-        std::vector<const char*> enabledFeatures = deviceBase->GetEnabledFeatures();
-        ASSERT_EQ(1u, enabledFeatures.size());
-        ASSERT_EQ(0, std::strcmp(featureName, enabledFeatures[0]));
+        wgpu::DeviceDescriptor deviceDescriptor;
+        deviceDescriptor.requiredFeatures = &featureName;
+        deviceDescriptor.requiredFeaturesCount = 1;
+
+        dawn_native::DeviceBase* deviceBase = dawn_native::FromAPI(
+            adapter.CreateDevice(reinterpret_cast<const WGPUDeviceDescriptor*>(&deviceDescriptor)));
+
+        ASSERT_EQ(1u, deviceBase->APIEnumerateFeatures(nullptr));
+        wgpu::FeatureName enabledFeature;
+        deviceBase->APIEnumerateFeatures(&enabledFeature);
+        EXPECT_EQ(enabledFeature, featureName);
     }
 }
diff --git a/src/tests/unittests/GetProcAddressTests.cpp b/src/tests/unittests/GetProcAddressTests.cpp
index 8f90efc..e2c6afd 100644
--- a/src/tests/unittests/GetProcAddressTests.cpp
+++ b/src/tests/unittests/GetProcAddressTests.cpp
@@ -59,7 +59,7 @@
             switch (GetParam()) {
                 case DawnFlavor::Native: {
                     mDevice = wgpu::Device::Acquire(
-                        reinterpret_cast<WGPUDevice>(mNativeAdapter.CreateDevice(nullptr)));
+                        reinterpret_cast<WGPUDevice>(mNativeAdapter.APICreateDevice()));
                     mProcs = dawn_native::GetProcs();
                     break;
                 }
diff --git a/src/tests/unittests/PerThreadProcTests.cpp b/src/tests/unittests/PerThreadProcTests.cpp
index 38ce981..6151a6c 100644
--- a/src/tests/unittests/PerThreadProcTests.cpp
+++ b/src/tests/unittests/PerThreadProcTests.cpp
@@ -57,10 +57,10 @@
 
     // Note: Acquire doesn't call reference or release.
     wgpu::Device deviceA =
-        wgpu::Device::Acquire(reinterpret_cast<WGPUDevice>(mNativeAdapter.CreateDevice(nullptr)));
+        wgpu::Device::Acquire(reinterpret_cast<WGPUDevice>(mNativeAdapter.APICreateDevice()));
 
     wgpu::Device deviceB =
-        wgpu::Device::Acquire(reinterpret_cast<WGPUDevice>(mNativeAdapter.CreateDevice(nullptr)));
+        wgpu::Device::Acquire(reinterpret_cast<WGPUDevice>(mNativeAdapter.APICreateDevice()));
 
     std::thread threadA([&]() {
         DawnProcTable procs = dawn_native::GetProcs();
diff --git a/src/tests/unittests/native/DeviceCreationTests.cpp b/src/tests/unittests/native/DeviceCreationTests.cpp
new file mode 100644
index 0000000..6402286
--- /dev/null
+++ b/src/tests/unittests/native/DeviceCreationTests.cpp
@@ -0,0 +1,115 @@
+// Copyright 2021 The Dawn Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "dawn/dawn_proc.h"
+#include "dawn_native/DawnNative.h"
+#include "tests/MockCallback.h"
+#include "utils/SystemUtils.h"
+#include "utils/WGPUHelpers.h"
+
+#include <gtest/gtest.h>
+
+namespace {
+
+    using namespace testing;
+
+    class DeviceCreationTest : public testing::Test {
+      protected:
+        void SetUp() override {
+            dawnProcSetProcs(&dawn_native::GetProcs());
+
+            instance = std::make_unique<dawn_native::Instance>();
+            instance->DiscoverDefaultAdapters();
+            for (dawn_native::Adapter& nativeAdapter : instance->GetAdapters()) {
+                wgpu::AdapterProperties properties;
+                nativeAdapter.GetProperties(&properties);
+
+                if (properties.backendType == wgpu::BackendType::Null) {
+                    adapter = wgpu::Adapter(nativeAdapter.Get());
+                    break;
+                }
+            }
+            ASSERT_NE(adapter, nullptr);
+        }
+
+        void TearDown() override {
+            adapter = nullptr;
+            instance = nullptr;
+            dawnProcSetProcs(nullptr);
+        }
+
+        std::unique_ptr<dawn_native::Instance> instance;
+        wgpu::Adapter adapter;
+    };
+
+    // Test successful call to CreateDevice with no descriptor
+    TEST_F(DeviceCreationTest, CreateDeviceNoDescriptorSuccess) {
+        wgpu::Device device = adapter.CreateDevice();
+        EXPECT_NE(device, nullptr);
+    }
+
+    // Test successful call to CreateDevice with descriptor.
+    TEST_F(DeviceCreationTest, CreateDeviceSuccess) {
+        wgpu::DeviceDescriptor desc = {};
+        wgpu::Device device = adapter.CreateDevice(&desc);
+        EXPECT_NE(device, nullptr);
+    }
+
+    // Test successful call to CreateDevice with toggle descriptor.
+    TEST_F(DeviceCreationTest, CreateDeviceWithTogglesSuccess) {
+        wgpu::DeviceDescriptor desc = {};
+        wgpu::DawnTogglesDeviceDescriptor togglesDesc = {};
+        desc.nextInChain = &togglesDesc;
+
+        const char* toggle = "skip_validation";
+        togglesDesc.forceEnabledToggles = &toggle;
+        togglesDesc.forceEnabledTogglesCount = 1;
+
+        wgpu::Device device = adapter.CreateDevice(&desc);
+        EXPECT_NE(device, nullptr);
+
+        auto toggles = dawn_native::GetTogglesUsed(device.Get());
+        EXPECT_THAT(toggles, testing::Contains(testing::StrEq(toggle)));
+    }
+
+    // Test successful call to RequestDevice with descriptor
+    TEST_F(DeviceCreationTest, RequestDeviceSuccess) {
+        WGPUDevice cDevice;
+        {
+            MockCallback<WGPURequestDeviceCallback> cb;
+            EXPECT_CALL(cb, Call(WGPURequestDeviceStatus_Success, NotNull(), nullptr, this))
+                .WillOnce(SaveArg<1>(&cDevice));
+
+            wgpu::DeviceDescriptor desc = {};
+            adapter.RequestDevice(&desc, cb.Callback(), cb.MakeUserdata(this));
+        }
+
+        wgpu::Device device = wgpu::Device::Acquire(cDevice);
+        EXPECT_NE(device, nullptr);
+    }
+
+    // Test failing call to RequestDevice with invalid feature
+    TEST_F(DeviceCreationTest, RequestDeviceFailure) {
+        MockCallback<WGPURequestDeviceCallback> cb;
+        EXPECT_CALL(cb, Call(WGPURequestDeviceStatus_Error, nullptr, NotNull(), this)).Times(1);
+
+        wgpu::DeviceDescriptor desc = {};
+        wgpu::FeatureName invalidFeature = static_cast<wgpu::FeatureName>(WGPUFeatureName_Force32);
+        desc.requiredFeatures = &invalidFeature;
+        desc.requiredFeaturesCount = 1;
+
+        adapter.RequestDevice(&desc, cb.Callback(), cb.MakeUserdata(this));
+    }
+
+}  // anonymous namespace
diff --git a/src/tests/white_box/VulkanImageWrappingTestsDmaBuf.cpp b/src/tests/white_box/VulkanImageWrappingTestsDmaBuf.cpp
index f1f3c27..830d5fd 100644
--- a/src/tests/white_box/VulkanImageWrappingTestsDmaBuf.cpp
+++ b/src/tests/white_box/VulkanImageWrappingTestsDmaBuf.cpp
@@ -312,17 +312,21 @@
 
             // Create another device based on the original
             backendAdapter = dawn_native::vulkan::ToBackend(deviceVk->GetAdapter());
-            deviceDescriptor.forceEnabledToggles = GetParam().forceEnabledWorkarounds;
-            deviceDescriptor.forceDisabledToggles = GetParam().forceDisabledWorkarounds;
+            deviceDescriptor.nextInChain = &togglesDesc;
+            togglesDesc.forceEnabledToggles = GetParam().forceEnabledWorkarounds.data();
+            togglesDesc.forceEnabledTogglesCount = GetParam().forceEnabledWorkarounds.size();
+            togglesDesc.forceDisabledToggles = GetParam().forceDisabledWorkarounds.data();
+            togglesDesc.forceDisabledTogglesCount = GetParam().forceDisabledWorkarounds.size();
 
             secondDeviceVk =
-                dawn_native::vulkan::ToBackend(backendAdapter->CreateDevice(&deviceDescriptor));
+                dawn_native::vulkan::ToBackend(backendAdapter->APICreateDevice(&deviceDescriptor));
             secondDevice = wgpu::Device::Acquire(dawn_native::ToAPI(secondDeviceVk));
         }
 
       protected:
         dawn_native::vulkan::Adapter* backendAdapter;
-        dawn_native::DawnDeviceDescriptor deviceDescriptor;
+        dawn_native::DeviceDescriptor deviceDescriptor;
+        dawn_native::DawnTogglesDeviceDescriptor togglesDesc;
 
         wgpu::Device secondDevice;
         dawn_native::vulkan::Device* secondDeviceVk;
@@ -691,7 +695,7 @@
         // device 2 = |secondDevice|
         // Create device 3
         dawn_native::vulkan::Device* thirdDeviceVk =
-            dawn_native::vulkan::ToBackend(backendAdapter->CreateDevice(&deviceDescriptor));
+            dawn_native::vulkan::ToBackend(backendAdapter->APICreateDevice(&deviceDescriptor));
         wgpu::Device thirdDevice = wgpu::Device::Acquire(dawn_native::ToAPI(thirdDeviceVk));
 
         // Make queue for device 2 and 3
diff --git a/src/tests/white_box/VulkanImageWrappingTestsOpaqueFD.cpp b/src/tests/white_box/VulkanImageWrappingTestsOpaqueFD.cpp
index 196c1b0..74c551a 100644
--- a/src/tests/white_box/VulkanImageWrappingTestsOpaqueFD.cpp
+++ b/src/tests/white_box/VulkanImageWrappingTestsOpaqueFD.cpp
@@ -383,11 +383,14 @@
 
             // Create another device based on the original
             backendAdapter = dawn_native::vulkan::ToBackend(deviceVk->GetAdapter());
-            deviceDescriptor.forceEnabledToggles = GetParam().forceEnabledWorkarounds;
-            deviceDescriptor.forceDisabledToggles = GetParam().forceDisabledWorkarounds;
+            deviceDescriptor.nextInChain = &togglesDesc;
+            togglesDesc.forceEnabledToggles = GetParam().forceEnabledWorkarounds.data();
+            togglesDesc.forceEnabledTogglesCount = GetParam().forceEnabledWorkarounds.size();
+            togglesDesc.forceDisabledToggles = GetParam().forceDisabledWorkarounds.data();
+            togglesDesc.forceDisabledTogglesCount = GetParam().forceDisabledWorkarounds.size();
 
             secondDeviceVk =
-                dawn_native::vulkan::ToBackend(backendAdapter->CreateDevice(&deviceDescriptor));
+                dawn_native::vulkan::ToBackend(backendAdapter->APICreateDevice(&deviceDescriptor));
             secondDevice = wgpu::Device::Acquire(dawn_native::ToAPI(secondDeviceVk));
 
             CreateBindExportImage(deviceVk, 1, 1, VK_FORMAT_R8G8B8A8_UNORM, &defaultImage,
@@ -418,7 +421,8 @@
         dawn_native::vulkan::Device* secondDeviceVk;
 
         dawn_native::vulkan::Adapter* backendAdapter;
-        dawn_native::DawnDeviceDescriptor deviceDescriptor;
+        dawn_native::DeviceDescriptor deviceDescriptor;
+        dawn_native::DawnTogglesDeviceDescriptor togglesDesc;
 
         wgpu::TextureDescriptor defaultDescriptor;
         VkImage defaultImage;
@@ -797,7 +801,7 @@
         // device 2 = |secondDevice|
         // Create device 3
         dawn_native::vulkan::Device* thirdDeviceVk =
-            dawn_native::vulkan::ToBackend(backendAdapter->CreateDevice(&deviceDescriptor));
+            dawn_native::vulkan::ToBackend(backendAdapter->APICreateDevice(&deviceDescriptor));
         wgpu::Device thirdDevice = wgpu::Device::Acquire(dawn_native::ToAPI(thirdDeviceVk));
 
         // Make queue for device 2 and 3