Rename "extension" to "feature"

This CL renames "extension" to "feature" to follow WebGPU. It still
supports both. A future Chromium CL will pick this change, then all
"extension" occurrences will be removed.

Change-Id: I070e32d7ae042f9b846df01f200b39f6741a0a14
Bug: dawn:1149
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/65664
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Austin Eng <enga@chromium.org>
Commit-Queue: François Beaufort <beaufort.francois@gmail.com>
diff --git a/dawn.json b/dawn.json
index 3d2c0f7..0bda87b 100644
--- a/dawn.json
+++ b/dawn.json
@@ -1021,6 +1021,7 @@
         "category": "structure",
         "extensible": false,
         "tags": ["dawn"],
+        "_comment": "TODO(dawn:1149): remove 'invalid extension' once it's no longer used.",
         "members": [
             {"name": "device ID", "type": "uint32_t"},
             {"name": "vendor ID", "type": "uint32_t"},
@@ -1033,6 +1034,7 @@
             {"name": "multi planar formats", "type": "bool", "default": "false"},
             {"name": "depth clamping", "type": "bool", "default": "false"},
             {"name": "invalid extension", "type": "bool", "default": "false"},
+            {"name": "invalid feature", "type": "bool", "default": "false"},
             {"name": "dawn internal usages", "type": "bool", "default": "false"},
             {"name": "limits", "type": "supported limits"}
         ]
diff --git a/docs/device_facilities.md b/docs/device_facilities.md
index ae75323..3a2384c 100644
--- a/docs/device_facilities.md
+++ b/docs/device_facilities.md
@@ -94,7 +94,7 @@
 
 ### Format Tables
 
-The frontend has a `Format` structure that represent all the information that are known about a particular WebGPU format for this Device based on the enabled extensions.
+The frontend has a `Format` structure that represent all the information that are known about a particular WebGPU format for this Device based on the enabled features.
 Formats are precomputed at device initialization and can be queried from a WebGPU format either assuming the format is a valid enum, or in a safe manner that doesn't do this assumption.
 A reference to these formats can be stored persistently as they have the same lifetime as the `Device`.
 
diff --git a/docs/extensions/dawn_internal_usages.md b/docs/features/dawn_internal_usages.md
similarity index 78%
rename from docs/extensions/dawn_internal_usages.md
rename to docs/features/dawn_internal_usages.md
index 5655b9a..ec06637 100644
--- a/docs/extensions/dawn_internal_usages.md
+++ b/docs/features/dawn_internal_usages.md
@@ -1,6 +1,6 @@
 # Dawn Internal Usages
 
-The `dawn-internal-usages` extension allows adding additional usage which affects how a texture is allocated, but does not affect frontend validation.
+The `dawn-internal-usages` feature allows adding additional usage which affects how a texture is allocated, but does not affect frontend validation.
 
 One use case for this is so that Chromium can use an internal copyTextureToTexture command to implement copies from a WebGPU texture-backed canvas to other Web platform primitives when the swapchain texture was not explicitly created with CopySrc usage in Javascript.
 
diff --git a/src/dawn_native/Adapter.cpp b/src/dawn_native/Adapter.cpp
index 61912f4..8690f76 100644
--- a/src/dawn_native/Adapter.cpp
+++ b/src/dawn_native/Adapter.cpp
@@ -21,7 +21,7 @@
     AdapterBase::AdapterBase(InstanceBase* instance, wgpu::BackendType backend)
         : mInstance(instance), mBackend(backend) {
         GetDefaultLimits(&mLimits.v1);
-        mSupportedExtensions.EnableExtension(Extension::DawnInternalUsages);
+        mSupportedFeatures.EnableFeature(Feature::DawnInternalUsages);
     }
 
     wgpu::BackendType AdapterBase::GetBackendType() const {
@@ -44,18 +44,18 @@
         return mInstance;
     }
 
-    ExtensionsSet AdapterBase::GetSupportedExtensions() const {
-        return mSupportedExtensions;
+    FeaturesSet AdapterBase::GetSupportedFeatures() const {
+        return mSupportedFeatures;
     }
 
-    bool AdapterBase::SupportsAllRequestedExtensions(
-        const std::vector<const char*>& requestedExtensions) const {
-        for (const char* extensionStr : requestedExtensions) {
-            Extension extensionEnum = mInstance->ExtensionNameToEnum(extensionStr);
-            if (extensionEnum == Extension::InvalidEnum) {
+    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 (!mSupportedExtensions.IsEnabled(extensionEnum)) {
+            if (!mSupportedFeatures.IsEnabled(featureEnum)) {
                 return false;
             }
         }
@@ -67,8 +67,8 @@
         adapterProperties.deviceID = mPCIInfo.deviceId;
         adapterProperties.vendorID = mPCIInfo.vendorId;
 
-        mSupportedExtensions.InitializeDeviceProperties(&adapterProperties);
-        // This is OK for now because there are no limit extension structs.
+        mSupportedFeatures.InitializeDeviceProperties(&adapterProperties);
+        // This is OK for now because there are no limit feature structs.
         // If we add additional structs, the caller will need to provide memory
         // to store them (ex. by calling GetLimits directly instead). Currently,
         // we keep this function as it's only used internally in Chromium to
@@ -121,13 +121,21 @@
     MaybeError AdapterBase::CreateDeviceInternal(DeviceBase** result,
                                                  const DeviceDescriptor* descriptor) {
         if (descriptor != nullptr) {
+            // TODO(dawn:1149): remove once requiredExtensions is no longer used.
             for (const char* extensionStr : descriptor->requiredExtensions) {
-                Extension extensionEnum = mInstance->ExtensionNameToEnum(extensionStr);
-                DAWN_INVALID_IF(extensionEnum == Extension::InvalidEnum,
+                Feature extensionEnum = mInstance->FeatureNameToEnum(extensionStr);
+                DAWN_INVALID_IF(extensionEnum == Feature::InvalidEnum,
                                 "Requested feature %s is unknown.", extensionStr);
-                DAWN_INVALID_IF(!mSupportedExtensions.IsEnabled(extensionEnum),
+                DAWN_INVALID_IF(!mSupportedFeatures.IsEnabled(extensionEnum),
                                 "Requested feature %s is disabled.", extensionStr);
             }
+            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) {
diff --git a/src/dawn_native/Adapter.h b/src/dawn_native/Adapter.h
index b8ba82a..adf230b 100644
--- a/src/dawn_native/Adapter.h
+++ b/src/dawn_native/Adapter.h
@@ -18,7 +18,7 @@
 #include "dawn_native/DawnNative.h"
 
 #include "dawn_native/Error.h"
-#include "dawn_native/Extensions.h"
+#include "dawn_native/Features.h"
 #include "dawn_native/Limits.h"
 #include "dawn_native/dawn_platform.h"
 
@@ -47,9 +47,8 @@
 
         void ResetInternalDeviceForTesting();
 
-        ExtensionsSet GetSupportedExtensions() const;
-        bool SupportsAllRequestedExtensions(
-            const std::vector<const char*>& requestedExtensions) const;
+        FeaturesSet GetSupportedFeatures() const;
+        bool SupportsAllRequestedFeatures(const std::vector<const char*>& requestedFeatures) const;
         WGPUDeviceProperties GetAdapterProperties() const;
 
         bool GetLimits(SupportedLimits* limits) const;
@@ -62,7 +61,7 @@
         PCIInfo mPCIInfo = {};
         wgpu::AdapterType mAdapterType = wgpu::AdapterType::Unknown;
         std::string mDriverDescription;
-        ExtensionsSet mSupportedExtensions;
+        FeaturesSet mSupportedFeatures;
 
       private:
         virtual ResultOrError<DeviceBase*> CreateDeviceImpl(const DeviceDescriptor* descriptor) = 0;
diff --git a/src/dawn_native/BUILD.gn b/src/dawn_native/BUILD.gn
index bcbcbd8..37254d7 100644
--- a/src/dawn_native/BUILD.gn
+++ b/src/dawn_native/BUILD.gn
@@ -248,10 +248,10 @@
     "ErrorInjector.h",
     "ErrorScope.cpp",
     "ErrorScope.h",
-    "Extensions.cpp",
-    "Extensions.h",
     "ExternalTexture.cpp",
     "ExternalTexture.h",
+    "Features.cpp",
+    "Features.h",
     "Format.cpp",
     "Format.h",
     "Forward.h",
diff --git a/src/dawn_native/CMakeLists.txt b/src/dawn_native/CMakeLists.txt
index 3d6e16b..6b90e2c 100644
--- a/src/dawn_native/CMakeLists.txt
+++ b/src/dawn_native/CMakeLists.txt
@@ -94,8 +94,8 @@
     "ErrorInjector.h"
     "ErrorScope.cpp"
     "ErrorScope.h"
-    "Extensions.cpp"
-    "Extensions.h"
+    "Features.cpp"
+    "Features.h"
     "ExternalTexture.cpp"
     "ExternalTexture.h"
     "IndirectDrawMetadata.cpp"
diff --git a/src/dawn_native/DawnNative.cpp b/src/dawn_native/DawnNative.cpp
index 1b2eddc..c1733af 100644
--- a/src/dawn_native/DawnNative.cpp
+++ b/src/dawn_native/DawnNative.cpp
@@ -100,9 +100,14 @@
         return mImpl->GetPCIInfo();
     }
 
+    // TODO(dawn:1149): remove once GetSupportedExtensions() is no longer used.
     std::vector<const char*> Adapter::GetSupportedExtensions() const {
-        ExtensionsSet supportedExtensionsSet = mImpl->GetSupportedExtensions();
-        return supportedExtensionsSet.GetEnabledExtensionNames();
+        return GetSupportedFeatures();
+    }
+
+    std::vector<const char*> Adapter::GetSupportedFeatures() const {
+        FeaturesSet supportedFeaturesSet = mImpl->GetSupportedFeatures();
+        return supportedFeaturesSet.GetEnabledFeatureNames();
     }
 
     WGPUDeviceProperties Adapter::GetAdapterProperties() const {
diff --git a/src/dawn_native/Device.cpp b/src/dawn_native/Device.cpp
index 73fabc3..caff193 100644
--- a/src/dawn_native/Device.cpp
+++ b/src/dawn_native/Device.cpp
@@ -176,7 +176,7 @@
         : mInstance(adapter->GetInstance()), mAdapter(adapter), mNextPipelineCompatibilityToken(1) {
         if (descriptor != nullptr) {
             ApplyToggleOverrides(descriptor);
-            ApplyExtensions(descriptor);
+            ApplyFeatures(descriptor);
         }
 
         if (descriptor != nullptr && descriptor->requiredLimits != nullptr) {
@@ -1049,20 +1049,26 @@
         return result.Detach();
     }
 
-    void DeviceBase::ApplyExtensions(const DeviceDescriptor* deviceDescriptor) {
+    void DeviceBase::ApplyFeatures(const DeviceDescriptor* deviceDescriptor) {
         ASSERT(deviceDescriptor);
-        ASSERT(GetAdapter()->SupportsAllRequestedExtensions(deviceDescriptor->requiredExtensions));
+        // TODO(dawn:1149): remove once requiredExtensions is no longer used.
+        ASSERT(GetAdapter()->SupportsAllRequestedFeatures(deviceDescriptor->requiredExtensions));
+        ASSERT(GetAdapter()->SupportsAllRequestedFeatures(deviceDescriptor->requiredFeatures));
 
-        mEnabledExtensions = GetAdapter()->GetInstance()->ExtensionNamesToExtensionsSet(
+        // TODO(dawn:1149): remove once requiredExtensions is no longer used.
+        mEnabledExtensions = GetAdapter()->GetInstance()->FeatureNamesToFeaturesSet(
             deviceDescriptor->requiredExtensions);
+        mEnabledFeatures = GetAdapter()->GetInstance()->FeatureNamesToFeaturesSet(
+            deviceDescriptor->requiredFeatures);
     }
 
-    std::vector<const char*> DeviceBase::GetEnabledExtensions() const {
-        return mEnabledExtensions.GetEnabledExtensionNames();
+    std::vector<const char*> DeviceBase::GetEnabledFeatures() const {
+        return mEnabledFeatures.GetEnabledFeatureNames();
     }
 
-    bool DeviceBase::IsExtensionEnabled(Extension extension) const {
-        return mEnabledExtensions.IsEnabled(extension);
+    bool DeviceBase::IsFeatureEnabled(Feature feature) const {
+        // TODO(dawn:1149): remove mEnabledExtensions once it is no longer used.
+        return mEnabledFeatures.IsEnabled(feature) || mEnabledExtensions.IsEnabled(feature);
     }
 
     bool DeviceBase::IsValidationEnabled() const {
diff --git a/src/dawn_native/Device.h b/src/dawn_native/Device.h
index 49614c3..eb7c9dc 100644
--- a/src/dawn_native/Device.h
+++ b/src/dawn_native/Device.h
@@ -17,7 +17,7 @@
 
 #include "dawn_native/Commands.h"
 #include "dawn_native/Error.h"
-#include "dawn_native/Extensions.h"
+#include "dawn_native/Features.h"
 #include "dawn_native/Format.h"
 #include "dawn_native/Forward.h"
 #include "dawn_native/Limits.h"
@@ -300,9 +300,9 @@
         bool IsLost() const;
         std::mutex* GetObjectListMutex(ObjectType type);
 
-        std::vector<const char*> GetEnabledExtensions() const;
+        std::vector<const char*> GetEnabledFeatures() const;
         std::vector<const char*> GetTogglesUsed() const;
-        bool IsExtensionEnabled(Extension extension) const;
+        bool IsFeatureEnabled(Feature feature) const;
         bool IsToggleEnabled(Toggle toggle) const;
         bool IsValidationEnabled() const;
         bool IsRobustnessEnabled() const;
@@ -423,7 +423,7 @@
             void* userdata);
 
         void ApplyToggleOverrides(const DeviceDescriptor* deviceDescriptor);
-        void ApplyExtensions(const DeviceDescriptor* deviceDescriptor);
+        void ApplyFeatures(const DeviceDescriptor* deviceDescriptor);
 
         void SetDefaultToggles();
 
@@ -510,7 +510,8 @@
         std::atomic_uint64_t mNextPipelineCompatibilityToken;
 
         CombinedLimits mLimits;
-        ExtensionsSet mEnabledExtensions;
+        FeaturesSet mEnabledExtensions;
+        FeaturesSet mEnabledFeatures;
 
         std::unique_ptr<InternalPipelineStore> mInternalPipelineStore;
 
diff --git a/src/dawn_native/Extensions.cpp b/src/dawn_native/Extensions.cpp
deleted file mode 100644
index 5eeb1a2..0000000
--- a/src/dawn_native/Extensions.cpp
+++ /dev/null
@@ -1,164 +0,0 @@
-// Copyright 2019 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 <array>
-
-#include "common/Assert.h"
-#include "common/BitSetIterator.h"
-#include "dawn_native/Extensions.h"
-
-namespace dawn_native {
-    namespace {
-
-        struct ExtensionEnumAndInfo {
-            Extension extension;
-            ExtensionInfo info;
-            bool WGPUDeviceProperties::*memberInWGPUDeviceProperties;
-        };
-
-        using ExtensionEnumAndInfoList =
-            std::array<ExtensionEnumAndInfo, static_cast<size_t>(Extension::EnumCount)>;
-
-        static constexpr ExtensionEnumAndInfoList kExtensionNameAndInfoList = {
-            {{Extension::TextureCompressionBC,
-              {"texture_compression_bc", "Support Block Compressed (BC) texture formats",
-               "https://bugs.chromium.org/p/dawn/issues/detail?id=42"},
-              &WGPUDeviceProperties::textureCompressionBC},
-             {Extension::TextureCompressionETC2,
-              {"texture-compression-etc2",
-               "Support Ericsson Texture Compressed (ETC2/EAC) texture "
-               "formats",
-               "https://bugs.chromium.org/p/dawn/issues/detail?id=955"},
-              &WGPUDeviceProperties::textureCompressionETC2},
-             {Extension::TextureCompressionASTC,
-              {"texture-compression-astc",
-               "Support Adaptable Scalable Texture Compressed (ASTC) "
-               "texture formats",
-               "https://bugs.chromium.org/p/dawn/issues/detail?id=955"},
-              &WGPUDeviceProperties::textureCompressionASTC},
-             {Extension::ShaderFloat16,
-              {"shader_float16",
-               "Support 16bit float arithmetic and declarations in uniform and storage buffers",
-               "https://bugs.chromium.org/p/dawn/issues/detail?id=426"},
-              &WGPUDeviceProperties::shaderFloat16},
-             {Extension::PipelineStatisticsQuery,
-              {"pipeline_statistics_query", "Support Pipeline Statistics Query",
-               "https://bugs.chromium.org/p/dawn/issues/detail?id=434"},
-              &WGPUDeviceProperties::pipelineStatisticsQuery},
-             {Extension::TimestampQuery,
-              {"timestamp_query", "Support Timestamp Query",
-               "https://bugs.chromium.org/p/dawn/issues/detail?id=434"},
-              &WGPUDeviceProperties::timestampQuery},
-             {Extension::MultiPlanarFormats,
-              {"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},
-             {Extension::DepthClamping,
-              {"depth_clamping", "Clamp depth to [0, 1] in NDC space instead of clipping",
-               "https://bugs.chromium.org/p/dawn/issues/detail?id=716"},
-              &WGPUDeviceProperties::depthClamping},
-             {Extension::DawnInternalUsages,
-              {"dawn-internal-usages",
-               "Add internal usages to resources to affect how the texture is allocated, but not "
-               "frontend validation. Other internal commands may access this usage.",
-               "https://dawn.googlesource.com/dawn/+/refs/heads/main/docs/extensions/"
-               "dawn_internal_usages.md"},
-              &WGPUDeviceProperties::dawnInternalUsages}}};
-
-    }  // anonymous namespace
-
-    void ExtensionsSet::EnableExtension(Extension extension) {
-        ASSERT(extension != Extension::InvalidEnum);
-        const size_t extensionIndex = static_cast<size_t>(extension);
-        extensionsBitSet.set(extensionIndex);
-    }
-
-    bool ExtensionsSet::IsEnabled(Extension extension) const {
-        ASSERT(extension != Extension::InvalidEnum);
-        const size_t extensionIndex = static_cast<size_t>(extension);
-        return extensionsBitSet[extensionIndex];
-    }
-
-    std::vector<const char*> ExtensionsSet::GetEnabledExtensionNames() const {
-        std::vector<const char*> enabledExtensionNames(extensionsBitSet.count());
-
-        uint32_t index = 0;
-        for (uint32_t i : IterateBitSet(extensionsBitSet)) {
-            const char* extensionName = ExtensionEnumToName(static_cast<Extension>(i));
-            enabledExtensionNames[index] = extensionName;
-            ++index;
-        }
-        return enabledExtensionNames;
-    }
-
-    void ExtensionsSet::InitializeDeviceProperties(WGPUDeviceProperties* properties) const {
-        ASSERT(properties != nullptr);
-
-        for (uint32_t i : IterateBitSet(extensionsBitSet)) {
-            properties->*(kExtensionNameAndInfoList[i].memberInWGPUDeviceProperties) = true;
-        }
-    }
-
-    const char* ExtensionEnumToName(Extension extension) {
-        ASSERT(extension != Extension::InvalidEnum);
-
-        const ExtensionEnumAndInfo& extensionNameAndInfo =
-            kExtensionNameAndInfoList[static_cast<size_t>(extension)];
-        ASSERT(extensionNameAndInfo.extension == extension);
-        return extensionNameAndInfo.info.name;
-    }
-
-    ExtensionsInfo::ExtensionsInfo() {
-        for (size_t index = 0; index < kExtensionNameAndInfoList.size(); ++index) {
-            const ExtensionEnumAndInfo& extensionNameAndInfo = kExtensionNameAndInfoList[index];
-            ASSERT(index == static_cast<size_t>(extensionNameAndInfo.extension));
-            mExtensionNameToEnumMap[extensionNameAndInfo.info.name] =
-                extensionNameAndInfo.extension;
-        }
-    }
-
-    const ExtensionInfo* ExtensionsInfo::GetExtensionInfo(const char* extensionName) const {
-        ASSERT(extensionName);
-
-        const auto& iter = mExtensionNameToEnumMap.find(extensionName);
-        if (iter != mExtensionNameToEnumMap.cend()) {
-            return &kExtensionNameAndInfoList[static_cast<size_t>(iter->second)].info;
-        }
-        return nullptr;
-    }
-
-    Extension ExtensionsInfo::ExtensionNameToEnum(const char* extensionName) const {
-        ASSERT(extensionName);
-
-        const auto& iter = mExtensionNameToEnumMap.find(extensionName);
-        if (iter != mExtensionNameToEnumMap.cend()) {
-            return kExtensionNameAndInfoList[static_cast<size_t>(iter->second)].extension;
-        }
-        return Extension::InvalidEnum;
-    }
-
-    ExtensionsSet ExtensionsInfo::ExtensionNamesToExtensionsSet(
-        const std::vector<const char*>& requiredExtensions) const {
-        ExtensionsSet extensionsSet;
-
-        for (const char* extensionName : requiredExtensions) {
-            Extension extensionEnum = ExtensionNameToEnum(extensionName);
-            ASSERT(extensionEnum != Extension::InvalidEnum);
-            extensionsSet.EnableExtension(extensionEnum);
-        }
-        return extensionsSet;
-    }
-
-}  // namespace dawn_native
diff --git a/src/dawn_native/Extensions.h b/src/dawn_native/Extensions.h
deleted file mode 100644
index b862032..0000000
--- a/src/dawn_native/Extensions.h
+++ /dev/null
@@ -1,74 +0,0 @@
-// Copyright 2019 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.
-
-#ifndef DAWNNATIVE_EXTENSIONS_H_
-#define DAWNNATIVE_EXTENSIONS_H_
-
-#include <bitset>
-#include <unordered_map>
-#include <vector>
-
-#include "dawn_native/DawnNative.h"
-
-namespace dawn_native {
-
-    enum class Extension {
-        TextureCompressionBC,
-        TextureCompressionETC2,
-        TextureCompressionASTC,
-        ShaderFloat16,
-        PipelineStatisticsQuery,
-        TimestampQuery,
-        MultiPlanarFormats,
-        DepthClamping,
-
-        // Dawn-specific
-        DawnInternalUsages,
-
-        EnumCount,
-        InvalidEnum = EnumCount,
-        ExtensionMin = TextureCompressionBC,
-    };
-
-    // A wrapper of the bitset to store if an extension is enabled or not. This wrapper provides the
-    // convenience to convert the enums of enum class Extension to the indices of a bitset.
-    struct ExtensionsSet {
-        std::bitset<static_cast<size_t>(Extension::EnumCount)> extensionsBitSet;
-
-        void EnableExtension(Extension extension);
-        bool IsEnabled(Extension extension) const;
-        std::vector<const char*> GetEnabledExtensionNames() const;
-        void InitializeDeviceProperties(WGPUDeviceProperties* properties) const;
-    };
-
-    const char* ExtensionEnumToName(Extension extension);
-
-    class ExtensionsInfo {
-      public:
-        ExtensionsInfo();
-
-        // Used to query the details of an extension. Return nullptr if extensionName is not a valid
-        // name of an extension supported in Dawn
-        const ExtensionInfo* GetExtensionInfo(const char* extensionName) const;
-        Extension ExtensionNameToEnum(const char* extensionName) const;
-        ExtensionsSet ExtensionNamesToExtensionsSet(
-            const std::vector<const char*>& requiredExtensions) const;
-
-      private:
-        std::unordered_map<std::string, Extension> mExtensionNameToEnumMap;
-    };
-
-}  // namespace dawn_native
-
-#endif  // DAWNNATIVE_EXTENSIONS_H_
diff --git a/src/dawn_native/Features.cpp b/src/dawn_native/Features.cpp
new file mode 100644
index 0000000..7b0e8a9
--- /dev/null
+++ b/src/dawn_native/Features.cpp
@@ -0,0 +1,163 @@
+// Copyright 2019 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 <array>
+
+#include "common/Assert.h"
+#include "common/BitSetIterator.h"
+#include "dawn_native/Features.h"
+
+namespace dawn_native {
+    namespace {
+
+        struct FeatureEnumAndInfo {
+            Feature feature;
+            FeatureInfo info;
+            bool WGPUDeviceProperties::*memberInWGPUDeviceProperties;
+        };
+
+        using FeatureEnumAndInfoList =
+            std::array<FeatureEnumAndInfo, static_cast<size_t>(Feature::EnumCount)>;
+
+        static constexpr FeatureEnumAndInfoList kFeatureNameAndInfoList = {
+            {{Feature::TextureCompressionBC,
+              {"texture_compression_bc", "Support Block Compressed (BC) texture formats",
+               "https://bugs.chromium.org/p/dawn/issues/detail?id=42"},
+              &WGPUDeviceProperties::textureCompressionBC},
+             {Feature::TextureCompressionETC2,
+              {"texture-compression-etc2",
+               "Support Ericsson Texture Compressed (ETC2/EAC) texture "
+               "formats",
+               "https://bugs.chromium.org/p/dawn/issues/detail?id=955"},
+              &WGPUDeviceProperties::textureCompressionETC2},
+             {Feature::TextureCompressionASTC,
+              {"texture-compression-astc",
+               "Support Adaptable Scalable Texture Compressed (ASTC) "
+               "texture formats",
+               "https://bugs.chromium.org/p/dawn/issues/detail?id=955"},
+              &WGPUDeviceProperties::textureCompressionASTC},
+             {Feature::ShaderFloat16,
+              {"shader_float16",
+               "Support 16bit float arithmetic and declarations in uniform and storage buffers",
+               "https://bugs.chromium.org/p/dawn/issues/detail?id=426"},
+              &WGPUDeviceProperties::shaderFloat16},
+             {Feature::PipelineStatisticsQuery,
+              {"pipeline_statistics_query", "Support Pipeline Statistics Query",
+               "https://bugs.chromium.org/p/dawn/issues/detail?id=434"},
+              &WGPUDeviceProperties::pipelineStatisticsQuery},
+             {Feature::TimestampQuery,
+              {"timestamp_query", "Support Timestamp Query",
+               "https://bugs.chromium.org/p/dawn/issues/detail?id=434"},
+              &WGPUDeviceProperties::timestampQuery},
+             {Feature::DepthClamping,
+              {"depth_clamping", "Clamp depth to [0, 1] in NDC space instead of clipping",
+               "https://bugs.chromium.org/p/dawn/issues/detail?id=716"},
+              &WGPUDeviceProperties::depthClamping},
+             {Feature::DawnInternalUsages,
+              {"dawn-internal-usages",
+               "Add internal usages to resources to affect how the texture is allocated, but not "
+               "frontend validation. Other internal commands may access this usage.",
+               "https://dawn.googlesource.com/dawn/+/refs/heads/main/docs/features/"
+               "dawn_internal_usages.md"},
+              &WGPUDeviceProperties::dawnInternalUsages},
+             {Feature::MultiPlanarFormats,
+              {"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}}};
+
+    }  // anonymous namespace
+
+    void FeaturesSet::EnableFeature(Feature feature) {
+        ASSERT(feature != Feature::InvalidEnum);
+        const size_t featureIndex = static_cast<size_t>(feature);
+        featuresBitSet.set(featureIndex);
+    }
+
+    bool FeaturesSet::IsEnabled(Feature feature) const {
+        ASSERT(feature != Feature::InvalidEnum);
+        const size_t featureIndex = static_cast<size_t>(feature);
+        return featuresBitSet[featureIndex];
+    }
+
+    std::vector<const char*> FeaturesSet::GetEnabledFeatureNames() const {
+        std::vector<const char*> enabledFeatureNames(featuresBitSet.count());
+
+        uint32_t index = 0;
+        for (uint32_t i : IterateBitSet(featuresBitSet)) {
+            const char* featureName = FeatureEnumToName(static_cast<Feature>(i));
+            enabledFeatureNames[index] = featureName;
+            ++index;
+        }
+        return enabledFeatureNames;
+    }
+
+    void FeaturesSet::InitializeDeviceProperties(WGPUDeviceProperties* properties) const {
+        ASSERT(properties != nullptr);
+
+        for (uint32_t i : IterateBitSet(featuresBitSet)) {
+            properties->*(kFeatureNameAndInfoList[i].memberInWGPUDeviceProperties) = true;
+        }
+    }
+
+    const char* FeatureEnumToName(Feature feature) {
+        ASSERT(feature != Feature::InvalidEnum);
+
+        const FeatureEnumAndInfo& featureNameAndInfo =
+            kFeatureNameAndInfoList[static_cast<size_t>(feature)];
+        ASSERT(featureNameAndInfo.feature == feature);
+        return featureNameAndInfo.info.name;
+    }
+
+    FeaturesInfo::FeaturesInfo() {
+        for (size_t index = 0; index < kFeatureNameAndInfoList.size(); ++index) {
+            const FeatureEnumAndInfo& featureNameAndInfo = kFeatureNameAndInfoList[index];
+            ASSERT(index == static_cast<size_t>(featureNameAndInfo.feature));
+            mFeatureNameToEnumMap[featureNameAndInfo.info.name] = featureNameAndInfo.feature;
+        }
+    }
+
+    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;
+        }
+        return nullptr;
+    }
+
+    Feature FeaturesInfo::FeatureNameToEnum(const char* featureName) const {
+        ASSERT(featureName);
+
+        const auto& iter = mFeatureNameToEnumMap.find(featureName);
+        if (iter != mFeatureNameToEnumMap.cend()) {
+            return kFeatureNameAndInfoList[static_cast<size_t>(iter->second)].feature;
+        }
+        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);
+        }
+        return featuresSet;
+    }
+
+}  // namespace dawn_native
diff --git a/src/dawn_native/Features.h b/src/dawn_native/Features.h
new file mode 100644
index 0000000..35bdf4f
--- /dev/null
+++ b/src/dawn_native/Features.h
@@ -0,0 +1,74 @@
+// Copyright 2019 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.
+
+#ifndef DAWNNATIVE_FEATURES_H_
+#define DAWNNATIVE_FEATURES_H_
+
+#include <bitset>
+#include <unordered_map>
+#include <vector>
+
+#include "dawn_native/DawnNative.h"
+
+namespace dawn_native {
+
+    enum class Feature {
+        TextureCompressionBC,
+        TextureCompressionETC2,
+        TextureCompressionASTC,
+        ShaderFloat16,
+        PipelineStatisticsQuery,
+        TimestampQuery,
+        DepthClamping,
+
+        // Dawn-specific
+        DawnInternalUsages,
+        MultiPlanarFormats,
+
+        EnumCount,
+        InvalidEnum = EnumCount,
+        FeatureMin = TextureCompressionBC,
+    };
+
+    // A wrapper of the bitset to store if an feature is enabled or not. This wrapper provides the
+    // convenience to convert the enums of enum class Feature to the indices of a bitset.
+    struct FeaturesSet {
+        std::bitset<static_cast<size_t>(Feature::EnumCount)> featuresBitSet;
+
+        void EnableFeature(Feature feature);
+        bool IsEnabled(Feature feature) const;
+        std::vector<const char*> GetEnabledFeatureNames() const;
+        void InitializeDeviceProperties(WGPUDeviceProperties* properties) const;
+    };
+
+    const char* FeatureEnumToName(Feature feature);
+
+    class FeaturesInfo {
+      public:
+        FeaturesInfo();
+
+        // 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;
+        Feature FeatureNameToEnum(const char* featureName) const;
+        FeaturesSet FeatureNamesToFeaturesSet(
+            const std::vector<const char*>& requiredFeatures) const;
+
+      private:
+        std::unordered_map<std::string, Feature> mFeatureNameToEnumMap;
+    };
+
+}  // namespace dawn_native
+
+#endif  // DAWNNATIVE_FEATURES_H_
diff --git a/src/dawn_native/Format.cpp b/src/dawn_native/Format.cpp
index f61c630..e9cde21 100644
--- a/src/dawn_native/Format.cpp
+++ b/src/dawn_native/Format.cpp
@@ -16,7 +16,7 @@
 
 #include "dawn_native/Device.h"
 #include "dawn_native/EnumMaskIterator.h"
-#include "dawn_native/Extensions.h"
+#include "dawn_native/Features.h"
 #include "dawn_native/Texture.h"
 
 #include <bitset>
@@ -122,7 +122,7 @@
 
     // Implementation details of the format table of the DeviceBase
 
-    // For the enum for formats are packed but this might change when we have a broader extension
+    // For the enum for formats are packed but this might change when we have a broader feature
     // mechanism for webgpu.h. Formats start at 1 because 0 is the undefined format.
     size_t ComputeFormatIndex(wgpu::TextureFormat format) {
         // This takes advantage of overflows to make the index of TextureFormat::Undefined outside
@@ -340,7 +340,7 @@
         // TODO(dawn:690): Implement Depth24UnormStencil8, Depth32FloatStencil8.
 
         // BC compressed formats
-        bool isBCFormatSupported = device->IsExtensionEnabled(Extension::TextureCompressionBC);
+        bool isBCFormatSupported = device->IsFeatureEnabled(Feature::TextureCompressionBC);
         AddCompressedFormat(wgpu::TextureFormat::BC1RGBAUnorm, 8, 4, 4, isBCFormatSupported, 4);
         AddCompressedFormat(wgpu::TextureFormat::BC1RGBAUnormSrgb, 8, 4, 4, isBCFormatSupported, 4);
         AddCompressedFormat(wgpu::TextureFormat::BC4RSnorm, 8, 4, 4, isBCFormatSupported, 1);
@@ -357,7 +357,7 @@
         AddCompressedFormat(wgpu::TextureFormat::BC7RGBAUnormSrgb, 16, 4, 4, isBCFormatSupported, 4);
 
         // ETC2/EAC compressed formats
-        bool isETC2FormatSupported = device->IsExtensionEnabled(Extension::TextureCompressionETC2);
+        bool isETC2FormatSupported = device->IsFeatureEnabled(Feature::TextureCompressionETC2);
         AddCompressedFormat(wgpu::TextureFormat::ETC2RGB8Unorm, 8, 4, 4, isETC2FormatSupported, 3);
         AddCompressedFormat(wgpu::TextureFormat::ETC2RGB8UnormSrgb, 8, 4, 4, isETC2FormatSupported, 3);
         AddCompressedFormat(wgpu::TextureFormat::ETC2RGB8A1Unorm, 8, 4, 4, isETC2FormatSupported, 4);
@@ -370,7 +370,7 @@
         AddCompressedFormat(wgpu::TextureFormat::EACRG11Snorm, 16, 4, 4, isETC2FormatSupported, 2);
 
         // ASTC compressed formats
-        bool isASTCFormatSupported = device->IsExtensionEnabled(Extension::TextureCompressionASTC);
+        bool isASTCFormatSupported = device->IsFeatureEnabled(Feature::TextureCompressionASTC);
         AddCompressedFormat(wgpu::TextureFormat::ASTC4x4Unorm, 16, 4, 4, isASTCFormatSupported, 4);
         AddCompressedFormat(wgpu::TextureFormat::ASTC4x4UnormSrgb, 16, 4, 4, isASTCFormatSupported, 4);
         AddCompressedFormat(wgpu::TextureFormat::ASTC5x4Unorm, 16, 5, 4, isASTCFormatSupported, 4);
@@ -401,7 +401,7 @@
         AddCompressedFormat(wgpu::TextureFormat::ASTC12x12UnormSrgb, 16, 12, 12, isASTCFormatSupported, 4);
 
         // multi-planar formats
-        const bool isMultiPlanarFormatSupported = device->IsExtensionEnabled(Extension::MultiPlanarFormats);
+        const bool isMultiPlanarFormatSupported = device->IsFeatureEnabled(Feature::MultiPlanarFormats);
         AddMultiAspectFormat(wgpu::TextureFormat::R8BG8Biplanar420Unorm, Aspect::Plane0 | Aspect::Plane1,
             wgpu::TextureFormat::R8Unorm, wgpu::TextureFormat::RG8Unorm, false, isMultiPlanarFormatSupported, 3);
 
diff --git a/src/dawn_native/Instance.cpp b/src/dawn_native/Instance.cpp
index a89396a..936471e 100644
--- a/src/dawn_native/Instance.cpp
+++ b/src/dawn_native/Instance.cpp
@@ -105,17 +105,17 @@
         return mTogglesInfo.ToggleNameToEnum(toggleName);
     }
 
-    const ExtensionInfo* InstanceBase::GetExtensionInfo(const char* extensionName) {
-        return mExtensionsInfo.GetExtensionInfo(extensionName);
+    const FeatureInfo* InstanceBase::GetFeatureInfo(const char* featureName) {
+        return mFeaturesInfo.GetFeatureInfo(featureName);
     }
 
-    Extension InstanceBase::ExtensionNameToEnum(const char* extensionName) {
-        return mExtensionsInfo.ExtensionNameToEnum(extensionName);
+    Feature InstanceBase::FeatureNameToEnum(const char* featureName) {
+        return mFeaturesInfo.FeatureNameToEnum(featureName);
     }
 
-    ExtensionsSet InstanceBase::ExtensionNamesToExtensionsSet(
-        const std::vector<const char*>& requiredExtensions) {
-        return mExtensionsInfo.ExtensionNamesToExtensionsSet(requiredExtensions);
+    FeaturesSet InstanceBase::FeatureNamesToFeaturesSet(
+        const std::vector<const char*>& requiredFeatures) {
+        return mFeaturesInfo.FeatureNamesToFeaturesSet(requiredFeatures);
     }
 
     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 4684e12..3451967 100644
--- a/src/dawn_native/Instance.h
+++ b/src/dawn_native/Instance.h
@@ -18,7 +18,7 @@
 #include "common/RefCounted.h"
 #include "dawn_native/Adapter.h"
 #include "dawn_native/BackendConnection.h"
-#include "dawn_native/Extensions.h"
+#include "dawn_native/Features.h"
 #include "dawn_native/Toggles.h"
 #include "dawn_native/dawn_platform.h"
 
@@ -55,12 +55,11 @@
         const ToggleInfo* GetToggleInfo(const char* toggleName);
         Toggle ToggleNameToEnum(const char* toggleName);
 
-        // Used to query the details of an extension. Return nullptr if extensionName is not a valid
-        // name of an extension supported in Dawn.
-        const ExtensionInfo* GetExtensionInfo(const char* extensionName);
-        Extension ExtensionNameToEnum(const char* extensionName);
-        ExtensionsSet ExtensionNamesToExtensionsSet(
-            const std::vector<const char*>& requiredExtensions);
+        // 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);
 
         bool IsBackendValidationEnabled() const;
         void SetBackendValidationLevel(BackendValidationLevel level);
@@ -104,7 +103,7 @@
         std::vector<std::unique_ptr<BackendConnection>> mBackends;
         std::vector<std::unique_ptr<AdapterBase>> mAdapters;
 
-        ExtensionsInfo mExtensionsInfo;
+        FeaturesInfo mFeaturesInfo;
         TogglesInfo mTogglesInfo;
 
 #if defined(DAWN_USE_X11)
diff --git a/src/dawn_native/QuerySet.cpp b/src/dawn_native/QuerySet.cpp
index ed8bc48..2ad7cd7 100644
--- a/src/dawn_native/QuerySet.cpp
+++ b/src/dawn_native/QuerySet.cpp
@@ -15,7 +15,7 @@
 #include "dawn_native/QuerySet.h"
 
 #include "dawn_native/Device.h"
-#include "dawn_native/Extensions.h"
+#include "dawn_native/Features.h"
 #include "dawn_native/ObjectType_autogen.h"
 #include "dawn_native/ValidationUtils_autogen.h"
 
@@ -63,8 +63,8 @@
                                 "fully implemented");
 
                 DAWN_INVALID_IF(
-                    !device->IsExtensionEnabled(Extension::PipelineStatisticsQuery),
-                    "Pipeline statistics query set created without the extension being enabled.");
+                    !device->IsFeatureEnabled(Feature::PipelineStatisticsQuery),
+                    "Pipeline statistics query set created without the feature being enabled.");
 
                 DAWN_INVALID_IF(descriptor->pipelineStatisticsCount == 0,
                                 "Pipeline statistics query set created with 0 statistics.");
@@ -85,8 +85,8 @@
                                 "Timestamp queries are disallowed because they may expose precise "
                                 "timing information.");
 
-                DAWN_INVALID_IF(!device->IsExtensionEnabled(Extension::TimestampQuery),
-                                "Timestamp query set created without the extension being enabled.");
+                DAWN_INVALID_IF(!device->IsFeatureEnabled(Feature::TimestampQuery),
+                                "Timestamp query set created without the feature being enabled.");
 
                 DAWN_INVALID_IF(descriptor->pipelineStatisticsCount != 0,
                                 "Pipeline statistics specified for a query of type %s.",
diff --git a/src/dawn_native/RenderPipeline.cpp b/src/dawn_native/RenderPipeline.cpp
index ea2f193..2ad7a22 100644
--- a/src/dawn_native/RenderPipeline.cpp
+++ b/src/dawn_native/RenderPipeline.cpp
@@ -240,7 +240,7 @@
                 wgpu::SType::PrimitiveDepthClampingState));
             const PrimitiveDepthClampingState* clampInfo = nullptr;
             FindInChain(descriptor->nextInChain, &clampInfo);
-            if (clampInfo && !device->IsExtensionEnabled(Extension::DepthClamping)) {
+            if (clampInfo && !device->IsFeatureEnabled(Feature::DepthClamping)) {
                 return DAWN_VALIDATION_ERROR("The depth clamping feature is not supported");
             }
             DAWN_TRY(ValidatePrimitiveTopology(descriptor->topology));
diff --git a/src/dawn_native/Texture.cpp b/src/dawn_native/Texture.cpp
index 8b005ad..508beaa 100644
--- a/src/dawn_native/Texture.cpp
+++ b/src/dawn_native/Texture.cpp
@@ -273,9 +273,9 @@
         DAWN_INVALID_IF(descriptor->dimension == wgpu::TextureDimension::e1D,
                         "1D textures aren't supported (yet).");
 
-        DAWN_INVALID_IF(internalUsageDesc != nullptr &&
-                            !device->IsExtensionEnabled(Extension::DawnInternalUsages),
-                        "The dawn-internal-usages feature is not enabled");
+        DAWN_INVALID_IF(
+            internalUsageDesc != nullptr && !device->IsFeatureEnabled(Feature::DawnInternalUsages),
+            "The dawn-internal-usages feature is not enabled");
 
         const Format* format;
         DAWN_TRY_ASSIGN(format, device->GetInternalFormat(descriptor->format));
@@ -434,7 +434,7 @@
     }
 
     // WebGPU only supports sample counts of 1 and 4. We could expand to more based on
-    // platform support, but it would probably be an extension.
+    // platform support, but it would probably be a feature.
     bool IsValidSampleCount(uint32_t sampleCount) {
         switch (sampleCount) {
             case 1:
diff --git a/src/dawn_native/d3d12/AdapterD3D12.cpp b/src/dawn_native/d3d12/AdapterD3D12.cpp
index 7021b59..67f5066 100644
--- a/src/dawn_native/d3d12/AdapterD3D12.cpp
+++ b/src/dawn_native/d3d12/AdapterD3D12.cpp
@@ -104,7 +104,7 @@
             mDriverDescription = o.str();
         }
 
-        InitializeSupportedExtensions();
+        InitializeSupportedFeatures();
 
         return {};
     }
@@ -130,13 +130,13 @@
         return true;
     }
 
-    void Adapter::InitializeSupportedExtensions() {
+    void Adapter::InitializeSupportedFeatures() {
         if (AreTimestampQueriesSupported()) {
-            mSupportedExtensions.EnableExtension(Extension::TimestampQuery);
+            mSupportedFeatures.EnableFeature(Feature::TimestampQuery);
         }
-        mSupportedExtensions.EnableExtension(Extension::TextureCompressionBC);
-        mSupportedExtensions.EnableExtension(Extension::PipelineStatisticsQuery);
-        mSupportedExtensions.EnableExtension(Extension::MultiPlanarFormats);
+        mSupportedFeatures.EnableFeature(Feature::TextureCompressionBC);
+        mSupportedFeatures.EnableFeature(Feature::PipelineStatisticsQuery);
+        mSupportedFeatures.EnableFeature(Feature::MultiPlanarFormats);
     }
 
     MaybeError Adapter::InitializeDebugLayerFilters() {
diff --git a/src/dawn_native/d3d12/AdapterD3D12.h b/src/dawn_native/d3d12/AdapterD3D12.h
index 1e3654e..9c3d8f4 100644
--- a/src/dawn_native/d3d12/AdapterD3D12.h
+++ b/src/dawn_native/d3d12/AdapterD3D12.h
@@ -47,7 +47,7 @@
 
         bool AreTimestampQueriesSupported() const;
 
-        void InitializeSupportedExtensions();
+        void InitializeSupportedFeatures();
         MaybeError InitializeDebugLayerFilters();
         void CleanUpDebugLayerFilters();
 
diff --git a/src/dawn_native/d3d12/DeviceD3D12.cpp b/src/dawn_native/d3d12/DeviceD3D12.cpp
index 8c3358b..3b96092 100644
--- a/src/dawn_native/d3d12/DeviceD3D12.cpp
+++ b/src/dawn_native/d3d12/DeviceD3D12.cpp
@@ -73,7 +73,7 @@
             CheckHRESULT(mD3d12Device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&mCommandQueue)),
                          "D3D12 create command queue"));
 
-        if (IsExtensionEnabled(Extension::TimestampQuery)) {
+        if (IsFeatureEnabled(Feature::TimestampQuery)) {
             // Get GPU timestamp counter frequency (in ticks/second). This fails if the specified
             // command queue doesn't support timestamps. D3D12_COMMAND_LIST_TYPE_DIRECT queues
             // always support timestamps except where there are bugs in Windows container and vGPU
@@ -203,7 +203,7 @@
     MaybeError Device::ApplyUseDxcToggle() {
         if (!ToBackend(GetAdapter())->GetBackend()->GetFunctions()->IsDXCAvailable()) {
             ForceSetToggle(Toggle::UseDXC, false);
-        } else if (IsExtensionEnabled(Extension::ShaderFloat16)) {
+        } else if (IsFeatureEnabled(Feature::ShaderFloat16)) {
             // Currently we can only use DXC to compile HLSL shaders using float16.
             ForceSetToggle(Toggle::UseDXC, true);
         }
diff --git a/src/dawn_native/d3d12/ShaderModuleD3D12.cpp b/src/dawn_native/d3d12/ShaderModuleD3D12.cpp
index d601325..5332623 100644
--- a/src/dawn_native/d3d12/ShaderModuleD3D12.cpp
+++ b/src/dawn_native/d3d12/ShaderModuleD3D12.cpp
@@ -116,7 +116,7 @@
             // DXC inputs
             uint64_t dxcVersion;
             const D3D12DeviceInfo* deviceInfo;
-            bool hasShaderFloat16Extension;
+            bool hasShaderFloat16Feature;
 
             static ResultOrError<ShaderCompilationRequest> Create(
                 const char* entryPointName,
@@ -192,8 +192,7 @@
                 request.fxcVersion = compiler == Compiler::FXC ? GetD3DCompilerVersion() : 0;
                 request.dxcVersion = compiler == Compiler::DXC ? dxcVersion : 0;
                 request.deviceInfo = &device->GetDeviceInfo();
-                request.hasShaderFloat16Extension =
-                    device->IsExtensionEnabled(Extension::ShaderFloat16);
+                request.hasShaderFloat16Feature = device->IsFeatureEnabled(Feature::ShaderFloat16);
                 return std::move(request);
             }
 
@@ -240,7 +239,7 @@
                 stream << " isRobustnessEnabled=" << isRobustnessEnabled;
                 stream << " fxcVersion=" << fxcVersion;
                 stream << " dxcVersion=" << dxcVersion;
-                stream << " hasShaderFloat16Extension=" << hasShaderFloat16Extension;
+                stream << " hasShaderFloat16Feature=" << hasShaderFloat16Feature;
                 stream << ")";
                 stream << "\n";
 
@@ -314,7 +313,7 @@
             DAWN_TRY_ASSIGN(entryPointW, ConvertStringToWstring(request.entryPointName));
 
             std::vector<const wchar_t*> arguments =
-                GetDXCArguments(request.compileFlags, request.hasShaderFloat16Extension);
+                GetDXCArguments(request.compileFlags, request.hasShaderFloat16Feature);
 
             ComPtr<IDxcOperationResult> result;
             DAWN_TRY(CheckHRESULT(
diff --git a/src/dawn_native/metal/BackendMTL.mm b/src/dawn_native/metal/BackendMTL.mm
index 4cffa1b..d250698 100644
--- a/src/dawn_native/metal/BackendMTL.mm
+++ b/src/dawn_native/metal/BackendMTL.mm
@@ -264,7 +264,7 @@
             mDriverDescription =
                 "Metal driver on " + std::string(systemName) + [osVersion UTF8String];
 
-            InitializeSupportedExtensions();
+            InitializeSupportedFeatures();
         }
 
         // AdapterBase Implementation
@@ -278,10 +278,10 @@
             return Device::Create(this, mDevice, descriptor);
         }
 
-        void InitializeSupportedExtensions() {
+        void InitializeSupportedFeatures() {
 #if defined(DAWN_PLATFORM_MACOS)
             if ([*mDevice supportsFeatureSet:MTLFeatureSet_macOS_GPUFamily1_v1]) {
-                mSupportedExtensions.EnableExtension(Extension::TextureCompressionBC);
+                mSupportedFeatures.EnableFeature(Feature::TextureCompressionBC);
             }
 #endif
 
@@ -291,7 +291,7 @@
                         {MTLCommonCounterVertexInvocations, MTLCommonCounterClipperInvocations,
                          MTLCommonCounterClipperPrimitivesOut, MTLCommonCounterFragmentInvocations,
                          MTLCommonCounterComputeKernelInvocations})) {
-                    mSupportedExtensions.EnableExtension(Extension::PipelineStatisticsQuery);
+                    mSupportedFeatures.EnableFeature(Feature::PipelineStatisticsQuery);
                 }
 
                 if (IsGPUCounterSupported(*mDevice, MTLCommonCounterSetTimestamp,
@@ -306,13 +306,13 @@
                     enableTimestampQuery &= !IsMacOSVersionAtLeast(11);
 #endif
                     if (enableTimestampQuery) {
-                        mSupportedExtensions.EnableExtension(Extension::TimestampQuery);
+                        mSupportedFeatures.EnableFeature(Feature::TimestampQuery);
                     }
                 }
             }
 
             if (@available(macOS 10.11, iOS 11.0, *)) {
-                mSupportedExtensions.EnableExtension(Extension::DepthClamping);
+                mSupportedFeatures.EnableFeature(Feature::DepthClamping);
             }
         }
 
diff --git a/src/dawn_native/metal/DeviceMTL.mm b/src/dawn_native/metal/DeviceMTL.mm
index 91b0984..67ce44b 100644
--- a/src/dawn_native/metal/DeviceMTL.mm
+++ b/src/dawn_native/metal/DeviceMTL.mm
@@ -134,7 +134,7 @@
 
         DAWN_TRY(mCommandContext.PrepareNextCommandBuffer(*mCommandQueue));
 
-        if (IsExtensionEnabled(Extension::TimestampQuery)) {
+        if (IsFeatureEnabled(Feature::TimestampQuery)) {
             // Make a best guess of timestamp period based on device vendor info, and converge it to
             // an accurate value by the following calculations.
             mTimestampPeriod =
@@ -312,8 +312,8 @@
     MaybeError Device::TickImpl() {
         DAWN_TRY(SubmitPendingCommandBuffer());
 
-        // Just run timestamp period calculation when timestamp extension is enabled.
-        if (IsExtensionEnabled(Extension::TimestampQuery)) {
+        // Just run timestamp period calculation when timestamp feature is enabled.
+        if (IsFeatureEnabled(Feature::TimestampQuery)) {
             if (@available(macos 10.15, iOS 14.0, *)) {
                 UpdateTimestampPeriod(GetMTLDevice(), mKalmanInfo.get(), &mCpuTimestamp,
                                       &mGpuTimestamp, &mTimestampPeriod);
diff --git a/src/dawn_native/null/DeviceNull.cpp b/src/dawn_native/null/DeviceNull.cpp
index 5ee1ef0..ab6ec33 100644
--- a/src/dawn_native/null/DeviceNull.cpp
+++ b/src/dawn_native/null/DeviceNull.cpp
@@ -28,8 +28,8 @@
         mPCIInfo.name = "Null backend";
         mAdapterType = wgpu::AdapterType::CPU;
 
-        // Enable all extensions by default for the convenience of tests.
-        mSupportedExtensions.extensionsBitSet.set();
+        // Enable all features by default for the convenience of tests.
+        mSupportedFeatures.featuresBitSet.set();
     }
 
     Adapter::~Adapter() = default;
@@ -38,9 +38,9 @@
         return false;
     }
 
-    // Used for the tests that intend to use an adapter without all extensions enabled.
-    void Adapter::SetSupportedExtensions(const std::vector<const char*>& requiredExtensions) {
-        mSupportedExtensions = GetInstance()->ExtensionNamesToExtensionsSet(requiredExtensions);
+    // 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);
     }
 
     ResultOrError<DeviceBase*> Adapter::CreateDeviceImpl(const DeviceDescriptor* descriptor) {
diff --git a/src/dawn_native/null/DeviceNull.h b/src/dawn_native/null/DeviceNull.h
index 834684f..c51152d 100644
--- a/src/dawn_native/null/DeviceNull.h
+++ b/src/dawn_native/null/DeviceNull.h
@@ -173,8 +173,8 @@
         // AdapterBase Implementation
         bool SupportsExternalImages() const override;
 
-        // Used for the tests that intend to use an adapter without all extensions enabled.
-        void SetSupportedExtensions(const std::vector<const char*>& requiredExtensions);
+        // Used for the tests that intend to use an adapter without all features enabled.
+        void SetSupportedFeatures(const std::vector<const char*>& requiredFeatures);
 
       private:
         ResultOrError<DeviceBase*> CreateDeviceImpl(const DeviceDescriptor* descriptor) override;
diff --git a/src/dawn_native/opengl/BackendGL.cpp b/src/dawn_native/opengl/BackendGL.cpp
index c2b24be..b92599e 100644
--- a/src/dawn_native/opengl/BackendGL.cpp
+++ b/src/dawn_native/opengl/BackendGL.cpp
@@ -187,7 +187,7 @@
                 mAdapterType = wgpu::AdapterType::CPU;
             }
 
-            InitializeSupportedExtensions();
+            InitializeSupportedFeatures();
 
             return {};
         }
@@ -209,7 +209,7 @@
             return Device::Create(this, descriptor, mFunctions);
         }
 
-        void InitializeSupportedExtensions() {
+        void InitializeSupportedFeatures() {
             // TextureCompressionBC
             {
                 // BC1, BC2 and BC3 are not supported in OpenGL or OpenGL ES core features.
@@ -249,8 +249,7 @@
 
                 if (supportsS3TC && (supportsTextureSRGB || supportsS3TCSRGB) && supportsRGTC &&
                     supportsBPTC) {
-                    mSupportedExtensions.EnableExtension(
-                        dawn_native::Extension::TextureCompressionBC);
+                    mSupportedFeatures.EnableFeature(dawn_native::Feature::TextureCompressionBC);
                 }
             }
         }
diff --git a/src/dawn_native/vulkan/AdapterVk.cpp b/src/dawn_native/vulkan/AdapterVk.cpp
index eee984e..55a2473 100644
--- a/src/dawn_native/vulkan/AdapterVk.cpp
+++ b/src/dawn_native/vulkan/AdapterVk.cpp
@@ -53,7 +53,7 @@
                 "Vulkan driver version: " + std::to_string(mDeviceInfo.properties.driverVersion);
         }
 
-        InitializeSupportedExtensions();
+        InitializeSupportedFeatures();
 
         mPCIInfo.deviceId = mDeviceInfo.properties.deviceID;
         mPCIInfo.vendorId = mDeviceInfo.properties.vendorID;
@@ -257,29 +257,29 @@
                                                          mBackend->GetFunctions());
     }
 
-    void Adapter::InitializeSupportedExtensions() {
+    void Adapter::InitializeSupportedFeatures() {
         if (mDeviceInfo.features.textureCompressionBC == VK_TRUE) {
-            mSupportedExtensions.EnableExtension(Extension::TextureCompressionBC);
+            mSupportedFeatures.EnableFeature(Feature::TextureCompressionBC);
         }
 
         if (mDeviceInfo.features.textureCompressionETC2 == VK_TRUE) {
-            mSupportedExtensions.EnableExtension(Extension::TextureCompressionETC2);
+            mSupportedFeatures.EnableFeature(Feature::TextureCompressionETC2);
         }
 
         if (mDeviceInfo.features.textureCompressionASTC_LDR == VK_TRUE) {
-            mSupportedExtensions.EnableExtension(Extension::TextureCompressionASTC);
+            mSupportedFeatures.EnableFeature(Feature::TextureCompressionASTC);
         }
 
         if (mDeviceInfo.features.pipelineStatisticsQuery == VK_TRUE) {
-            mSupportedExtensions.EnableExtension(Extension::PipelineStatisticsQuery);
+            mSupportedFeatures.EnableFeature(Feature::PipelineStatisticsQuery);
         }
 
         if (mDeviceInfo.features.depthClamp == VK_TRUE) {
-            mSupportedExtensions.EnableExtension(Extension::DepthClamping);
+            mSupportedFeatures.EnableFeature(Feature::DepthClamping);
         }
 
         if (mDeviceInfo.properties.limits.timestampComputeAndGraphics == VK_TRUE) {
-            mSupportedExtensions.EnableExtension(Extension::TimestampQuery);
+            mSupportedFeatures.EnableFeature(Feature::TimestampQuery);
         }
     }
 
diff --git a/src/dawn_native/vulkan/AdapterVk.h b/src/dawn_native/vulkan/AdapterVk.h
index a6141c4..47679e8 100644
--- a/src/dawn_native/vulkan/AdapterVk.h
+++ b/src/dawn_native/vulkan/AdapterVk.h
@@ -41,7 +41,7 @@
       private:
         ResultOrError<DeviceBase*> CreateDeviceImpl(const DeviceDescriptor* descriptor) override;
         MaybeError CheckCoreWebGPUSupport();
-        void InitializeSupportedExtensions();
+        void InitializeSupportedFeatures();
 
         VkPhysicalDevice mPhysicalDevice;
         Backend* mBackend;
diff --git a/src/dawn_native/vulkan/DeviceVk.cpp b/src/dawn_native/vulkan/DeviceVk.cpp
index 2f879de..1834ae6 100644
--- a/src/dawn_native/vulkan/DeviceVk.cpp
+++ b/src/dawn_native/vulkan/DeviceVk.cpp
@@ -348,31 +348,31 @@
             usedKnobs.features.samplerAnisotropy = VK_TRUE;
         }
 
-        if (IsExtensionEnabled(Extension::TextureCompressionBC)) {
+        if (IsFeatureEnabled(Feature::TextureCompressionBC)) {
             ASSERT(ToBackend(GetAdapter())->GetDeviceInfo().features.textureCompressionBC ==
                    VK_TRUE);
             usedKnobs.features.textureCompressionBC = VK_TRUE;
         }
 
-        if (IsExtensionEnabled(Extension::TextureCompressionETC2)) {
+        if (IsFeatureEnabled(Feature::TextureCompressionETC2)) {
             ASSERT(ToBackend(GetAdapter())->GetDeviceInfo().features.textureCompressionETC2 ==
                    VK_TRUE);
             usedKnobs.features.textureCompressionETC2 = VK_TRUE;
         }
 
-        if (IsExtensionEnabled(Extension::TextureCompressionASTC)) {
+        if (IsFeatureEnabled(Feature::TextureCompressionASTC)) {
             ASSERT(ToBackend(GetAdapter())->GetDeviceInfo().features.textureCompressionASTC_LDR ==
                    VK_TRUE);
             usedKnobs.features.textureCompressionASTC_LDR = VK_TRUE;
         }
 
-        if (IsExtensionEnabled(Extension::PipelineStatisticsQuery)) {
+        if (IsFeatureEnabled(Feature::PipelineStatisticsQuery)) {
             ASSERT(ToBackend(GetAdapter())->GetDeviceInfo().features.pipelineStatisticsQuery ==
                    VK_TRUE);
             usedKnobs.features.pipelineStatisticsQuery = VK_TRUE;
         }
 
-        if (IsExtensionEnabled(Extension::ShaderFloat16)) {
+        if (IsFeatureEnabled(Feature::ShaderFloat16)) {
             const VulkanDeviceInfo& deviceInfo = ToBackend(GetAdapter())->GetDeviceInfo();
             ASSERT(deviceInfo.HasExt(DeviceExt::ShaderFloat16Int8) &&
                    deviceInfo.shaderFloat16Int8Features.shaderFloat16 == VK_TRUE &&
@@ -390,7 +390,7 @@
                               VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES);
         }
 
-        if (IsExtensionEnabled(Extension::DepthClamping)) {
+        if (IsFeatureEnabled(Feature::DepthClamping)) {
             ASSERT(ToBackend(GetAdapter())->GetDeviceInfo().features.depthClamp == VK_TRUE);
             usedKnobs.features.depthClamp = VK_TRUE;
         }
diff --git a/src/dawn_node/binding/GPUAdapter.cpp b/src/dawn_node/binding/GPUAdapter.cpp
index 30b69fb..81a95e1 100644
--- a/src/dawn_node/binding/GPUAdapter.cpp
+++ b/src/dawn_node/binding/GPUAdapter.cpp
@@ -106,20 +106,20 @@
         interop::Promise<interop::Interface<interop::GPUDevice>> promise(env);
 
         if (descriptor.has_value()) {
-            // See src/dawn_native/Extensions.cpp for feature <-> extension mappings.
+            // See src/dawn_native/Features.cpp for enum <-> string mappings.
             for (auto required : descriptor->requiredFeatures) {
                 switch (required) {
                     case interop::GPUFeatureName::kDepthClamping:
-                        desc.requiredExtensions.emplace_back("depth_clamping");
+                        desc.requiredFeatures.emplace_back("depth_clamping");
                         continue;
                     case interop::GPUFeatureName::kPipelineStatisticsQuery:
-                        desc.requiredExtensions.emplace_back("pipeline_statistics_query");
+                        desc.requiredFeatures.emplace_back("pipeline_statistics_query");
                         continue;
                     case interop::GPUFeatureName::kTextureCompressionBc:
-                        desc.requiredExtensions.emplace_back("texture_compression_bc");
+                        desc.requiredFeatures.emplace_back("texture_compression_bc");
                         continue;
                     case interop::GPUFeatureName::kTimestampQuery:
-                        desc.requiredExtensions.emplace_back("timestamp_query");
+                        desc.requiredFeatures.emplace_back("timestamp_query");
                         continue;
                     case interop::GPUFeatureName::kDepth24UnormStencil8:
                     case interop::GPUFeatureName::kDepth32FloatStencil8:
diff --git a/src/include/dawn_native/DawnNative.h b/src/include/dawn_native/DawnNative.h
index 2d89687..501512a 100644
--- a/src/include/dawn_native/DawnNative.h
+++ b/src/include/dawn_native/DawnNative.h
@@ -63,7 +63,9 @@
     // An optional parameter of Adapter::CreateDevice() to send additional information when creating
     // a Device. For example, we can use it to enable a workaround, optimization or feature.
     struct DAWN_NATIVE_EXPORT DeviceDescriptor {
+        // TODO(dawn:1149): remove once requiredExtensions is no longer used.
         std::vector<const char*> requiredExtensions;
+        std::vector<const char*> requiredFeatures;
         std::vector<const char*> forceEnabledToggles;
         std::vector<const char*> forceDisabledToggles;
 
@@ -79,10 +81,10 @@
         const char* url;
     };
 
-    // A struct to record the information of an extension. An extension is a GPU feature that is not
+    // A struct to record the information of a feature. A feature is a GPU feature that is not
     // required to be supported by all Dawn backends and can only be used when it is enabled on the
     // creation of device.
-    using ExtensionInfo = ToggleInfo;
+    using FeatureInfo = ToggleInfo;
 
     // An adapter is an object that represent on possibility of creating devices in the system.
     // Most of the time it will represent a combination of a physical GPU and an API. Not that the
@@ -109,6 +111,7 @@
         void GetProperties(wgpu::AdapterProperties* properties) const;
 
         std::vector<const char*> GetSupportedExtensions() const;
+        std::vector<const char*> GetSupportedFeatures() const;
         WGPUDeviceProperties GetAdapterProperties() const;
         bool GetLimits(WGPUSupportedLimits* limits) const;
 
diff --git a/src/tests/BUILD.gn b/src/tests/BUILD.gn
index b3aaa20..84a74f5 100644
--- a/src/tests/BUILD.gn
+++ b/src/tests/BUILD.gn
@@ -162,7 +162,7 @@
     "unittests/EnumClassBitmasksTests.cpp",
     "unittests/EnumMaskIteratorTests.cpp",
     "unittests/ErrorTests.cpp",
-    "unittests/ExtensionTests.cpp",
+    "unittests/FeatureTests.cpp",
     "unittests/GPUInfoTests.cpp",
     "unittests/GetProcAddressTests.cpp",
     "unittests/ITypArrayTests.cpp",
diff --git a/src/tests/DawnTest.cpp b/src/tests/DawnTest.cpp
index 9f0c502..56e8279 100644
--- a/src/tests/DawnTest.cpp
+++ b/src/tests/DawnTest.cpp
@@ -854,7 +854,7 @@
     return mBackendAdapter;
 }
 
-std::vector<const char*> DawnTestBase::GetRequiredExtensions() {
+std::vector<const char*> DawnTestBase::GetRequiredFeatures() {
     return {};
 }
 
@@ -862,15 +862,15 @@
     return mParam.adapterProperties;
 }
 
-bool DawnTestBase::SupportsExtensions(const std::vector<const char*>& extensions) {
+bool DawnTestBase::SupportsFeatures(const std::vector<const char*>& features) {
     ASSERT(mBackendAdapter);
-    std::set<std::string> supportedExtensionsSet;
-    for (const char* supportedExtensionName : mBackendAdapter.GetSupportedExtensions()) {
-        supportedExtensionsSet.insert(supportedExtensionName);
+    std::set<std::string> supportedFeaturesSet;
+    for (const char* supportedFeatureName : mBackendAdapter.GetSupportedFeatures()) {
+        supportedFeaturesSet.insert(supportedFeatureName);
     }
 
-    for (const char* extensionName : extensions) {
-        if (supportedExtensionsSet.find(extensionName) == supportedExtensionsSet.end()) {
+    for (const char* featureName : features) {
+        if (supportedFeaturesSet.find(featureName) == supportedFeaturesSet.end()) {
             return false;
         }
     }
@@ -912,7 +912,7 @@
     dawn_native::DeviceDescriptor deviceDescriptor = {};
     deviceDescriptor.forceEnabledToggles = mParam.forceEnabledWorkarounds;
     deviceDescriptor.forceDisabledToggles = mParam.forceDisabledWorkarounds;
-    deviceDescriptor.requiredExtensions = GetRequiredExtensions();
+    deviceDescriptor.requiredFeatures = GetRequiredFeatures();
 
     // Disabled disallowing unsafe APIs so we can test them.
     deviceDescriptor.forceDisabledToggles.push_back("disallow_unsafe_apis");
diff --git a/src/tests/DawnTest.h b/src/tests/DawnTest.h
index 206c15d..a8be5ce 100644
--- a/src/tests/DawnTest.h
+++ b/src/tests/DawnTest.h
@@ -475,13 +475,13 @@
     void FlushWire();
     void WaitForAllOperations();
 
-    bool SupportsExtensions(const std::vector<const char*>& extensions);
+    bool SupportsFeatures(const std::vector<const char*>& features);
 
-    // Called in SetUp() to get the extensions required to be enabled in the tests. The tests must
-    // check if the required extensions are supported by the adapter in this function and guarantee
-    // the returned extensions are all supported by the adapter. The tests may provide different
-    // code path to handle the situation when not all extensions are supported.
-    virtual std::vector<const char*> GetRequiredExtensions();
+    // Called in SetUp() to get the features required to be enabled in the tests. The tests must
+    // check if the required features are supported by the adapter in this function and guarantee
+    // the returned features are all supported by the adapter. The tests may provide different
+    // code path to handle the situation when not all features are supported.
+    virtual std::vector<const char*> GetRequiredFeatures();
 
     const wgpu::AdapterProperties& GetAdapterProperties() const;
 
@@ -568,7 +568,7 @@
         }                                                 \
     } while (0)
 
-// Skip a test which requires an extension or a toggle to be present / not present or some WIP
+// Skip a test which requires a feature or a toggle to be present / not present or some WIP
 // features.
 #define DAWN_TEST_UNSUPPORTED_IF(condition) \
     DAWN_SKIP_TEST_IF_BASE(condition, "unsupported", condition)
diff --git a/src/tests/end2end/BufferZeroInitTests.cpp b/src/tests/end2end/BufferZeroInitTests.cpp
index 1fcc0d7..f37ac91 100644
--- a/src/tests/end2end/BufferZeroInitTests.cpp
+++ b/src/tests/end2end/BufferZeroInitTests.cpp
@@ -46,12 +46,12 @@
 
 class BufferZeroInitTest : public DawnTest {
   protected:
-    std::vector<const char*> GetRequiredExtensions() override {
-        std::vector<const char*> requiredExtensions = {};
-        if (SupportsExtensions({"timestamp_query"})) {
-            requiredExtensions.push_back("timestamp_query");
+    std::vector<const char*> GetRequiredFeatures() override {
+        std::vector<const char*> requiredFeatures = {};
+        if (SupportsFeatures({"timestamp_query"})) {
+            requiredFeatures.push_back("timestamp_query");
         }
-        return requiredExtensions;
+        return requiredFeatures;
     }
 
   public:
@@ -1314,8 +1314,8 @@
     // without any copy commands on Metal on AMD GPU.
     DAWN_SUPPRESS_TEST_IF(IsMetal() && IsAMD());
 
-    // Skip if timestamp extension is not supported on device
-    DAWN_TEST_UNSUPPORTED_IF(!SupportsExtensions({"timestamp_query"}));
+    // Skip if timestamp feature is not supported on device
+    DAWN_TEST_UNSUPPORTED_IF(!SupportsFeatures({"timestamp_query"}));
 
     // crbug.com/dawn/940: Does not work on Mac 11.0+. Backend validation changed.
     DAWN_TEST_UNSUPPORTED_IF(IsMacOS() && !IsMacOS(10));
diff --git a/src/tests/end2end/CompressedTextureFormatTests.cpp b/src/tests/end2end/CompressedTextureFormatTests.cpp
index 3f4b62a..c756743 100644
--- a/src/tests/end2end/CompressedTextureFormatTests.cpp
+++ b/src/tests/end2end/CompressedTextureFormatTests.cpp
@@ -40,19 +40,17 @@
 
 class CompressedTextureFormatTest : public DawnTestWithParams<CompressedTextureFormatTestParams> {
   protected:
-    std::vector<const char*> GetRequiredExtensions() override {
+    std::vector<const char*> GetRequiredFeatures() override {
         const wgpu::TextureFormat format = GetParam().mTextureFormat;
-        if (utils::IsBCTextureFormat(format) && SupportsExtensions({"texture_compression_bc"})) {
+        if (utils::IsBCTextureFormat(format) && SupportsFeatures({"texture_compression_bc"})) {
             mIsFormatSupported = true;
             return {"texture_compression_bc"};
         }
-        if (utils::IsETC2TextureFormat(format) &&
-            SupportsExtensions({"texture-compression-etc2"})) {
+        if (utils::IsETC2TextureFormat(format) && SupportsFeatures({"texture-compression-etc2"})) {
             mIsFormatSupported = true;
             return {"texture-compression-etc2"};
         }
-        if (utils::IsASTCTextureFormat(format) &&
-            SupportsExtensions({"texture-compression-astc"})) {
+        if (utils::IsASTCTextureFormat(format) && SupportsFeatures({"texture-compression-astc"})) {
             mIsFormatSupported = true;
             return {"texture-compression-astc"};
         }
@@ -1151,14 +1149,14 @@
 // Suite of regression tests that target specific compression types.
 class CompressedTextureFormatSpecificTest : public DawnTest {
   protected:
-    std::vector<const char*> GetRequiredExtensions() override {
-        mIsBCFormatSupported = SupportsExtensions({"texture_compression_bc"});
+    std::vector<const char*> GetRequiredFeatures() override {
+        mIsBCFormatSupported = SupportsFeatures({"texture_compression_bc"});
 
-        std::vector<const char*> extensions;
+        std::vector<const char*> features;
         if (mIsBCFormatSupported) {
-            extensions.emplace_back("texture_compression_bc");
+            features.emplace_back("texture_compression_bc");
         }
-        return extensions;
+        return features;
     }
 
     bool IsBCFormatSupported() const {
diff --git a/src/tests/end2end/CopyTests.cpp b/src/tests/end2end/CopyTests.cpp
index f0750a1..c33ef20 100644
--- a/src/tests/end2end/CopyTests.cpp
+++ b/src/tests/end2end/CopyTests.cpp
@@ -331,7 +331,7 @@
 
 class CopyTests_T2T : public CopyTests, public DawnTestWithParams<CopyTestsParams> {
   protected:
-    std::vector<const char*> GetRequiredExtensions() override {
+    std::vector<const char*> GetRequiredFeatures() override {
         return {"dawn-internal-usages"};
     }
 
diff --git a/src/tests/end2end/D3D12ResourceWrappingTests.cpp b/src/tests/end2end/D3D12ResourceWrappingTests.cpp
index 92142b0..3c1ffd0 100644
--- a/src/tests/end2end/D3D12ResourceWrappingTests.cpp
+++ b/src/tests/end2end/D3D12ResourceWrappingTests.cpp
@@ -29,7 +29,7 @@
 
     class D3D12ResourceTestBase : public DawnTest {
       protected:
-        std::vector<const char*> GetRequiredExtensions() override {
+        std::vector<const char*> GetRequiredFeatures() override {
             return {"dawn-internal-usages"};
         }
 
diff --git a/src/tests/end2end/D3D12VideoViewsTests.cpp b/src/tests/end2end/D3D12VideoViewsTests.cpp
index f4fedb9..6d793e9 100644
--- a/src/tests/end2end/D3D12VideoViewsTests.cpp
+++ b/src/tests/end2end/D3D12VideoViewsTests.cpp
@@ -68,8 +68,8 @@
             mD3d11Device = std::move(d3d11Device);
         }
 
-        std::vector<const char*> GetRequiredExtensions() override {
-            mIsMultiPlanarFormatsSupported = SupportsExtensions({"multiplanar_formats"});
+        std::vector<const char*> GetRequiredFeatures() override {
+            mIsMultiPlanarFormatsSupported = SupportsFeatures({"multiplanar_formats"});
             if (!mIsMultiPlanarFormatsSupported) {
                 return {};
             }
diff --git a/src/tests/end2end/NonzeroTextureCreationTests.cpp b/src/tests/end2end/NonzeroTextureCreationTests.cpp
index 6040562..c00cceb 100644
--- a/src/tests/end2end/NonzeroTextureCreationTests.cpp
+++ b/src/tests/end2end/NonzeroTextureCreationTests.cpp
@@ -75,9 +75,9 @@
       protected:
         constexpr static uint32_t kSize = 128;
 
-        std::vector<const char*> GetRequiredExtensions() override {
+        std::vector<const char*> GetRequiredFeatures() override {
             if (GetParam().mFormat == wgpu::TextureFormat::BC1RGBAUnorm &&
-                SupportsExtensions({"texture_compression_bc"})) {
+                SupportsFeatures({"texture_compression_bc"})) {
                 return {"texture_compression_bc"};
             }
             return {};
@@ -85,7 +85,7 @@
 
         void Run() {
             DAWN_TEST_UNSUPPORTED_IF(GetParam().mFormat == wgpu::TextureFormat::BC1RGBAUnorm &&
-                                     !SupportsExtensions({"texture_compression_bc"}));
+                                     !SupportsFeatures({"texture_compression_bc"}));
 
             // TODO(crbug.com/dawn/667): Work around the fact that some platforms do not support
             // reading from Snorm textures.
@@ -129,7 +129,7 @@
                                   GetParam().mAspect == wgpu::TextureAspect::DepthOnly &&
                                   IsOpenGL() && IsLinux());
 
-            // GL may support the extension, but reading data back is not implemented.
+            // GL may support the feature, but reading data back is not implemented.
             DAWN_TEST_UNSUPPORTED_IF(GetParam().mFormat == wgpu::TextureFormat::BC1RGBAUnorm &&
                                      (IsOpenGL() || IsOpenGLES()));
 
diff --git a/src/tests/end2end/PrimitiveStateTests.cpp b/src/tests/end2end/PrimitiveStateTests.cpp
index 5c5114b..1bc48bb 100644
--- a/src/tests/end2end/PrimitiveStateTests.cpp
+++ b/src/tests/end2end/PrimitiveStateTests.cpp
@@ -24,7 +24,7 @@
   protected:
     void SetUp() override {
         DawnTest::SetUp();
-        DAWN_TEST_UNSUPPORTED_IF(!SupportsExtensions({"depth_clamping"}));
+        DAWN_TEST_UNSUPPORTED_IF(!SupportsFeatures({"depth_clamping"}));
 
         wgpu::TextureDescriptor renderTargetDescriptor;
         renderTargetDescriptor.size = {kRTSize, kRTSize};
@@ -67,12 +67,12 @@
             })");
     }
 
-    std::vector<const char*> GetRequiredExtensions() override {
-        std::vector<const char*> requiredExtensions = {};
-        if (SupportsExtensions({"depth_clamping"})) {
-            requiredExtensions.push_back("depth_clamping");
+    std::vector<const char*> GetRequiredFeatures() override {
+        std::vector<const char*> requiredFeatures = {};
+        if (SupportsFeatures({"depth_clamping"})) {
+            requiredFeatures.push_back("depth_clamping");
         }
-        return requiredExtensions;
+        return requiredFeatures;
     }
 
     struct TestSpec {
diff --git a/src/tests/end2end/QueryTests.cpp b/src/tests/end2end/QueryTests.cpp
index bf3be44..347ef04 100644
--- a/src/tests/end2end/QueryTests.cpp
+++ b/src/tests/end2end/QueryTests.cpp
@@ -453,17 +453,17 @@
     void SetUp() override {
         DawnTest::SetUp();
 
-        // Skip all tests if pipeline statistics extension is not supported
-        DAWN_TEST_UNSUPPORTED_IF(!SupportsExtensions({"pipeline_statistics_query"}));
+        // Skip all tests if pipeline statistics feature is not supported
+        DAWN_TEST_UNSUPPORTED_IF(!SupportsFeatures({"pipeline_statistics_query"}));
     }
 
-    std::vector<const char*> GetRequiredExtensions() override {
-        std::vector<const char*> requiredExtensions = {};
-        if (SupportsExtensions({"pipeline_statistics_query"})) {
-            requiredExtensions.push_back("pipeline_statistics_query");
+    std::vector<const char*> GetRequiredFeatures() override {
+        std::vector<const char*> requiredFeatures = {};
+        if (SupportsFeatures({"pipeline_statistics_query"})) {
+            requiredFeatures.push_back("pipeline_statistics_query");
         }
 
-        return requiredExtensions;
+        return requiredFeatures;
     }
 
     wgpu::QuerySet CreateQuerySetForPipelineStatistics(
@@ -522,16 +522,16 @@
     void SetUp() override {
         DawnTest::SetUp();
 
-        // Skip all tests if timestamp extension is not supported
-        DAWN_TEST_UNSUPPORTED_IF(!SupportsExtensions({"timestamp_query"}));
+        // Skip all tests if timestamp feature is not supported
+        DAWN_TEST_UNSUPPORTED_IF(!SupportsFeatures({"timestamp_query"}));
     }
 
-    std::vector<const char*> GetRequiredExtensions() override {
-        std::vector<const char*> requiredExtensions = {};
-        if (SupportsExtensions({"timestamp_query"})) {
-            requiredExtensions.push_back("timestamp_query");
+    std::vector<const char*> GetRequiredFeatures() override {
+        std::vector<const char*> requiredFeatures = {};
+        if (SupportsFeatures({"timestamp_query"})) {
+            requiredFeatures.push_back("timestamp_query");
         }
-        return requiredExtensions;
+        return requiredFeatures;
     }
 
     wgpu::QuerySet CreateQuerySetForTimestamp(uint32_t queryCount) {
diff --git a/src/tests/end2end/ShaderFloat16Tests.cpp b/src/tests/end2end/ShaderFloat16Tests.cpp
index 6a8c664..cc16086 100644
--- a/src/tests/end2end/ShaderFloat16Tests.cpp
+++ b/src/tests/end2end/ShaderFloat16Tests.cpp
@@ -19,8 +19,8 @@
 
 class ShaderFloat16Tests : public DawnTest {
   protected:
-    std::vector<const char*> GetRequiredExtensions() override {
-        mIsShaderFloat16Supported = SupportsExtensions({"shader_float16"});
+    std::vector<const char*> GetRequiredFeatures() override {
+        mIsShaderFloat16Supported = SupportsFeatures({"shader_float16"});
         if (!mIsShaderFloat16Supported) {
             return {};
         }
diff --git a/src/tests/end2end/TextureZeroInitTests.cpp b/src/tests/end2end/TextureZeroInitTests.cpp
index 9237e89..07799b5 100644
--- a/src/tests/end2end/TextureZeroInitTests.cpp
+++ b/src/tests/end2end/TextureZeroInitTests.cpp
@@ -1719,8 +1719,8 @@
         DAWN_TEST_UNSUPPORTED_IF(!IsBCFormatSupported());
     }
 
-    std::vector<const char*> GetRequiredExtensions() override {
-        mIsBCFormatSupported = SupportsExtensions({"texture_compression_bc"});
+    std::vector<const char*> GetRequiredFeatures() override {
+        mIsBCFormatSupported = SupportsFeatures({"texture_compression_bc"});
         if (!mIsBCFormatSupported) {
             return {};
         }
diff --git a/src/tests/unittests/ExtensionTests.cpp b/src/tests/unittests/ExtensionTests.cpp
deleted file mode 100644
index 4e74f8e..0000000
--- a/src/tests/unittests/ExtensionTests.cpp
+++ /dev/null
@@ -1,81 +0,0 @@
-// Copyright 2019 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 <gtest/gtest.h>
-
-#include "dawn_native/Extensions.h"
-#include "dawn_native/Instance.h"
-#include "dawn_native/null/DeviceNull.h"
-
-class ExtensionTests : public testing::Test {
-  public:
-    ExtensionTests()
-        : testing::Test(),
-          mInstanceBase(dawn_native::InstanceBase::Create()),
-          mAdapterBase(mInstanceBase.Get()) {
-    }
-
-    std::vector<const char*> GetAllExtensionNames() {
-        std::vector<const char*> allExtensionNames(kTotalExtensionsCount);
-        for (size_t i = 0; i < kTotalExtensionsCount; ++i) {
-            allExtensionNames[i] = ExtensionEnumToName(static_cast<dawn_native::Extension>(i));
-        }
-        return allExtensionNames;
-    }
-
-    static constexpr size_t kTotalExtensionsCount =
-        static_cast<size_t>(dawn_native::Extension::EnumCount);
-
-  protected:
-    Ref<dawn_native::InstanceBase> mInstanceBase;
-    dawn_native::null::Adapter mAdapterBase;
-};
-
-// Test the creation of a device will fail if the requested extension is not supported on the
-// Adapter.
-TEST_F(ExtensionTests, AdapterWithRequiredExtensionDisabled) {
-    const std::vector<const char*> kAllExtensionNames = GetAllExtensionNames();
-    for (size_t i = 0; i < kTotalExtensionsCount; ++i) {
-        dawn_native::Extension notSupportedExtension = static_cast<dawn_native::Extension>(i);
-
-        std::vector<const char*> extensionNamesWithoutOne = kAllExtensionNames;
-        extensionNamesWithoutOne.erase(extensionNamesWithoutOne.begin() + i);
-
-        mAdapterBase.SetSupportedExtensions(extensionNamesWithoutOne);
-        dawn_native::Adapter adapterWithoutExtension(&mAdapterBase);
-
-        dawn_native::DeviceDescriptor deviceDescriptor;
-        const char* extensionName = ExtensionEnumToName(notSupportedExtension);
-        deviceDescriptor.requiredExtensions = std::vector<const char*>(1, extensionName);
-        WGPUDevice deviceWithExtension = adapterWithoutExtension.CreateDevice(&deviceDescriptor);
-        ASSERT_EQ(nullptr, deviceWithExtension);
-    }
-}
-
-// Test Device.GetEnabledExtensions() can return the names of the enabled extensions correctly.
-TEST_F(ExtensionTests, GetEnabledExtensions) {
-    dawn_native::Adapter adapter(&mAdapterBase);
-    for (size_t i = 0; i < kTotalExtensionsCount; ++i) {
-        dawn_native::Extension extension = static_cast<dawn_native::Extension>(i);
-        const char* extensionName = ExtensionEnumToName(extension);
-
-        dawn_native::DeviceDescriptor deviceDescriptor;
-        deviceDescriptor.requiredExtensions = {extensionName};
-        dawn_native::DeviceBase* deviceBase =
-            reinterpret_cast<dawn_native::DeviceBase*>(adapter.CreateDevice(&deviceDescriptor));
-        std::vector<const char*> enabledExtensions = deviceBase->GetEnabledExtensions();
-        ASSERT_EQ(1u, enabledExtensions.size());
-        ASSERT_EQ(0, std::strcmp(extensionName, enabledExtensions[0]));
-    }
-}
diff --git a/src/tests/unittests/FeatureTests.cpp b/src/tests/unittests/FeatureTests.cpp
new file mode 100644
index 0000000..db67982
--- /dev/null
+++ b/src/tests/unittests/FeatureTests.cpp
@@ -0,0 +1,81 @@
+// Copyright 2019 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 <gtest/gtest.h>
+
+#include "dawn_native/Features.h"
+#include "dawn_native/Instance.h"
+#include "dawn_native/null/DeviceNull.h"
+
+class FeatureTests : public testing::Test {
+  public:
+    FeatureTests()
+        : testing::Test(),
+          mInstanceBase(dawn_native::InstanceBase::Create()),
+          mAdapterBase(mInstanceBase.Get()) {
+    }
+
+    std::vector<const char*> GetAllFeatureNames() {
+        std::vector<const char*> allFeatureNames(kTotalFeaturesCount);
+        for (size_t i = 0; i < kTotalFeaturesCount; ++i) {
+            allFeatureNames[i] = FeatureEnumToName(static_cast<dawn_native::Feature>(i));
+        }
+        return allFeatureNames;
+    }
+
+    static constexpr size_t kTotalFeaturesCount =
+        static_cast<size_t>(dawn_native::Feature::EnumCount);
+
+  protected:
+    Ref<dawn_native::InstanceBase> mInstanceBase;
+    dawn_native::null::Adapter mAdapterBase;
+};
+
+// 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();
+    for (size_t i = 0; i < kTotalFeaturesCount; ++i) {
+        dawn_native::Feature notSupportedFeature = static_cast<dawn_native::Feature>(i);
+
+        std::vector<const char*> featureNamesWithoutOne = kAllFeatureNames;
+        featureNamesWithoutOne.erase(featureNamesWithoutOne.begin() + i);
+
+        mAdapterBase.SetSupportedFeatures(featureNamesWithoutOne);
+        dawn_native::Adapter adapterWithoutFeature(&mAdapterBase);
+
+        dawn_native::DeviceDescriptor deviceDescriptor;
+        const char* featureName = FeatureEnumToName(notSupportedFeature);
+        deviceDescriptor.requiredFeatures = std::vector<const char*>(1, featureName);
+        WGPUDevice deviceWithFeature = adapterWithoutFeature.CreateDevice(&deviceDescriptor);
+        ASSERT_EQ(nullptr, deviceWithFeature);
+    }
+}
+
+// Test Device.GetEnabledFeatures() can return the names of the enabled features correctly.
+TEST_F(FeatureTests, GetEnabledFeatures) {
+    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);
+
+        dawn_native::DeviceDescriptor deviceDescriptor;
+        deviceDescriptor.requiredFeatures = {featureName};
+        dawn_native::DeviceBase* deviceBase =
+            reinterpret_cast<dawn_native::DeviceBase*>(adapter.CreateDevice(&deviceDescriptor));
+        std::vector<const char*> enabledFeatures = deviceBase->GetEnabledFeatures();
+        ASSERT_EQ(1u, enabledFeatures.size());
+        ASSERT_EQ(0, std::strcmp(featureName, enabledFeatures[0]));
+    }
+}
diff --git a/src/tests/unittests/validation/CopyCommandsValidationTests.cpp b/src/tests/unittests/validation/CopyCommandsValidationTests.cpp
index 63e72b2..c6e166a 100644
--- a/src/tests/unittests/validation/CopyCommandsValidationTests.cpp
+++ b/src/tests/unittests/validation/CopyCommandsValidationTests.cpp
@@ -2047,8 +2047,8 @@
   protected:
     WGPUDevice CreateTestDevice() override {
         dawn_native::DeviceDescriptor descriptor;
-        descriptor.requiredExtensions = {"texture_compression_bc", "texture-compression-etc2",
-                                         "texture-compression-astc"};
+        descriptor.requiredFeatures = {"texture_compression_bc", "texture-compression-etc2",
+                                       "texture-compression-astc"};
         return adapter.CreateDevice(&descriptor);
     }
 
diff --git a/src/tests/unittests/validation/InternalUsageValidationTests.cpp b/src/tests/unittests/validation/InternalUsageValidationTests.cpp
index 27ca9fc..4c04e53 100644
--- a/src/tests/unittests/validation/InternalUsageValidationTests.cpp
+++ b/src/tests/unittests/validation/InternalUsageValidationTests.cpp
@@ -18,8 +18,8 @@
 
 class TextureInternalUsageValidationDisabledTest : public ValidationTest {};
 
-// Test that using the extension is an error if it is not enabled
-TEST_F(TextureInternalUsageValidationDisabledTest, RequiresExtension) {
+// Test that using the feature is an error if it is not enabled
+TEST_F(TextureInternalUsageValidationDisabledTest, RequiresFeature) {
     wgpu::TextureDescriptor textureDesc = {};
     textureDesc.size = {1, 1};
     textureDesc.usage = wgpu::TextureUsage::CopySrc;
@@ -31,7 +31,7 @@
     wgpu::DawnTextureInternalUsageDescriptor internalDesc = {};
     textureDesc.nextInChain = &internalDesc;
 
-    // Error with chained extension struct.
+    // Error with chained feature struct.
     ASSERT_DEVICE_ERROR(device.CreateTexture(&textureDesc));
 
     // Also does not work with various internal usages.
@@ -45,7 +45,7 @@
 class TextureInternalUsageValidationTest : public ValidationTest {
     WGPUDevice CreateTestDevice() override {
         dawn_native::DeviceDescriptor descriptor;
-        descriptor.requiredExtensions.push_back("dawn-internal-usages");
+        descriptor.requiredFeatures.push_back("dawn-internal-usages");
 
         return adapter.CreateDevice(&descriptor);
     }
diff --git a/src/tests/unittests/validation/QueryValidationTests.cpp b/src/tests/unittests/validation/QueryValidationTests.cpp
index 2517887..c877a36 100644
--- a/src/tests/unittests/validation/QueryValidationTests.cpp
+++ b/src/tests/unittests/validation/QueryValidationTests.cpp
@@ -36,12 +36,12 @@
     }
 };
 
-// Test creating query set without extensions
-TEST_F(QuerySetValidationTest, CreationWithoutExtensions) {
-    // Creating a query set for occlusion queries succeeds without any extensions enabled.
+// Test creating query set without features
+TEST_F(QuerySetValidationTest, CreationWithoutFeatures) {
+    // Creating a query set for occlusion queries succeeds without any features enabled.
     CreateQuerySet(device, wgpu::QueryType::Occlusion, 1);
 
-    // Creating a query set for other types of queries fails without extensions enabled.
+    // Creating a query set for other types of queries fails without features enabled.
     ASSERT_DEVICE_ERROR(CreateQuerySet(device, wgpu::QueryType::PipelineStatistics, 1,
                                        {wgpu::PipelineStatisticName::VertexShaderInvocations}));
     ASSERT_DEVICE_ERROR(CreateQuerySet(device, wgpu::QueryType::Timestamp, 1));
@@ -226,13 +226,13 @@
   protected:
     WGPUDevice CreateTestDevice() override {
         dawn_native::DeviceDescriptor descriptor;
-        descriptor.requiredExtensions.push_back("timestamp_query");
+        descriptor.requiredFeatures.push_back("timestamp_query");
         descriptor.forceDisabledToggles.push_back("disallow_unsafe_apis");
         return adapter.CreateDevice(&descriptor);
     }
 };
 
-// Test creating query set with only the timestamp extension enabled.
+// Test creating query set with only the timestamp feature enabled.
 TEST_F(TimestampQueryValidationTest, Creation) {
     // Creating a query set for occlusion queries succeeds.
     CreateQuerySet(device, wgpu::QueryType::Occlusion, 1);
@@ -430,7 +430,7 @@
   protected:
     WGPUDevice CreateTestDevice() override {
         dawn_native::DeviceDescriptor descriptor;
-        descriptor.requiredExtensions.push_back("pipeline_statistics_query");
+        descriptor.requiredFeatures.push_back("pipeline_statistics_query");
         // TODO(crbug.com/1177506): Pipeline statistic query is an unsafe API, disable disallowing
         // unsafe APIs to test it.
         descriptor.forceDisabledToggles.push_back("disallow_unsafe_apis");
@@ -438,7 +438,7 @@
     }
 };
 
-// Test creating query set with only the pipeline statistics extension enabled.
+// Test creating query set with only the pipeline statistics feature enabled.
 TEST_F(PipelineStatisticsQueryValidationTest, Creation) {
     // Creating a query set for occlusion queries succeeds.
     CreateQuerySet(device, wgpu::QueryType::Occlusion, 1);
diff --git a/src/tests/unittests/validation/QueueWriteTextureValidationTests.cpp b/src/tests/unittests/validation/QueueWriteTextureValidationTests.cpp
index bb7f4f8..6efdb0e 100644
--- a/src/tests/unittests/validation/QueueWriteTextureValidationTests.cpp
+++ b/src/tests/unittests/validation/QueueWriteTextureValidationTests.cpp
@@ -558,8 +558,8 @@
       protected:
         WGPUDevice CreateTestDevice() override {
             dawn_native::DeviceDescriptor descriptor;
-            descriptor.requiredExtensions = {"texture_compression_bc", "texture-compression-etc2",
-                                             "texture-compression-astc"};
+            descriptor.requiredFeatures = {"texture_compression_bc", "texture-compression-etc2",
+                                           "texture-compression-astc"};
             return adapter.CreateDevice(&descriptor);
         }
 
diff --git a/src/tests/unittests/validation/RenderPipelineValidationTests.cpp b/src/tests/unittests/validation/RenderPipelineValidationTests.cpp
index eeac1ff..911cd50 100644
--- a/src/tests/unittests/validation/RenderPipelineValidationTests.cpp
+++ b/src/tests/unittests/validation/RenderPipelineValidationTests.cpp
@@ -782,7 +782,7 @@
 }
 
 // Test that specifying a clampDepth value results in an error if the feature is not enabled.
-TEST_F(RenderPipelineValidationTest, ClampDepthWithoutExtension) {
+TEST_F(RenderPipelineValidationTest, ClampDepthWithoutFeature) {
     {
         utils::ComboRenderPipelineDescriptor descriptor;
         descriptor.vertex.module = vsModule;
@@ -1125,12 +1125,12 @@
   protected:
     WGPUDevice CreateTestDevice() override {
         dawn_native::DeviceDescriptor descriptor;
-        descriptor.requiredExtensions = {"depth_clamping"};
+        descriptor.requiredFeatures = {"depth_clamping"};
         return adapter.CreateDevice(&descriptor);
     }
 };
 
-// Tests that specifying a clampDepth value succeeds if the extension is enabled.
+// Tests that specifying a clampDepth value succeeds if the feature is enabled.
 TEST_F(DepthClampingValidationTest, Success) {
     {
         utils::ComboRenderPipelineDescriptor descriptor;
diff --git a/src/tests/unittests/validation/TextureValidationTests.cpp b/src/tests/unittests/validation/TextureValidationTests.cpp
index 4608119..56b4990 100644
--- a/src/tests/unittests/validation/TextureValidationTests.cpp
+++ b/src/tests/unittests/validation/TextureValidationTests.cpp
@@ -533,9 +533,9 @@
         ASSERT_DEVICE_ERROR(device.CreateTexture(&descriptor));
     }
 
-    // Test that the creation of a texture with BC format will fail when the extension
+    // Test that the creation of a texture with BC format will fail when the feature
     // textureCompressionBC is not enabled.
-    TEST_F(TextureValidationTest, UseBCFormatWithoutEnablingExtension) {
+    TEST_F(TextureValidationTest, UseBCFormatWithoutEnablingFeature) {
         for (wgpu::TextureFormat format : utils::kBCFormats) {
             wgpu::TextureDescriptor descriptor = CreateDefaultTextureDescriptor();
             descriptor.format = format;
@@ -543,9 +543,9 @@
         }
     }
 
-    // Test that the creation of a texture with ETC2 format will fail when the extension
+    // Test that the creation of a texture with ETC2 format will fail when the feature
     // textureCompressionETC2 is not enabled.
-    TEST_F(TextureValidationTest, UseETC2FormatWithoutEnablingExtension) {
+    TEST_F(TextureValidationTest, UseETC2FormatWithoutEnablingFeature) {
         for (wgpu::TextureFormat format : utils::kETC2Formats) {
             wgpu::TextureDescriptor descriptor = CreateDefaultTextureDescriptor();
             descriptor.format = format;
@@ -553,9 +553,9 @@
         }
     }
 
-    // Test that the creation of a texture with ASTC format will fail when the extension
+    // Test that the creation of a texture with ASTC format will fail when the feature
     // textureCompressionASTC is not enabled.
-    TEST_F(TextureValidationTest, UseASTCFormatWithoutEnablingExtension) {
+    TEST_F(TextureValidationTest, UseASTCFormatWithoutEnablingFeature) {
         for (wgpu::TextureFormat format : utils::kASTCFormats) {
             wgpu::TextureDescriptor descriptor = CreateDefaultTextureDescriptor();
             descriptor.format = format;
@@ -569,8 +569,8 @@
       protected:
         WGPUDevice CreateTestDevice() override {
             dawn_native::DeviceDescriptor descriptor;
-            descriptor.requiredExtensions = {"texture_compression_bc", "texture-compression-etc2",
-                                             "texture-compression-astc"};
+            descriptor.requiredFeatures = {"texture_compression_bc", "texture-compression-etc2",
+                                           "texture-compression-astc"};
             return adapter.CreateDevice(&descriptor);
         }
 
diff --git a/src/tests/unittests/validation/UnsafeAPIValidationTests.cpp b/src/tests/unittests/validation/UnsafeAPIValidationTests.cpp
index ffdb128..6e22dcc 100644
--- a/src/tests/unittests/validation/UnsafeAPIValidationTests.cpp
+++ b/src/tests/unittests/validation/UnsafeAPIValidationTests.cpp
@@ -110,8 +110,8 @@
   protected:
     WGPUDevice CreateTestDevice() override {
         dawn_native::DeviceDescriptor descriptor;
-        descriptor.requiredExtensions.push_back("pipeline_statistics_query");
-        descriptor.requiredExtensions.push_back("timestamp_query");
+        descriptor.requiredFeatures.push_back("pipeline_statistics_query");
+        descriptor.requiredFeatures.push_back("timestamp_query");
         descriptor.forceEnabledToggles.push_back("disallow_unsafe_apis");
         return adapter.CreateDevice(&descriptor);
     }
diff --git a/src/tests/unittests/validation/VideoViewsValidationTests.cpp b/src/tests/unittests/validation/VideoViewsValidationTests.cpp
index 0e313c7..b799901 100644
--- a/src/tests/unittests/validation/VideoViewsValidationTests.cpp
+++ b/src/tests/unittests/validation/VideoViewsValidationTests.cpp
@@ -22,7 +22,7 @@
       protected:
         WGPUDevice CreateTestDevice() override {
             dawn_native::DeviceDescriptor descriptor;
-            descriptor.requiredExtensions = {"multiplanar_formats"};
+            descriptor.requiredFeatures = {"multiplanar_formats"};
             return adapter.CreateDevice(&descriptor);
         }
 
diff --git a/src/tests/white_box/D3D12ResourceHeapTests.cpp b/src/tests/white_box/D3D12ResourceHeapTests.cpp
index 722203d..5586082 100644
--- a/src/tests/white_box/D3D12ResourceHeapTests.cpp
+++ b/src/tests/white_box/D3D12ResourceHeapTests.cpp
@@ -26,8 +26,8 @@
         DAWN_TEST_UNSUPPORTED_IF(UsesWire());
     }
 
-    std::vector<const char*> GetRequiredExtensions() override {
-        mIsBCFormatSupported = SupportsExtensions({"texture_compression_bc"});
+    std::vector<const char*> GetRequiredFeatures() override {
+        mIsBCFormatSupported = SupportsFeatures({"texture_compression_bc"});
         if (!mIsBCFormatSupported) {
             return {};
         }
diff --git a/src/tests/white_box/EGLImageWrappingTests.cpp b/src/tests/white_box/EGLImageWrappingTests.cpp
index cec291e..82eb738 100644
--- a/src/tests/white_box/EGLImageWrappingTests.cpp
+++ b/src/tests/white_box/EGLImageWrappingTests.cpp
@@ -115,7 +115,7 @@
 
 class EGLImageTestBase : public DawnTest {
   protected:
-    std::vector<const char*> GetRequiredExtensions() override {
+    std::vector<const char*> GetRequiredFeatures() override {
         return {"dawn-internal-usages"};
     }
 
diff --git a/src/tests/white_box/VulkanImageWrappingTestsDmaBuf.cpp b/src/tests/white_box/VulkanImageWrappingTestsDmaBuf.cpp
index 8bc9670..4349f4d 100644
--- a/src/tests/white_box/VulkanImageWrappingTestsDmaBuf.cpp
+++ b/src/tests/white_box/VulkanImageWrappingTestsDmaBuf.cpp
@@ -34,7 +34,7 @@
 
         class VulkanImageWrappingTestBase : public DawnTest {
           protected:
-            std::vector<const char*> GetRequiredExtensions() override {
+            std::vector<const char*> GetRequiredFeatures() override {
                 return {"dawn-internal-usages"};
             }
 
diff --git a/src/tests/white_box/VulkanImageWrappingTestsOpaqueFD.cpp b/src/tests/white_box/VulkanImageWrappingTestsOpaqueFD.cpp
index c4e4266..b81f8ce 100644
--- a/src/tests/white_box/VulkanImageWrappingTestsOpaqueFD.cpp
+++ b/src/tests/white_box/VulkanImageWrappingTestsOpaqueFD.cpp
@@ -31,7 +31,7 @@
 
         class VulkanImageWrappingTestBase : public DawnTest {
           protected:
-            std::vector<const char*> GetRequiredExtensions() override {
+            std::vector<const char*> GetRequiredFeatures() override {
                 return {"dawn-internal-usages"};
             }