From 7ed06243377fbbb0171391018780d8b88a2d0c77 Mon Sep 17 00:00:00 2001 From: Ben Clayton Date: Thu, 30 Sep 2021 07:17:33 +0000 Subject: [PATCH] dawn_node: Begin implementing GPUSupportedFeatures Requires setlike interface interop. Bug: dawn:1123 Bug: dawn:1143 Change-Id: I1451f72b32b99858be871db99888f86872b53fd0 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/65245 Commit-Queue: Ben Clayton Reviewed-by: Austin Eng --- src/dawn_node/binding/GPUAdapter.cpp | 74 ++++++++++++++++++++++++-- src/dawn_node/binding/GPUDevice.cpp | 7 ++- src/dawn_node/interop/WebGPU.cpp.tmpl | 20 ++++++- src/dawn_node/interop/WebGPU.h.tmpl | 18 +++++++ src/dawn_node/tools/cmd/idlgen/main.go | 15 ++++++ 5 files changed, 128 insertions(+), 6 deletions(-) diff --git a/src/dawn_node/binding/GPUAdapter.cpp b/src/dawn_node/binding/GPUAdapter.cpp index 0d473045b3..b86d747489 100644 --- a/src/dawn_node/binding/GPUAdapter.cpp +++ b/src/dawn_node/binding/GPUAdapter.cpp @@ -19,6 +19,51 @@ namespace wgpu { namespace binding { + namespace { + + //////////////////////////////////////////////////////////////////////////////// + // wgpu::binding::::Features + // Implements interop::GPUSupportedFeatures + //////////////////////////////////////////////////////////////////////////////// + class Features : public interop::GPUSupportedFeatures { + public: + Features(WGPUDeviceProperties properties) : properties_(std::move(properties)) { + } + + bool has(interop::GPUFeatureName feature) { + switch (feature) { + case interop::GPUFeatureName::kDepthClamping: + return properties_.depthClamping; + case interop::GPUFeatureName::kDepth24UnormStencil8: + return false; // TODO(crbug.com/dawn/1130) + case interop::GPUFeatureName::kDepth32FloatStencil8: + return false; // TODO(crbug.com/dawn/1130) + case interop::GPUFeatureName::kPipelineStatisticsQuery: + return properties_.pipelineStatisticsQuery; + case interop::GPUFeatureName::kTextureCompressionBc: + return properties_.textureCompressionBC; + case interop::GPUFeatureName::kTimestampQuery: + return properties_.timestampQuery; + } + UNIMPLEMENTED("feature: ", feature); + return false; + } + + // 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; + } + + private: + WGPUDeviceProperties properties_; + }; + + } // namespace + //////////////////////////////////////////////////////////////////////////////// // wgpu::bindings::GPUAdapter // TODO(crbug.com/dawn/1133): This is a stub implementation. Properly implement. @@ -31,8 +76,8 @@ namespace wgpu { namespace binding { } interop::Interface GPUAdapter::getFeatures(Napi::Env env) { - class Features : public interop::GPUSupportedFeatures {}; - return interop::GPUSupportedFeatures::Create(env); + return interop::GPUSupportedFeatures::Create(env, + adapter_.GetAdapterProperties()); } interop::Interface GPUAdapter::getLimits(Napi::Env env) { @@ -49,6 +94,30 @@ namespace wgpu { namespace binding { dawn_native::DeviceDescriptor desc{}; // TODO(crbug.com/dawn/1133): Fill in. interop::Promise> promise(env); + if (descriptor.has_value()) { + // See src/dawn_native/Extensions.cpp for feature <-> extension mappings. + for (auto required : descriptor->requiredFeatures) { + switch (required) { + case interop::GPUFeatureName::kDepthClamping: + desc.requiredExtensions.emplace_back("depth_clamping"); + continue; + case interop::GPUFeatureName::kPipelineStatisticsQuery: + desc.requiredExtensions.emplace_back("pipeline_statistics_query"); + continue; + case interop::GPUFeatureName::kTextureCompressionBc: + desc.requiredExtensions.emplace_back("texture_compression_bc"); + continue; + case interop::GPUFeatureName::kTimestampQuery: + desc.requiredExtensions.emplace_back("timestamp_query"); + continue; + case interop::GPUFeatureName::kDepth24UnormStencil8: + case interop::GPUFeatureName::kDepth32FloatStencil8: + continue; // TODO(crbug.com/dawn/1130) + } + UNIMPLEMENTED("required: ", required); + } + } + auto wgpu_device = adapter_.CreateDevice(&desc); if (wgpu_device) { promise.Resolve(interop::GPUDevice::Create(env, env, wgpu_device)); @@ -57,5 +126,4 @@ namespace wgpu { namespace binding { } return promise; } - }} // namespace wgpu::binding diff --git a/src/dawn_node/binding/GPUDevice.cpp b/src/dawn_node/binding/GPUDevice.cpp index d87da51c94..5d40b2687b 100644 --- a/src/dawn_node/binding/GPUDevice.cpp +++ b/src/dawn_node/binding/GPUDevice.cpp @@ -109,7 +109,12 @@ namespace wgpu { namespace binding { } interop::Interface GPUDevice::getFeatures(Napi::Env env) { - class Features : public interop::GPUSupportedFeatures {}; + class Features : public interop::GPUSupportedFeatures { + public: + bool has(Napi::Env, std::string feature) override { + UNIMPLEMENTED(); + } + }; return interop::GPUSupportedFeatures::Create(env); } diff --git a/src/dawn_node/interop/WebGPU.cpp.tmpl b/src/dawn_node/interop/WebGPU.cpp.tmpl index d52a991b05..388bb963be 100644 --- a/src/dawn_node/interop/WebGPU.cpp.tmpl +++ b/src/dawn_node/interop/WebGPU.cpp.tmpl @@ -141,6 +141,9 @@ Wrappers* Wrappers::instance = nullptr; {{- end}} static Napi::Function Class(Napi::Env env) { return DefineClass(env, "{{$.Name}}", { +{{ if $s := SetlikeOf $}} + InstanceMethod("has", &W{{$.Name}}::has), +{{- end}} {{- range $m := MethodsOf $}} InstanceMethod("{{$m.Name}}", &W{{$.Name}}::{{$m.Name}}), {{- end}} @@ -156,6 +159,17 @@ Wrappers* Wrappers::instance = nullptr; } W{{$.Name}}(const Napi::CallbackInfo& info) : ObjectWrap(info) {} + +{{ if $s := SetlikeOf $}} + Napi::Value has(const Napi::CallbackInfo& info) { + std::tuple<{{template "Type" $s.Elem}}> args; + if (FromJS(info, args)) { + return ToJS(info.Env(), impl->has(info.Env(), std::get<0>(args))); + } + Napi::Error::New(info.Env(), "invalid arguments to has()").ThrowAsJavaScriptException(); + return {}; + } +{{- end}} {{- range $m := MethodsOf $}} Napi::Value {{$m.Name}}(const Napi::CallbackInfo& info) { {{- range $overload_idx, $o := $m.Overloads}} @@ -307,8 +321,7 @@ Interface<{{$.Name}}> {{$.Name}}::Bind(Napi::Env env, std::unique_ptr<{{$.Name}} -------------------------------------------------------------------------------- */ -}} {{- define "Enum"}} -bool Converter<{{$.Name}}>::FromJS(Napi::Env env, Napi::Value value, {{$.Name}}& out) { - std::string str = value.ToString(); +bool Converter<{{$.Name}}>::FromString(std::string str, {{$.Name}}& out) { {{- range $e := $.Values}} if (str == {{$e.Value}}) { out = {{$.Name}}::{{EnumEntryName $e.Value}}; @@ -317,6 +330,9 @@ bool Converter<{{$.Name}}>::FromJS(Napi::Env env, Napi::Value value, {{$.Name}}& {{- end}} return false; } +bool Converter<{{$.Name}}>::FromJS(Napi::Env env, Napi::Value value, {{$.Name}}& out) { + return FromString(value.ToString(), out); +} Napi::Value Converter<{{$.Name}}>::ToJS(Napi::Env env, {{$.Name}} value) { switch (value) { {{- range $e := $.Values}} diff --git a/src/dawn_node/interop/WebGPU.h.tmpl b/src/dawn_node/interop/WebGPU.h.tmpl index 7c791c6c77..62a222c4d4 100644 --- a/src/dawn_node/interop/WebGPU.h.tmpl +++ b/src/dawn_node/interop/WebGPU.h.tmpl @@ -123,6 +123,9 @@ public: virtual ~{{$.Name}}(); {{$.Name}}(); +{{- if $s := SetlikeOf $}} +{{- template "InterfaceSetlike" $s}} +{{- end}} {{- range $m := MethodsOf $}} {{- template "InterfaceMethod" $m}} {{- end}} @@ -165,6 +168,7 @@ class Converter<{{$.Name}}> { public: static bool FromJS(Napi::Env, Napi::Value, {{$.Name}}&); static Napi::Value ToJS(Napi::Env, {{$.Name}}); + static bool FromString(std::string, {{$.Name}}&); }; std::ostream& operator<<(std::ostream& o, {{$.Name}}); @@ -184,6 +188,20 @@ std::ostream& operator<<(std::ostream& o, {{$.Name}}); {{- end }} +{{- /* +-------------------------------------------------------------------------------- +-- InterfaceSetlike emits the C++ methods for a setlike interface +-------------------------------------------------------------------------------- +*/ -}} +{{- define "InterfaceSetlike"}} + virtual bool has(Napi::Env, {{template "Type" $.Elem}}) = 0; +{{- /* TODO(crbug.com/dawn/1143): + entries, forEach, keys, size, values + read-write: add, clear, or delete +*/}} +{{- end }} + + {{- /* -------------------------------------------------------------------------------- -- InterfaceMethod emits the C++ declaration for a single interface ast.Member diff --git a/src/dawn_node/tools/cmd/idlgen/main.go b/src/dawn_node/tools/cmd/idlgen/main.go index e8e4104bde..5ea5499fcc 100644 --- a/src/dawn_node/tools/cmd/idlgen/main.go +++ b/src/dawn_node/tools/cmd/idlgen/main.go @@ -128,6 +128,7 @@ func run() error { "IsUnionType": is(ast.UnionType{}), "Lookup": g.lookup, "MethodsOf": methodsOf, + "SetlikeOf": setlikeOf, "Title": strings.Title, } t, err := g.t. @@ -569,6 +570,20 @@ func constantsOf(obj interface{}) []*ast.Member { return out } +// setlikeOf returns the setlike ast.Pattern, if obj is a setlike interface. +func setlikeOf(obj interface{}) *ast.Pattern { + iface, ok := obj.(*ast.Interface) + if !ok { + return nil + } + for _, pattern := range iface.Patterns { + if pattern.Type == ast.Setlike { + return pattern + } + } + return nil +} + // pascalCase returns the snake-case string s transformed into 'PascalCase', // Rules: // * The first letter of the string is capitalized