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 <bclayton@google.com>
Reviewed-by: Austin Eng <enga@chromium.org>
diff --git a/src/dawn_node/binding/GPUAdapter.cpp b/src/dawn_node/binding/GPUAdapter.cpp
index 0d47304..b86d747 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::<anon>::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<interop::GPUFeatureName>::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 @@
}
interop::Interface<interop::GPUSupportedFeatures> GPUAdapter::getFeatures(Napi::Env env) {
- class Features : public interop::GPUSupportedFeatures {};
- return interop::GPUSupportedFeatures::Create<Features>(env);
+ return interop::GPUSupportedFeatures::Create<Features>(env,
+ adapter_.GetAdapterProperties());
}
interop::Interface<interop::GPUSupportedLimits> GPUAdapter::getLimits(Napi::Env env) {
@@ -49,6 +94,30 @@
dawn_native::DeviceDescriptor desc{}; // TODO(crbug.com/dawn/1133): Fill in.
interop::Promise<interop::Interface<interop::GPUDevice>> 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<GPUDevice>(env, env, wgpu_device));
@@ -57,5 +126,4 @@
}
return promise;
}
-
}} // namespace wgpu::binding
diff --git a/src/dawn_node/binding/GPUDevice.cpp b/src/dawn_node/binding/GPUDevice.cpp
index d87da51..5d40b26 100644
--- a/src/dawn_node/binding/GPUDevice.cpp
+++ b/src/dawn_node/binding/GPUDevice.cpp
@@ -109,7 +109,12 @@
}
interop::Interface<interop::GPUSupportedFeatures> 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<Features>(env);
}
diff --git a/src/dawn_node/interop/WebGPU.cpp.tmpl b/src/dawn_node/interop/WebGPU.cpp.tmpl
index d52a991..388bb96 100644
--- a/src/dawn_node/interop/WebGPU.cpp.tmpl
+++ b/src/dawn_node/interop/WebGPU.cpp.tmpl
@@ -141,6 +141,9 @@
{{- 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 @@
}
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 @@
--------------------------------------------------------------------------------
*/ -}}
{{- 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 @@
{{- 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 7c791c6..62a222c 100644
--- a/src/dawn_node/interop/WebGPU.h.tmpl
+++ b/src/dawn_node/interop/WebGPU.h.tmpl
@@ -123,6 +123,9 @@
virtual ~{{$.Name}}();
{{$.Name}}();
+{{- if $s := SetlikeOf $}}
+{{- template "InterfaceSetlike" $s}}
+{{- end}}
{{- range $m := MethodsOf $}}
{{- template "InterfaceMethod" $m}}
{{- end}}
@@ -165,6 +168,7 @@
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}});
@@ -186,6 +190,20 @@
{{- /*
--------------------------------------------------------------------------------
+-- 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
-- method
--------------------------------------------------------------------------------
diff --git a/src/dawn_node/tools/cmd/idlgen/main.go b/src/dawn_node/tools/cmd/idlgen/main.go
index e8e4104..5ea5499 100644
--- a/src/dawn_node/tools/cmd/idlgen/main.go
+++ b/src/dawn_node/tools/cmd/idlgen/main.go
@@ -128,6 +128,7 @@
"IsUnionType": is(ast.UnionType{}),
"Lookup": g.lookup,
"MethodsOf": methodsOf,
+ "SetlikeOf": setlikeOf,
"Title": strings.Title,
}
t, err := g.t.
@@ -569,6 +570,20 @@
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