diff --git a/src/dawn/node/binding/CMakeLists.txt b/src/dawn/node/binding/CMakeLists.txt index 7907ae7d72..a4e427b253 100644 --- a/src/dawn/node/binding/CMakeLists.txt +++ b/src/dawn/node/binding/CMakeLists.txt @@ -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" diff --git a/src/dawn/node/binding/Converter.cpp b/src/dawn/node/binding/Converter.cpp index f2718bd886..524fdca56b 100644 --- a/src/dawn/node/binding/Converter.cpp +++ b/src/dawn/node/binding/Converter.cpp @@ -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: diff --git a/src/dawn/node/binding/Converter.h b/src/dawn/node/binding/Converter.h index 564b8a608a..16ad9b95a4 100644 --- a/src/dawn/node/binding/Converter.h +++ b/src/dawn/node/binding/Converter.h @@ -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(); diff --git a/src/dawn/node/binding/GPUAdapter.cpp b/src/dawn/node/binding/GPUAdapter.cpp index c396a6aaee..73c8c11cc1 100644 --- a/src/dawn/node/binding/GPUAdapter.cpp +++ b/src/dawn/node/binding/GPUAdapter.cpp @@ -18,9 +18,11 @@ #include #include +#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 Split(const std::string& s, char delim) { namespace wgpu::binding { -namespace { - -//////////////////////////////////////////////////////////////////////////////// -// wgpu::binding::::Features -// Implements interop::GPUSupportedFeatures -//////////////////////////////////////////////////////////////////////////////// -class Features : public interop::GPUSupportedFeatures { - public: - explicit Features(std::vector 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::FromString(name, feature)) { - return has(feature); - } - return false; - } - std::vector keys(Napi::Env) override { - std::vector out; - out.reserve(enabled_.size()); - for (auto feature : enabled_) { - out.push_back(interop::Converter::ToString(feature)); - } - return out; - } - - private: - std::unordered_set enabled_; -}; - -} // namespace - //////////////////////////////////////////////////////////////////////////////// // wgpu::bindings::GPUAdapter // TODO(crbug.com/dawn/1133): This is a stub implementation. Properly implement. @@ -167,7 +103,8 @@ interop::Interface GPUAdapter::getFeatures(Napi:: size_t count = adapter.EnumerateFeatures(nullptr); std::vector features(count); adapter.EnumerateFeatures(&features[0]); - return interop::GPUSupportedFeatures::Create(env, std::move(features)); + return interop::GPUSupportedFeatures::Create(env, env, + std::move(features)); } interop::Interface GPUAdapter::getLimits(Napi::Env env) { @@ -195,34 +132,19 @@ interop::Promise> GPUAdapter::requestDevi wgpu::DeviceDescriptor desc{}; // TODO(crbug.com/dawn/1133): Fill in. interop::Promise> promise(env, PROMISE_INFO); + Converter conv(env); std::vector 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" 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; diff --git a/src/dawn/node/binding/GPUDevice.cpp b/src/dawn/node/binding/GPUDevice.cpp index 5aab3eb0b8..362362114c 100644 --- a/src/dawn/node/binding/GPUDevice.cpp +++ b/src/dawn/node/binding/GPUDevice.cpp @@ -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 GPUDevice::getFeatures(Napi::Env env) { - class Features : public interop::GPUSupportedFeatures { - public: - bool has(Napi::Env, std::string feature) override { UNIMPLEMENTED(); } - std::vector keys(Napi::Env) override { UNIMPLEMENTED(); } - }; - return interop::GPUSupportedFeatures::Create(env); + size_t count = device_.EnumerateFeatures(nullptr); + std::vector features(count); + device_.EnumerateFeatures(&features[0]); + return interop::GPUSupportedFeatures::Create(env, env, + std::move(features)); } interop::Interface GPUDevice::getLimits(Napi::Env env) { diff --git a/src/dawn/node/binding/GPUSupportedFeatures.cpp b/src/dawn/node/binding/GPUSupportedFeatures.cpp new file mode 100644 index 0000000000..cebce06e20 --- /dev/null +++ b/src/dawn/node/binding/GPUSupportedFeatures.cpp @@ -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 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::FromString(name, feature)) { + return false; + } + + return enabled_.count(feature); +} + +std::vector GPUSupportedFeatures::keys(Napi::Env) { + std::vector out; + out.reserve(enabled_.size()); + for (auto feature : enabled_) { + out.push_back(interop::Converter::ToString(feature)); + } + return out; +} + +} // namespace wgpu::binding diff --git a/src/dawn/node/binding/GPUSupportedFeatures.h b/src/dawn/node/binding/GPUSupportedFeatures.h new file mode 100644 index 0000000000..922cefa163 --- /dev/null +++ b/src/dawn/node/binding/GPUSupportedFeatures.h @@ -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 +#include +#include + +#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 features); + + // interop::GPUSupportedFeatures interface compliance + bool has(Napi::Env, std::string name) override; + std::vector keys(Napi::Env) override; + + private: + std::unordered_set enabled_; +}; + +} // namespace wgpu::binding + +#endif // SRC_DAWN_NODE_BINDING_GPUSUPPORTEDFEATURES_H_