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>
This commit is contained in:
Austin Eng 2021-12-15 00:12:30 +00:00 committed by Dawn LUCI CQ
parent fe1e929d5a
commit 89ddadcd1e
15 changed files with 130 additions and 17 deletions

View File

@ -97,6 +97,14 @@
{"name": "feature", "type": "feature name"} {"name": "feature", "type": "feature name"}
] ]
}, },
{
"tags": ["dawn"],
"name": "enumerate features",
"returns": "uint32_t",
"args": [
{"name": "features", "type": "feature name", "annotation": "*"}
]
},
{ {
"name": "request device", "name": "request device",
"args": [ "args": [
@ -1057,6 +1065,22 @@
{"name": "limits", "type": "supported limits", "annotation": "*"} {"name": "limits", "type": "supported limits", "annotation": "*"}
] ]
}, },
{
"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", "name": "get queue",
"returns": "queue" "returns": "queue"
@ -1297,7 +1321,10 @@
{"value": 7, "name": "texture compression ETC2"}, {"value": 7, "name": "texture compression ETC2"},
{"value": 8, "name": "texture compression ASTC"}, {"value": 8, "name": "texture compression ASTC"},
{"value": 9, "name": "indirect first instance"}, {"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": { "filter mode": {

View File

@ -151,6 +151,7 @@
"AdapterGetProperties", "AdapterGetProperties",
"AdapterGetLimits", "AdapterGetLimits",
"AdapterHasFeature", "AdapterHasFeature",
"AdapterEnumerateFeatures",
"AdapterRequestDevice", "AdapterRequestDevice",
"BufferMapAsync", "BufferMapAsync",
"BufferGetConstMappedRange", "BufferGetConstMappedRange",
@ -159,6 +160,8 @@
"DeviceCreateComputePipelineAsync", "DeviceCreateComputePipelineAsync",
"DeviceCreateRenderPipelineAsync", "DeviceCreateRenderPipelineAsync",
"DeviceGetLimits", "DeviceGetLimits",
"DeviceHasFeature",
"DeviceEnumerateFeatures",
"DevicePopErrorScope", "DevicePopErrorScope",
"DeviceSetDeviceLostCallback", "DeviceSetDeviceLostCallback",
"DeviceSetUncapturedErrorCallback", "DeviceSetUncapturedErrorCallback",

View File

@ -43,7 +43,7 @@ namespace dawn_native {
{% for arg in method.arguments %} {% for arg in method.arguments %}
{% set varName = as_varName(arg.name) %} {% 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}}); auto {{varName}}_ = static_cast<{{as_frontendType(arg.type)}}>({{varName}});
{% elif arg.annotation != "value" or arg.type.category == "object" %} {% elif arg.annotation != "value" or arg.type.category == "object" %}
auto {{varName}}_ = reinterpret_cast<{{decorate("", as_frontendType(arg.type), arg)}}>({{varName}}); auto {{varName}}_ = reinterpret_cast<{{decorate("", as_frontendType(arg.type), arg)}}>({{varName}});

View File

@ -64,6 +64,8 @@ namespace dawn_wire { namespace client {
{% endif %} {% endif %}
{% for arg in method.arguments %} {% 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)}}; cmd.{{as_varName(arg.name)}} = {{as_varName(arg.name)}};
{% endfor %} {% endfor %}

View File

@ -86,6 +86,10 @@ namespace dawn_native {
return mSupportedFeatures.IsEnabled(feature); return mSupportedFeatures.IsEnabled(feature);
} }
uint32_t AdapterBase::APIEnumerateFeatures(wgpu::FeatureName* features) const {
return mSupportedFeatures.EnumerateFeatures(features);
}
void AdapterBase::APIRequestDevice(const DeviceDescriptor* descriptor, void AdapterBase::APIRequestDevice(const DeviceDescriptor* descriptor,
WGPURequestDeviceCallback callback, WGPURequestDeviceCallback callback,
void* userdata) { void* userdata) {

View File

@ -40,6 +40,7 @@ namespace dawn_native {
bool APIGetLimits(SupportedLimits* limits) const; bool APIGetLimits(SupportedLimits* limits) const;
void APIGetProperties(AdapterProperties* properties) const; void APIGetProperties(AdapterProperties* properties) const;
bool APIHasFeature(wgpu::FeatureName feature) const; bool APIHasFeature(wgpu::FeatureName feature) const;
uint32_t APIEnumerateFeatures(wgpu::FeatureName* features) const;
void APIRequestDevice(const DeviceDescriptor* descriptor, void APIRequestDevice(const DeviceDescriptor* descriptor,
WGPURequestDeviceCallback callback, WGPURequestDeviceCallback callback,
void* userdata); void* userdata);

View File

@ -1197,7 +1197,7 @@ namespace dawn_native {
} }
} }
bool DeviceBase::APIGetLimits(SupportedLimits* limits) { bool DeviceBase::APIGetLimits(SupportedLimits* limits) const {
ASSERT(limits != nullptr); ASSERT(limits != nullptr);
if (limits->nextInChain != nullptr) { if (limits->nextInChain != nullptr) {
return false; return false;
@ -1206,6 +1206,14 @@ namespace dawn_native {
return true; 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) { void DeviceBase::APIInjectError(wgpu::ErrorType type, const char* message) {
if (ConsumedError(ValidateErrorType(type))) { if (ConsumedError(ValidateErrorType(type))) {
return; return;

View File

@ -257,7 +257,9 @@ namespace dawn_native {
QueueBase* APIGetQueue(); 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); void APIInjectError(wgpu::ErrorType type, const char* message);
bool APITick(); bool APITick();

View File

@ -106,6 +106,12 @@ namespace dawn_native {
return Feature::Depth24UnormStencil8; return Feature::Depth24UnormStencil8;
case wgpu::FeatureName::Depth32FloatStencil8: case wgpu::FeatureName::Depth32FloatStencil8:
return Feature::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: case wgpu::FeatureName::IndirectFirstInstance:
return Feature::InvalidEnum; return Feature::InvalidEnum;
@ -113,6 +119,36 @@ namespace dawn_native {
return Feature::InvalidEnum; 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 } // anonymous namespace
void FeaturesSet::EnableFeature(Feature feature) { void FeaturesSet::EnableFeature(Feature feature) {
@ -132,6 +168,17 @@ namespace dawn_native {
return f != Feature::InvalidEnum && IsEnabled(f); 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*> FeaturesSet::GetEnabledFeatureNames() const {
std::vector<const char*> enabledFeatureNames(featuresBitSet.count()); std::vector<const char*> enabledFeatureNames(featuresBitSet.count());

View File

@ -19,6 +19,7 @@
#include <unordered_map> #include <unordered_map>
#include <vector> #include <vector>
#include "common/ityp_bitset.h"
#include "dawn/webgpu_cpp.h" #include "dawn/webgpu_cpp.h"
#include "dawn_native/DawnNative.h" #include "dawn_native/DawnNative.h"
@ -52,6 +53,9 @@ namespace dawn_native {
void EnableFeature(Feature feature); void EnableFeature(Feature feature);
bool IsEnabled(Feature feature) const; bool IsEnabled(Feature feature) const;
bool IsEnabled(wgpu::FeatureName 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; std::vector<const char*> GetEnabledFeatureNames() const;
void InitializeDeviceProperties(WGPUDeviceProperties* properties) const; void InitializeDeviceProperties(WGPUDeviceProperties* properties) const;
}; };

View File

@ -28,6 +28,10 @@ namespace dawn_wire { namespace client {
UNREACHABLE(); UNREACHABLE();
} }
uint32_t Adapter::EnumerateFeatures(WGPUFeatureName* features) const {
UNREACHABLE();
}
void Adapter::RequestDevice(const WGPUDeviceDescriptor* descriptor, void Adapter::RequestDevice(const WGPUDeviceDescriptor* descriptor,
WGPURequestDeviceCallback callback, WGPURequestDeviceCallback callback,
void* userdata) { void* userdata) {

View File

@ -29,6 +29,7 @@ namespace dawn_wire { namespace client {
bool GetLimits(WGPUSupportedLimits* limits) const; bool GetLimits(WGPUSupportedLimits* limits) const;
void GetProperties(WGPUAdapterProperties* properties) const; void GetProperties(WGPUAdapterProperties* properties) const;
bool HasFeature(WGPUFeatureName feature) const; bool HasFeature(WGPUFeatureName feature) const;
uint32_t EnumerateFeatures(WGPUFeatureName* features) const;
void RequestDevice(const WGPUDeviceDescriptor* descriptor, void RequestDevice(const WGPUDeviceDescriptor* descriptor,
WGPURequestDeviceCallback callback, WGPURequestDeviceCallback callback,
void* userdata); void* userdata);

View File

@ -196,12 +196,20 @@ namespace dawn_wire { namespace client {
return Buffer::CreateError(this); return Buffer::CreateError(this);
} }
bool Device::GetLimits(WGPUSupportedLimits* limits) { bool Device::GetLimits(WGPUSupportedLimits* limits) const {
// Not implemented in the wire. // Not implemented in the wire.
UNREACHABLE(); UNREACHABLE();
return false; return false;
} }
bool Device::HasFeature(WGPUFeatureName feature) const {
UNREACHABLE();
}
uint32_t Device::EnumerateFeatures(WGPUFeatureName* features) const {
UNREACHABLE();
}
WGPUQueue Device::GetQueue() { WGPUQueue Device::GetQueue() {
// The queue is lazily created because if a Device is created by // The queue is lazily created because if a Device is created by
// Reserve/Inject, we cannot send the GetQueue message until // Reserve/Inject, we cannot send the GetQueue message until

View File

@ -64,7 +64,9 @@ namespace dawn_wire { namespace client {
WGPUCreatePipelineAsyncStatus status, WGPUCreatePipelineAsyncStatus status,
const char* message); 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(); WGPUQueue GetQueue();
void CancelCallbacksForDisconnect() override; void CancelCallbacksForDisconnect() override;

View File

@ -36,13 +36,14 @@ namespace {
WGPUInstance serverInstance = api.GetNewInstance(); WGPUInstance serverInstance = api.GetNewInstance();
EXPECT_CALL(api, InstanceReference(serverInstance)); EXPECT_CALL(api, InstanceReference(serverInstance));
ASSERT_TRUE( ASSERT_TRUE(GetWireServer()->InjectInstance(serverInstance, reservation.id,
GetWireServer()->InjectInstance(serverInstance, reservation.id, reservation.generation)); reservation.generation));
WGPUSurfaceDescriptor surfaceDesc = {}; WGPUSurfaceDescriptor surfaceDesc = {};
wgpuInstanceCreateSurface(reservation.instance, &surfaceDesc); wgpuInstanceCreateSurface(reservation.instance, &surfaceDesc);
WGPUSurface serverSurface = api.GetNewSurface(); WGPUSurface serverSurface = api.GetNewSurface();
EXPECT_CALL(api, InstanceCreateSurface(serverInstance, NotNull())).WillOnce(Return(serverSurface)); EXPECT_CALL(api, InstanceCreateSurface(serverInstance, NotNull()))
.WillOnce(Return(serverSurface));
FlushClient(); FlushClient();
} }
@ -55,19 +56,18 @@ namespace {
ASSERT_NE(reservation1.instance, reservation2.instance); ASSERT_NE(reservation1.instance, reservation2.instance);
} }
// Test that injecting the same id fails. // Test that injecting the same id fails.
TEST_F(WireInjectInstanceTests, InjectExistingID) { TEST_F(WireInjectInstanceTests, InjectExistingID) {
ReservedInstance reservation = GetWireClient()->ReserveInstance(); ReservedInstance reservation = GetWireClient()->ReserveInstance();
WGPUInstance serverInstance = api.GetNewInstance(); WGPUInstance serverInstance = api.GetNewInstance();
EXPECT_CALL(api, InstanceReference(serverInstance)); EXPECT_CALL(api, InstanceReference(serverInstance));
ASSERT_TRUE( ASSERT_TRUE(GetWireServer()->InjectInstance(serverInstance, reservation.id,
GetWireServer()->InjectInstance(serverInstance, reservation.id, reservation.generation)); reservation.generation));
// ID already in use, call fails. // ID already in use, call fails.
ASSERT_FALSE( ASSERT_FALSE(GetWireServer()->InjectInstance(serverInstance, reservation.id,
GetWireServer()->InjectInstance(serverInstance, reservation.id, reservation.generation)); reservation.generation));
} }
// Test that the server only borrows the instance and does a single reference-release // Test that the server only borrows the instance and does a single reference-release
@ -77,8 +77,8 @@ namespace {
// Injecting the instance adds a reference // Injecting the instance adds a reference
WGPUInstance serverInstance = api.GetNewInstance(); WGPUInstance serverInstance = api.GetNewInstance();
EXPECT_CALL(api, InstanceReference(serverInstance)); EXPECT_CALL(api, InstanceReference(serverInstance));
ASSERT_TRUE( ASSERT_TRUE(GetWireServer()->InjectInstance(serverInstance, reservation.id,
GetWireServer()->InjectInstance(serverInstance, reservation.id, reservation.generation)); reservation.generation));
// Releasing the instance removes a single reference. // Releasing the instance removes a single reference.
wgpuInstanceRelease(reservation.instance); wgpuInstanceRelease(reservation.instance);