• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 The Dawn Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "src/dawn_node/binding/GPUAdapter.h"
16 
17 #include <unordered_set>
18 
19 #include "src/dawn_node/binding/Flags.h"
20 #include "src/dawn_node/binding/GPUDevice.h"
21 #include "src/dawn_node/binding/GPUSupportedLimits.h"
22 
23 namespace {
24     // TODO(amaiorano): Move to utility header
Split(const std::string & s,char delim)25     std::vector<std::string> Split(const std::string& s, char delim) {
26         if (s.empty())
27             return {};
28 
29         std::vector<std::string> result;
30         const size_t lastIndex = s.length() - 1;
31         size_t startIndex = 0;
32         size_t i = startIndex;
33 
34         while (i <= lastIndex) {
35             if (s[i] == delim) {
36                 auto token = s.substr(startIndex, i - startIndex);
37                 if (!token.empty())  // Discard empty tokens
38                     result.push_back(token);
39                 startIndex = i + 1;
40             } else if (i == lastIndex) {
41                 auto token = s.substr(startIndex, i - startIndex + 1);
42                 if (!token.empty())  // Discard empty tokens
43                     result.push_back(token);
44             }
45             ++i;
46         }
47         return result;
48     }
49 }  // namespace
50 
51 namespace wgpu { namespace binding {
52 
53     namespace {
54 
55         ////////////////////////////////////////////////////////////////////////////////
56         // wgpu::binding::<anon>::Features
57         // Implements interop::GPUSupportedFeatures
58         ////////////////////////////////////////////////////////////////////////////////
59         class Features : public interop::GPUSupportedFeatures {
60           public:
Features(WGPUDeviceProperties properties)61             Features(WGPUDeviceProperties properties) {
62                 if (properties.depthClamping) {
63                     enabled_.emplace(interop::GPUFeatureName::kDepthClamping);
64                 }
65                 if (properties.pipelineStatisticsQuery) {
66                     enabled_.emplace(interop::GPUFeatureName::kPipelineStatisticsQuery);
67                 }
68                 if (properties.textureCompressionBC) {
69                     enabled_.emplace(interop::GPUFeatureName::kTextureCompressionBc);
70                 }
71                 if (properties.timestampQuery) {
72                     enabled_.emplace(interop::GPUFeatureName::kTimestampQuery);
73                 }
74 
75                 // TODO(crbug.com/dawn/1130)
76                 // interop::GPUFeatureName::kDepth24UnormStencil8:
77                 // interop::GPUFeatureName::kDepth32FloatStencil8:
78             }
79 
has(interop::GPUFeatureName feature)80             bool has(interop::GPUFeatureName feature) {
81                 return enabled_.count(feature) != 0;
82             }
83 
84             // interop::GPUSupportedFeatures compliance
has(Napi::Env,std::string name)85             bool has(Napi::Env, std::string name) override {
86                 interop::GPUFeatureName feature;
87                 if (interop::Converter<interop::GPUFeatureName>::FromString(name, feature)) {
88                     return has(feature);
89                 }
90                 return false;
91             }
keys(Napi::Env)92             std::vector<std::string> keys(Napi::Env) override {
93                 std::vector<std::string> out;
94                 out.reserve(enabled_.size());
95                 for (auto feature : enabled_) {
96                     out.push_back(interop::Converter<interop::GPUFeatureName>::ToString(feature));
97                 }
98                 return out;
99             }
100 
101           private:
102             std::unordered_set<interop::GPUFeatureName> enabled_;
103         };
104 
105     }  // namespace
106 
107     ////////////////////////////////////////////////////////////////////////////////
108     // wgpu::bindings::GPUAdapter
109     // TODO(crbug.com/dawn/1133): This is a stub implementation. Properly implement.
110     ////////////////////////////////////////////////////////////////////////////////
GPUAdapter(dawn_native::Adapter a,const Flags & flags)111     GPUAdapter::GPUAdapter(dawn_native::Adapter a, const Flags& flags)
112         : adapter_(a), flags_(flags) {
113     }
114 
getName(Napi::Env)115     std::string GPUAdapter::getName(Napi::Env) {
116         return "dawn-adapter";
117     }
118 
getFeatures(Napi::Env env)119     interop::Interface<interop::GPUSupportedFeatures> GPUAdapter::getFeatures(Napi::Env env) {
120         return interop::GPUSupportedFeatures::Create<Features>(env,
121                                                                adapter_.GetAdapterProperties());
122     }
123 
getLimits(Napi::Env env)124     interop::Interface<interop::GPUSupportedLimits> GPUAdapter::getLimits(Napi::Env env) {
125         WGPUSupportedLimits limits{};
126         if (!adapter_.GetLimits(&limits)) {
127             Napi::Error::New(env, "failed to get adapter limits").ThrowAsJavaScriptException();
128         }
129 
130         wgpu::SupportedLimits wgpuLimits{};
131 
132 #define COPY_LIMIT(LIMIT) wgpuLimits.limits.LIMIT = limits.limits.LIMIT
133         COPY_LIMIT(maxTextureDimension1D);
134         COPY_LIMIT(maxTextureDimension2D);
135         COPY_LIMIT(maxTextureDimension3D);
136         COPY_LIMIT(maxTextureArrayLayers);
137         COPY_LIMIT(maxBindGroups);
138         COPY_LIMIT(maxDynamicUniformBuffersPerPipelineLayout);
139         COPY_LIMIT(maxDynamicStorageBuffersPerPipelineLayout);
140         COPY_LIMIT(maxSampledTexturesPerShaderStage);
141         COPY_LIMIT(maxSamplersPerShaderStage);
142         COPY_LIMIT(maxStorageBuffersPerShaderStage);
143         COPY_LIMIT(maxStorageTexturesPerShaderStage);
144         COPY_LIMIT(maxUniformBuffersPerShaderStage);
145         COPY_LIMIT(maxUniformBufferBindingSize);
146         COPY_LIMIT(maxStorageBufferBindingSize);
147         COPY_LIMIT(minUniformBufferOffsetAlignment);
148         COPY_LIMIT(minStorageBufferOffsetAlignment);
149         COPY_LIMIT(maxVertexBuffers);
150         COPY_LIMIT(maxVertexAttributes);
151         COPY_LIMIT(maxVertexBufferArrayStride);
152         COPY_LIMIT(maxInterStageShaderComponents);
153         COPY_LIMIT(maxComputeWorkgroupStorageSize);
154         COPY_LIMIT(maxComputeInvocationsPerWorkgroup);
155         COPY_LIMIT(maxComputeWorkgroupSizeX);
156         COPY_LIMIT(maxComputeWorkgroupSizeY);
157         COPY_LIMIT(maxComputeWorkgroupSizeZ);
158         COPY_LIMIT(maxComputeWorkgroupsPerDimension);
159 #undef COPY_LIMIT
160 
161         return interop::GPUSupportedLimits::Create<GPUSupportedLimits>(env, wgpuLimits);
162     }
163 
getIsFallbackAdapter(Napi::Env)164     bool GPUAdapter::getIsFallbackAdapter(Napi::Env) {
165         UNIMPLEMENTED();
166     }
167 
requestDevice(Napi::Env env,interop::GPUDeviceDescriptor descriptor)168     interop::Promise<interop::Interface<interop::GPUDevice>> GPUAdapter::requestDevice(
169         Napi::Env env,
170         interop::GPUDeviceDescriptor descriptor) {
171         dawn_native::DawnDeviceDescriptor desc{};  // TODO(crbug.com/dawn/1133): Fill in.
172         interop::Promise<interop::Interface<interop::GPUDevice>> promise(env, PROMISE_INFO);
173 
174         // See src/dawn_native/Features.cpp for enum <-> string mappings.
175         for (auto required : descriptor.requiredFeatures) {
176             switch (required) {
177                 case interop::GPUFeatureName::kDepthClamping:
178                     desc.requiredFeatures.emplace_back("depth-clamping");
179                     continue;
180                 case interop::GPUFeatureName::kPipelineStatisticsQuery:
181                     desc.requiredFeatures.emplace_back("pipeline-statistics-query");
182                     continue;
183                 case interop::GPUFeatureName::kTextureCompressionBc:
184                     desc.requiredFeatures.emplace_back("texture-compression-bc");
185                     continue;
186                 case interop::GPUFeatureName::kTimestampQuery:
187                     desc.requiredFeatures.emplace_back("timestamp-query");
188                     continue;
189                 case interop::GPUFeatureName::kDepth24UnormStencil8:
190                 case interop::GPUFeatureName::kDepth32FloatStencil8:
191                     continue;  // TODO(crbug.com/dawn/1130)
192             }
193             UNIMPLEMENTED("required: ", required);
194         }
195 
196         // Propogate enabled/disabled dawn features
197         // Note: DawnDeviceDescriptor::forceEnabledToggles and forceDisabledToggles are vectors of
198         // 'const char*', so we make sure the parsed strings survive the CreateDevice() call by
199         // storing them on the stack.
200         std::vector<std::string> enabledToggles;
201         std::vector<std::string> disabledToggles;
202         if (auto values = flags_.Get("enable-dawn-features")) {
203             enabledToggles = Split(*values, ',');
204             for (auto& t : enabledToggles) {
205                 desc.forceEnabledToggles.emplace_back(t.c_str());
206             }
207         }
208         if (auto values = flags_.Get("disable-dawn-features")) {
209             disabledToggles = Split(*values, ',');
210             for (auto& t : disabledToggles) {
211                 desc.forceDisabledToggles.emplace_back(t.c_str());
212             }
213         }
214 
215         auto wgpu_device = adapter_.CreateDevice(&desc);
216         if (wgpu_device) {
217             promise.Resolve(interop::GPUDevice::Create<GPUDevice>(env, env, wgpu_device));
218         } else {
219             Napi::Error::New(env, "failed to create device").ThrowAsJavaScriptException();
220         }
221         return promise;
222     }
223 }}  // namespace wgpu::binding
224