node: Implement GPUDevice.features

Bug: None
Change-Id: I29f2832d22567d357a474e2b9522d3b7f195b3fb
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/112600
Reviewed-by: Ben Clayton <bclayton@google.com>
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
Kokoro: Ben Clayton <bclayton@google.com>
This commit is contained in:
Corentin Wallez 2022-12-07 13:53:04 +00:00 committed by Dawn LUCI CQ
parent 4c8f5a1ac2
commit 6be7f3212b
7 changed files with 207 additions and 98 deletions

View File

@ -59,6 +59,8 @@ add_library(dawn_node_binding STATIC
"GPUSampler.h"
"GPUShaderModule.cpp"
"GPUShaderModule.h"
"GPUSupportedFeatures.cpp"
"GPUSupportedFeatures.h"
"GPUSupportedLimits.cpp"
"GPUSupportedLimits.h"
"GPUTexture.cpp"

View File

@ -1622,6 +1622,85 @@ bool Converter::Convert(wgpu::QueryType& out, const interop::GPUQueryType& in) {
return false;
}
bool Converter::Convert(wgpu::FeatureName& out, interop::GPUFeatureName in) {
switch (in) {
case interop::GPUFeatureName::kTextureCompressionBc:
out = wgpu::FeatureName::TextureCompressionBC;
return true;
case interop::GPUFeatureName::kTextureCompressionEtc2:
out = wgpu::FeatureName::TextureCompressionETC2;
return true;
case interop::GPUFeatureName::kTextureCompressionAstc:
out = wgpu::FeatureName::TextureCompressionASTC;
return true;
case interop::GPUFeatureName::kTimestampQuery:
out = wgpu::FeatureName::TimestampQuery;
return true;
case interop::GPUFeatureName::kDepth32FloatStencil8:
out = wgpu::FeatureName::Depth32FloatStencil8;
return true;
case interop::GPUFeatureName::kDepthClipControl:
out = wgpu::FeatureName::DepthClipControl;
return true;
case interop::GPUFeatureName::kIndirectFirstInstance:
out = wgpu::FeatureName::IndirectFirstInstance;
return true;
case interop::GPUFeatureName::kShaderF16:
out = wgpu::FeatureName::ShaderF16;
return true;
case interop::GPUFeatureName::kRg11B10UfloatRenderable:
out = wgpu::FeatureName::RG11B10UfloatRenderable;
return true;
case interop::GPUFeatureName::kBgra8UnormStorage:
// TODO(dawn:1123) Add support for these extensions when possible.
return false;
}
return false;
}
bool Converter::Convert(interop::GPUFeatureName& out, wgpu::FeatureName in) {
switch (in) {
case wgpu::FeatureName::Depth32FloatStencil8:
out = interop::GPUFeatureName::kDepth32FloatStencil8;
return true;
case wgpu::FeatureName::TimestampQuery:
out = interop::GPUFeatureName::kTimestampQuery;
return true;
case wgpu::FeatureName::TextureCompressionBC:
out = interop::GPUFeatureName::kTextureCompressionBc;
return true;
case wgpu::FeatureName::TextureCompressionETC2:
out = interop::GPUFeatureName::kTextureCompressionEtc2;
return true;
case wgpu::FeatureName::TextureCompressionASTC:
out = interop::GPUFeatureName::kTextureCompressionAstc;
return true;
case wgpu::FeatureName::IndirectFirstInstance:
out = interop::GPUFeatureName::kIndirectFirstInstance;
return true;
case wgpu::FeatureName::DepthClipControl:
out = interop::GPUFeatureName::kDepthClipControl;
return true;
case wgpu::FeatureName::ShaderF16:
out = interop::GPUFeatureName::kShaderF16;
return true;
case wgpu::FeatureName::RG11B10UfloatRenderable:
out = interop::GPUFeatureName::kRg11B10UfloatRenderable;
return true;
case wgpu::FeatureName::PipelineStatisticsQuery:
case wgpu::FeatureName::DawnShaderFloat16:
case wgpu::FeatureName::DawnInternalUsages:
case wgpu::FeatureName::DawnMultiPlanarFormats:
case wgpu::FeatureName::DawnNative:
case wgpu::FeatureName::ChromiumExperimentalDp4a:
case wgpu::FeatureName::TimestampQueryInsidePasses:
case wgpu::FeatureName::Undefined:
return false;
}
return false;
}
bool Converter::Convert(interop::GPUQueryType& out, wgpu::QueryType in) {
switch (in) {
case wgpu::QueryType::Occlusion:

View File

@ -270,6 +270,12 @@ class Converter {
[[nodiscard]] bool Convert(interop::GPUQueryType& out, wgpu::QueryType in);
// The two conversion methods don't generate an error when false is returned. That
// responsibility is left to the caller if it is needed (it isn't always needed, see
// https://gpuweb.github.io/gpuweb/#gpu-supportedfeatures)
[[nodiscard]] bool Convert(wgpu::FeatureName& out, interop::GPUFeatureName in);
[[nodiscard]] bool Convert(interop::GPUFeatureName& out, wgpu::FeatureName in);
// std::string to C string
inline bool Convert(const char*& out, const std::string& in) {
out = in.c_str();

View File

@ -18,9 +18,11 @@
#include <utility>
#include <vector>
#include "src/dawn/node/binding/Converter.h"
#include "src/dawn/node/binding/Errors.h"
#include "src/dawn/node/binding/Flags.h"
#include "src/dawn/node/binding/GPUDevice.h"
#include "src/dawn/node/binding/GPUSupportedFeatures.h"
#include "src/dawn/node/binding/GPUSupportedLimits.h"
namespace {
@ -88,72 +90,6 @@ std::vector<std::string> Split(const std::string& s, char delim) {
namespace wgpu::binding {
namespace {
////////////////////////////////////////////////////////////////////////////////
// wgpu::binding::<anon>::Features
// Implements interop::GPUSupportedFeatures
////////////////////////////////////////////////////////////////////////////////
class Features : public interop::GPUSupportedFeatures {
public:
explicit Features(std::vector<wgpu::FeatureName> features) {
for (wgpu::FeatureName feature : features) {
switch (feature) {
case wgpu::FeatureName::Depth32FloatStencil8:
enabled_.emplace(interop::GPUFeatureName::kDepth32FloatStencil8);
break;
case wgpu::FeatureName::TimestampQuery:
enabled_.emplace(interop::GPUFeatureName::kTimestampQuery);
break;
case wgpu::FeatureName::TextureCompressionBC:
enabled_.emplace(interop::GPUFeatureName::kTextureCompressionBc);
break;
case wgpu::FeatureName::TextureCompressionETC2:
enabled_.emplace(interop::GPUFeatureName::kTextureCompressionEtc2);
break;
case wgpu::FeatureName::TextureCompressionASTC:
enabled_.emplace(interop::GPUFeatureName::kTextureCompressionAstc);
break;
case wgpu::FeatureName::IndirectFirstInstance:
enabled_.emplace(interop::GPUFeatureName::kIndirectFirstInstance);
break;
case wgpu::FeatureName::DepthClipControl:
enabled_.emplace(interop::GPUFeatureName::kDepthClipControl);
break;
default:
break;
}
}
// TODO(dawn:1123) add support for these extensions when possible.
// wgpu::interop::GPUFeatureName::kShaderF16
// wgpu::interop::GPUFeatureName::kBgra8UnormStorage
}
bool has(interop::GPUFeatureName feature) { return enabled_.count(feature) != 0; }
// interop::GPUSupportedFeatures compliance
bool has(Napi::Env, std::string name) override {
interop::GPUFeatureName feature;
if (interop::Converter<interop::GPUFeatureName>::FromString(name, feature)) {
return has(feature);
}
return false;
}
std::vector<std::string> keys(Napi::Env) override {
std::vector<std::string> out;
out.reserve(enabled_.size());
for (auto feature : enabled_) {
out.push_back(interop::Converter<interop::GPUFeatureName>::ToString(feature));
}
return out;
}
private:
std::unordered_set<interop::GPUFeatureName> enabled_;
};
} // namespace
////////////////////////////////////////////////////////////////////////////////
// wgpu::bindings::GPUAdapter
// TODO(crbug.com/dawn/1133): This is a stub implementation. Properly implement.
@ -167,7 +103,8 @@ interop::Interface<interop::GPUSupportedFeatures> GPUAdapter::getFeatures(Napi::
size_t count = adapter.EnumerateFeatures(nullptr);
std::vector<wgpu::FeatureName> features(count);
adapter.EnumerateFeatures(&features[0]);
return interop::GPUSupportedFeatures::Create<Features>(env, std::move(features));
return interop::GPUSupportedFeatures::Create<GPUSupportedFeatures>(env, env,
std::move(features));
}
interop::Interface<interop::GPUSupportedLimits> GPUAdapter::getLimits(Napi::Env env) {
@ -195,34 +132,19 @@ interop::Promise<interop::Interface<interop::GPUDevice>> GPUAdapter::requestDevi
wgpu::DeviceDescriptor desc{}; // TODO(crbug.com/dawn/1133): Fill in.
interop::Promise<interop::Interface<interop::GPUDevice>> promise(env, PROMISE_INFO);
Converter conv(env);
std::vector<wgpu::FeatureName> requiredFeatures;
// See src/dawn/native/Features.cpp for enum <-> string mappings.
for (auto required : descriptor.requiredFeatures) {
switch (required) {
case interop::GPUFeatureName::kTextureCompressionBc:
requiredFeatures.emplace_back(wgpu::FeatureName::TextureCompressionBC);
continue;
case interop::GPUFeatureName::kTextureCompressionEtc2:
requiredFeatures.emplace_back(wgpu::FeatureName::TextureCompressionETC2);
continue;
case interop::GPUFeatureName::kTextureCompressionAstc:
requiredFeatures.emplace_back(wgpu::FeatureName::TextureCompressionASTC);
continue;
case interop::GPUFeatureName::kTimestampQuery:
requiredFeatures.emplace_back(wgpu::FeatureName::TimestampQuery);
continue;
case interop::GPUFeatureName::kDepth32FloatStencil8:
requiredFeatures.emplace_back(wgpu::FeatureName::Depth32FloatStencil8);
continue;
case interop::GPUFeatureName::kDepthClipControl:
case interop::GPUFeatureName::kShaderF16:
case interop::GPUFeatureName::kIndirectFirstInstance:
case interop::GPUFeatureName::kBgra8UnormStorage:
case interop::GPUFeatureName::kRg11B10UfloatRenderable:
// TODO(dawn:1123) Add support for these extensions when possible.
continue;
wgpu::FeatureName feature = wgpu::FeatureName::Undefined;
// requiredFeatures is a "sequence<GPUFeatureName>" so a Javascript exception should be
// thrown if one of the strings isn't one of the known features.
if (!conv(feature, required)) {
Napi::Error::New(env, "invalid value for GPUFeatureName").ThrowAsJavaScriptException();
return promise;
}
UNIMPLEMENTED("required: ", required);
requiredFeatures.emplace_back(feature);
}
wgpu::RequiredLimits limits;

View File

@ -33,6 +33,7 @@
#include "src/dawn/node/binding/GPURenderPipeline.h"
#include "src/dawn/node/binding/GPUSampler.h"
#include "src/dawn/node/binding/GPUShaderModule.h"
#include "src/dawn/node/binding/GPUSupportedFeatures.h"
#include "src/dawn/node/binding/GPUSupportedLimits.h"
#include "src/dawn/node/binding/GPUTexture.h"
#include "src/dawn/node/utils/Debug.h"
@ -178,12 +179,11 @@ GPUDevice::~GPUDevice() {
}
interop::Interface<interop::GPUSupportedFeatures> GPUDevice::getFeatures(Napi::Env env) {
class Features : public interop::GPUSupportedFeatures {
public:
bool has(Napi::Env, std::string feature) override { UNIMPLEMENTED(); }
std::vector<std::string> keys(Napi::Env) override { UNIMPLEMENTED(); }
};
return interop::GPUSupportedFeatures::Create<Features>(env);
size_t count = device_.EnumerateFeatures(nullptr);
std::vector<wgpu::FeatureName> features(count);
device_.EnumerateFeatures(&features[0]);
return interop::GPUSupportedFeatures::Create<GPUSupportedFeatures>(env, env,
std::move(features));
}
interop::Interface<interop::GPUSupportedLimits> GPUDevice::getLimits(Napi::Env env) {

View File

@ -0,0 +1,56 @@
// Copyright 2022 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 "src/dawn/node/binding/GPUSupportedFeatures.h"
#include "src/dawn/node/binding/Converter.h"
namespace wgpu::binding {
////////////////////////////////////////////////////////////////////////////////
// wgpu::bindings::GPUSupportedFeatures
////////////////////////////////////////////////////////////////////////////////
GPUSupportedFeatures::GPUSupportedFeatures(Napi::Env env, std::vector<wgpu::FeatureName> features) {
Converter conv(env);
// Add all known GPUFeatureNames that are known by dawn.node and skip the other ones are they
// may be native-only extension, Dawn-specific or other special cases.
for (wgpu::FeatureName feature : features) {
interop::GPUFeatureName gpuFeature;
if (conv(gpuFeature, feature)) {
enabled_.emplace(gpuFeature);
}
}
}
bool GPUSupportedFeatures::has(Napi::Env, std::string name) {
interop::GPUFeatureName feature;
if (!interop::Converter<interop::GPUFeatureName>::FromString(name, feature)) {
return false;
}
return enabled_.count(feature);
}
std::vector<std::string> GPUSupportedFeatures::keys(Napi::Env) {
std::vector<std::string> out;
out.reserve(enabled_.size());
for (auto feature : enabled_) {
out.push_back(interop::Converter<interop::GPUFeatureName>::ToString(feature));
}
return out;
}
} // namespace wgpu::binding

View File

@ -0,0 +1,44 @@
// Copyright 2022 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 SRC_DAWN_NODE_BINDING_GPUSUPPORTEDFEATURES_H_
#define SRC_DAWN_NODE_BINDING_GPUSUPPORTEDFEATURES_H_
#include <string>
#include <unordered_set>
#include <vector>
#include "dawn/webgpu_cpp.h"
#include "src/dawn/node/interop/Napi.h"
#include "src/dawn/node/interop/WebGPU.h"
namespace wgpu::binding {
// GPUSupportedLFeatures is an implementation of interop::GPUSupportedFeatures.
class GPUSupportedFeatures final : public interop::GPUSupportedFeatures {
public:
GPUSupportedFeatures(Napi::Env env, std::vector<wgpu::FeatureName> features);
// interop::GPUSupportedFeatures interface compliance
bool has(Napi::Env, std::string name) override;
std::vector<std::string> keys(Napi::Env) override;
private:
std::unordered_set<interop::GPUFeatureName> enabled_;
};
} // namespace wgpu::binding
#endif // SRC_DAWN_NODE_BINDING_GPUSUPPORTEDFEATURES_H_