Add feature queries to dawn_native/dawn_wire

This is so we can implement the adapter/device APIs fully
on dawn_wire.

Bug: dawn:689
Change-Id: I47f68157d081f359f871e0efe0d974dfe53de7d7
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/71521
Reviewed-by: Loko Kung <lokokung@google.com>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Commit-Queue: Austin Eng <enga@chromium.org>
diff --git a/dawn.json b/dawn.json
index 884b5e6..97cff4a 100644
--- a/dawn.json
+++ b/dawn.json
@@ -98,6 +98,14 @@
                 ]
             },
             {
+                "tags": ["dawn"],
+                "name": "enumerate features",
+                "returns": "uint32_t",
+                "args": [
+                    {"name": "features", "type": "feature name", "annotation": "*"}
+                ]
+            },
+            {
                 "name": "request device",
                 "args": [
                     {"name": "descriptor", "type": "device descriptor", "annotation": "const*"},
@@ -1058,6 +1066,22 @@
                 ]
             },
             {
+                "tags": ["dawn"],
+                "name": "has feature",
+                "returns": "bool",
+                "args": [
+                    {"name": "feature", "type": "feature name"}
+                ]
+            },
+            {
+                "tags": ["dawn"],
+                "name": "enumerate features",
+                "returns": "uint32_t",
+                "args": [
+                    {"name": "features", "type": "feature name", "annotation": "*"}
+                ]
+            },
+            {
                 "name": "get queue",
                 "returns": "queue"
             },
@@ -1297,7 +1321,10 @@
             {"value": 7, "name": "texture compression ETC2"},
             {"value": 8, "name": "texture compression ASTC"},
             {"value": 9, "name": "indirect first instance"},
-            {"value": 1000, "name": "depth clamping", "tags": ["emscripten", "dawn"]}
+            {"value": 1000, "name": "depth clamping", "tags": ["emscripten", "dawn"]},
+            {"value": 1001, "name": "dawn shader float 16", "tags": ["dawn"]},
+            {"value": 1002, "name": "dawn internal usages", "tags": ["dawn"]},
+            {"value": 1003, "name": "dawn multi planar formats", "tags": ["dawn"]}
         ]
     },
     "filter mode": {
diff --git a/dawn_wire.json b/dawn_wire.json
index 5083751..4bd03a1 100644
--- a/dawn_wire.json
+++ b/dawn_wire.json
@@ -151,6 +151,7 @@
             "AdapterGetProperties",
             "AdapterGetLimits",
             "AdapterHasFeature",
+            "AdapterEnumerateFeatures",
             "AdapterRequestDevice",
             "BufferMapAsync",
             "BufferGetConstMappedRange",
@@ -159,6 +160,8 @@
             "DeviceCreateComputePipelineAsync",
             "DeviceCreateRenderPipelineAsync",
             "DeviceGetLimits",
+            "DeviceHasFeature",
+            "DeviceEnumerateFeatures",
             "DevicePopErrorScope",
             "DeviceSetDeviceLostCallback",
             "DeviceSetUncapturedErrorCallback",
diff --git a/generator/templates/dawn_native/ProcTable.cpp b/generator/templates/dawn_native/ProcTable.cpp
index 73a9d8d..857cbc7 100644
--- a/generator/templates/dawn_native/ProcTable.cpp
+++ b/generator/templates/dawn_native/ProcTable.cpp
@@ -43,7 +43,7 @@
 
                 {% for arg in method.arguments %}
                     {% set varName = as_varName(arg.name) %}
-                    {% if arg.type.category in ["enum", "bitmask"] %}
+                    {% if arg.type.category in ["enum", "bitmask"] and arg.annotation == "value" %}
                         auto {{varName}}_ = static_cast<{{as_frontendType(arg.type)}}>({{varName}});
                     {% elif arg.annotation != "value" or arg.type.category == "object" %}
                         auto {{varName}}_ = reinterpret_cast<{{decorate("", as_frontendType(arg.type), arg)}}>({{varName}});
diff --git a/generator/templates/dawn_wire/client/ApiProcs.cpp b/generator/templates/dawn_wire/client/ApiProcs.cpp
index 48b3e3a..71201ec 100644
--- a/generator/templates/dawn_wire/client/ApiProcs.cpp
+++ b/generator/templates/dawn_wire/client/ApiProcs.cpp
@@ -64,6 +64,8 @@
                     {% endif %}
 
                     {% for arg in method.arguments %}
+                        //* Commands with mutable pointers should not be autogenerated.
+                        {{assert(arg.annotation != "*")}}
                         cmd.{{as_varName(arg.name)}} = {{as_varName(arg.name)}};
                     {% endfor %}
 
diff --git a/src/dawn_native/Adapter.cpp b/src/dawn_native/Adapter.cpp
index c3ac8de..7ef85c1 100644
--- a/src/dawn_native/Adapter.cpp
+++ b/src/dawn_native/Adapter.cpp
@@ -86,6 +86,10 @@
         return mSupportedFeatures.IsEnabled(feature);
     }
 
+    uint32_t AdapterBase::APIEnumerateFeatures(wgpu::FeatureName* features) const {
+        return mSupportedFeatures.EnumerateFeatures(features);
+    }
+
     void AdapterBase::APIRequestDevice(const DeviceDescriptor* descriptor,
                                        WGPURequestDeviceCallback callback,
                                        void* userdata) {
diff --git a/src/dawn_native/Adapter.h b/src/dawn_native/Adapter.h
index 36930db..a8a5fdb 100644
--- a/src/dawn_native/Adapter.h
+++ b/src/dawn_native/Adapter.h
@@ -40,6 +40,7 @@
         bool APIGetLimits(SupportedLimits* limits) const;
         void APIGetProperties(AdapterProperties* properties) const;
         bool APIHasFeature(wgpu::FeatureName feature) const;
+        uint32_t APIEnumerateFeatures(wgpu::FeatureName* features) const;
         void APIRequestDevice(const DeviceDescriptor* descriptor,
                               WGPURequestDeviceCallback callback,
                               void* userdata);
diff --git a/src/dawn_native/Device.cpp b/src/dawn_native/Device.cpp
index 35b5101..127b29f 100644
--- a/src/dawn_native/Device.cpp
+++ b/src/dawn_native/Device.cpp
@@ -1197,7 +1197,7 @@
         }
     }
 
-    bool DeviceBase::APIGetLimits(SupportedLimits* limits) {
+    bool DeviceBase::APIGetLimits(SupportedLimits* limits) const {
         ASSERT(limits != nullptr);
         if (limits->nextInChain != nullptr) {
             return false;
@@ -1206,6 +1206,14 @@
         return true;
     }
 
+    bool DeviceBase::APIHasFeature(wgpu::FeatureName feature) const {
+        return mEnabledFeatures.IsEnabled(feature);
+    }
+
+    uint32_t DeviceBase::APIEnumerateFeatures(wgpu::FeatureName* features) const {
+        return mEnabledFeatures.EnumerateFeatures(features);
+    }
+
     void DeviceBase::APIInjectError(wgpu::ErrorType type, const char* message) {
         if (ConsumedError(ValidateErrorType(type))) {
             return;
diff --git a/src/dawn_native/Device.h b/src/dawn_native/Device.h
index ff9b7f0..298d0b4 100644
--- a/src/dawn_native/Device.h
+++ b/src/dawn_native/Device.h
@@ -257,7 +257,9 @@
 
         QueueBase* APIGetQueue();
 
-        bool APIGetLimits(SupportedLimits* limits);
+        bool APIGetLimits(SupportedLimits* limits) const;
+        bool APIHasFeature(wgpu::FeatureName feature) const;
+        uint32_t APIEnumerateFeatures(wgpu::FeatureName* features) const;
         void APIInjectError(wgpu::ErrorType type, const char* message);
         bool APITick();
 
diff --git a/src/dawn_native/Features.cpp b/src/dawn_native/Features.cpp
index ad427d3..037d8f4 100644
--- a/src/dawn_native/Features.cpp
+++ b/src/dawn_native/Features.cpp
@@ -106,6 +106,12 @@
                     return Feature::Depth24UnormStencil8;
                 case wgpu::FeatureName::Depth32FloatStencil8:
                     return Feature::Depth32FloatStencil8;
+                case wgpu::FeatureName::DawnShaderFloat16:
+                    return Feature::ShaderFloat16;
+                case wgpu::FeatureName::DawnInternalUsages:
+                    return Feature::DawnInternalUsages;
+                case wgpu::FeatureName::DawnMultiPlanarFormats:
+                    return Feature::MultiPlanarFormats;
 
                 case wgpu::FeatureName::IndirectFirstInstance:
                     return Feature::InvalidEnum;
@@ -113,6 +119,36 @@
             return Feature::InvalidEnum;
         }
 
+        wgpu::FeatureName ToAPIFeature(Feature feature) {
+            switch (feature) {
+                case Feature::TextureCompressionBC:
+                    return wgpu::FeatureName::TextureCompressionBC;
+                case Feature::TextureCompressionETC2:
+                    return wgpu::FeatureName::TextureCompressionETC2;
+                case Feature::TextureCompressionASTC:
+                    return wgpu::FeatureName::TextureCompressionASTC;
+                case Feature::PipelineStatisticsQuery:
+                    return wgpu::FeatureName::PipelineStatisticsQuery;
+                case Feature::TimestampQuery:
+                    return wgpu::FeatureName::TimestampQuery;
+                case Feature::DepthClamping:
+                    return wgpu::FeatureName::DepthClamping;
+                case Feature::Depth24UnormStencil8:
+                    return wgpu::FeatureName::Depth24UnormStencil8;
+                case Feature::Depth32FloatStencil8:
+                    return wgpu::FeatureName::Depth32FloatStencil8;
+                case Feature::ShaderFloat16:
+                    return wgpu::FeatureName::DawnShaderFloat16;
+                case Feature::DawnInternalUsages:
+                    return wgpu::FeatureName::DawnInternalUsages;
+                case Feature::MultiPlanarFormats:
+                    return wgpu::FeatureName::DawnMultiPlanarFormats;
+
+                case Feature::EnumCount:
+                    UNREACHABLE();
+            }
+        }
+
     }  // anonymous namespace
 
     void FeaturesSet::EnableFeature(Feature feature) {
@@ -132,6 +168,17 @@
         return f != Feature::InvalidEnum && IsEnabled(f);
     }
 
+    uint32_t FeaturesSet::EnumerateFeatures(wgpu::FeatureName* features) const {
+        for (uint32_t i : IterateBitSet(featuresBitSet)) {
+            wgpu::FeatureName feature = ToAPIFeature(static_cast<Feature>(i));
+            if (features != nullptr) {
+                *features = feature;
+                features += 1;
+            }
+        }
+        return featuresBitSet.count();
+    }
+
     std::vector<const char*> FeaturesSet::GetEnabledFeatureNames() const {
         std::vector<const char*> enabledFeatureNames(featuresBitSet.count());
 
diff --git a/src/dawn_native/Features.h b/src/dawn_native/Features.h
index 4c4a79a..6dd2afc 100644
--- a/src/dawn_native/Features.h
+++ b/src/dawn_native/Features.h
@@ -19,6 +19,7 @@
 #include <unordered_map>
 #include <vector>
 
+#include "common/ityp_bitset.h"
 #include "dawn/webgpu_cpp.h"
 #include "dawn_native/DawnNative.h"
 
@@ -52,6 +53,9 @@
         void EnableFeature(Feature feature);
         bool IsEnabled(Feature feature) const;
         bool IsEnabled(wgpu::FeatureName feature) const;
+        // Returns |count|, the number of features. Writes out all |count| values if |features| is
+        // non-null.
+        uint32_t EnumerateFeatures(wgpu::FeatureName* features) const;
         std::vector<const char*> GetEnabledFeatureNames() const;
         void InitializeDeviceProperties(WGPUDeviceProperties* properties) const;
     };
diff --git a/src/dawn_wire/client/Adapter.cpp b/src/dawn_wire/client/Adapter.cpp
index ee789f9..f3e46ef 100644
--- a/src/dawn_wire/client/Adapter.cpp
+++ b/src/dawn_wire/client/Adapter.cpp
@@ -28,6 +28,10 @@
         UNREACHABLE();
     }
 
+    uint32_t Adapter::EnumerateFeatures(WGPUFeatureName* features) const {
+        UNREACHABLE();
+    }
+
     void Adapter::RequestDevice(const WGPUDeviceDescriptor* descriptor,
                                 WGPURequestDeviceCallback callback,
                                 void* userdata) {
diff --git a/src/dawn_wire/client/Adapter.h b/src/dawn_wire/client/Adapter.h
index d939220..58c5d0f 100644
--- a/src/dawn_wire/client/Adapter.h
+++ b/src/dawn_wire/client/Adapter.h
@@ -29,6 +29,7 @@
         bool GetLimits(WGPUSupportedLimits* limits) const;
         void GetProperties(WGPUAdapterProperties* properties) const;
         bool HasFeature(WGPUFeatureName feature) const;
+        uint32_t EnumerateFeatures(WGPUFeatureName* features) const;
         void RequestDevice(const WGPUDeviceDescriptor* descriptor,
                            WGPURequestDeviceCallback callback,
                            void* userdata);
diff --git a/src/dawn_wire/client/Device.cpp b/src/dawn_wire/client/Device.cpp
index 8379d51..57e6599 100644
--- a/src/dawn_wire/client/Device.cpp
+++ b/src/dawn_wire/client/Device.cpp
@@ -196,12 +196,20 @@
         return Buffer::CreateError(this);
     }
 
-    bool Device::GetLimits(WGPUSupportedLimits* limits) {
+    bool Device::GetLimits(WGPUSupportedLimits* limits) const {
         // Not implemented in the wire.
         UNREACHABLE();
         return false;
     }
 
+    bool Device::HasFeature(WGPUFeatureName feature) const {
+        UNREACHABLE();
+    }
+
+    uint32_t Device::EnumerateFeatures(WGPUFeatureName* features) const {
+        UNREACHABLE();
+    }
+
     WGPUQueue Device::GetQueue() {
         // The queue is lazily created because if a Device is created by
         // Reserve/Inject, we cannot send the GetQueue message until
diff --git a/src/dawn_wire/client/Device.h b/src/dawn_wire/client/Device.h
index 426799c..fff5cf8 100644
--- a/src/dawn_wire/client/Device.h
+++ b/src/dawn_wire/client/Device.h
@@ -64,7 +64,9 @@
                                                  WGPUCreatePipelineAsyncStatus status,
                                                  const char* message);
 
-        bool GetLimits(WGPUSupportedLimits* limits);
+        bool GetLimits(WGPUSupportedLimits* limits) const;
+        bool HasFeature(WGPUFeatureName feature) const;
+        uint32_t EnumerateFeatures(WGPUFeatureName* features) const;
         WGPUQueue GetQueue();
 
         void CancelCallbacksForDisconnect() override;
diff --git a/src/tests/unittests/wire/WireInjectInstanceTests.cpp b/src/tests/unittests/wire/WireInjectInstanceTests.cpp
index 7bdf170..05502f5 100644
--- a/src/tests/unittests/wire/WireInjectInstanceTests.cpp
+++ b/src/tests/unittests/wire/WireInjectInstanceTests.cpp
@@ -23,7 +23,7 @@
 namespace {
 
     class WireInjectInstanceTests : public WireTest {
-    public:
+      public:
         WireInjectInstanceTests() {
         }
         ~WireInjectInstanceTests() override = default;
@@ -36,13 +36,14 @@
 
         WGPUInstance serverInstance = api.GetNewInstance();
         EXPECT_CALL(api, InstanceReference(serverInstance));
-        ASSERT_TRUE(
-            GetWireServer()->InjectInstance(serverInstance, reservation.id, reservation.generation));
+        ASSERT_TRUE(GetWireServer()->InjectInstance(serverInstance, reservation.id,
+                                                    reservation.generation));
 
         WGPUSurfaceDescriptor surfaceDesc = {};
         wgpuInstanceCreateSurface(reservation.instance, &surfaceDesc);
         WGPUSurface serverSurface = api.GetNewSurface();
-        EXPECT_CALL(api, InstanceCreateSurface(serverInstance, NotNull())).WillOnce(Return(serverSurface));
+        EXPECT_CALL(api, InstanceCreateSurface(serverInstance, NotNull()))
+            .WillOnce(Return(serverSurface));
         FlushClient();
     }
 
@@ -55,19 +56,18 @@
         ASSERT_NE(reservation1.instance, reservation2.instance);
     }
 
-
     // Test that injecting the same id fails.
     TEST_F(WireInjectInstanceTests, InjectExistingID) {
         ReservedInstance reservation = GetWireClient()->ReserveInstance();
 
         WGPUInstance serverInstance = api.GetNewInstance();
         EXPECT_CALL(api, InstanceReference(serverInstance));
-        ASSERT_TRUE(
-            GetWireServer()->InjectInstance(serverInstance, reservation.id, reservation.generation));
+        ASSERT_TRUE(GetWireServer()->InjectInstance(serverInstance, reservation.id,
+                                                    reservation.generation));
 
         // ID already in use, call fails.
-        ASSERT_FALSE(
-            GetWireServer()->InjectInstance(serverInstance, reservation.id, reservation.generation));
+        ASSERT_FALSE(GetWireServer()->InjectInstance(serverInstance, reservation.id,
+                                                     reservation.generation));
     }
 
     // Test that the server only borrows the instance and does a single reference-release
@@ -77,8 +77,8 @@
         // Injecting the instance adds a reference
         WGPUInstance serverInstance = api.GetNewInstance();
         EXPECT_CALL(api, InstanceReference(serverInstance));
-        ASSERT_TRUE(
-            GetWireServer()->InjectInstance(serverInstance, reservation.id, reservation.generation));
+        ASSERT_TRUE(GetWireServer()->InjectInstance(serverInstance, reservation.id,
+                                                    reservation.generation));
 
         // Releasing the instance removes a single reference.
         wgpuInstanceRelease(reservation.instance);