blob: ae11f9c407a7cac771109b1c7bec9eb575daf213 [file] [log] [blame]
Ben Claytonbc207f72021-09-29 08:48:43 +00001// 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
Ben Clayton902ad1f2022-02-04 12:51:25 +000015#include "src/dawn/node/binding/GPUDevice.h"
Ben Claytonbc207f72021-09-29 08:48:43 +000016
17#include <memory>
dan sinclair13e96992022-04-20 00:58:34 +000018#include <utility>
19#include <vector>
Ben Claytonbc207f72021-09-29 08:48:43 +000020
Ben Clayton902ad1f2022-02-04 12:51:25 +000021#include "src/dawn/node/binding/Converter.h"
22#include "src/dawn/node/binding/Errors.h"
23#include "src/dawn/node/binding/GPUBindGroup.h"
24#include "src/dawn/node/binding/GPUBindGroupLayout.h"
25#include "src/dawn/node/binding/GPUBuffer.h"
26#include "src/dawn/node/binding/GPUCommandBuffer.h"
27#include "src/dawn/node/binding/GPUCommandEncoder.h"
28#include "src/dawn/node/binding/GPUComputePipeline.h"
29#include "src/dawn/node/binding/GPUPipelineLayout.h"
30#include "src/dawn/node/binding/GPUQuerySet.h"
31#include "src/dawn/node/binding/GPUQueue.h"
32#include "src/dawn/node/binding/GPURenderBundleEncoder.h"
33#include "src/dawn/node/binding/GPURenderPipeline.h"
34#include "src/dawn/node/binding/GPUSampler.h"
35#include "src/dawn/node/binding/GPUShaderModule.h"
Corentin Wallez6be7f322022-12-07 13:53:04 +000036#include "src/dawn/node/binding/GPUSupportedFeatures.h"
Ben Clayton902ad1f2022-02-04 12:51:25 +000037#include "src/dawn/node/binding/GPUSupportedLimits.h"
38#include "src/dawn/node/binding/GPUTexture.h"
39#include "src/dawn/node/utils/Debug.h"
Ben Claytonbc207f72021-09-29 08:48:43 +000040
Corentin Wallez7f8fa042022-01-06 09:22:17 +000041namespace wgpu::binding {
Ben Claytonbc207f72021-09-29 08:48:43 +000042
dan sinclair41e4d9a2022-05-01 14:40:55 +000043namespace {
Ben Claytonbc207f72021-09-29 08:48:43 +000044
Ben Clayton1604ae52022-07-11 11:45:08 +000045// Returns a string representation of the WGPULoggingType
46const char* str(WGPULoggingType ty) {
47 switch (ty) {
48 case WGPULoggingType_Verbose:
49 return "verbose";
50 case WGPULoggingType_Info:
51 return "info";
52 case WGPULoggingType_Warning:
53 return "warning";
54 case WGPULoggingType_Error:
55 return "error";
56 default:
57 return "unknown";
58 }
59}
60
61// Returns a string representation of the WGPUErrorType
62const char* str(WGPUErrorType ty) {
63 switch (ty) {
64 case WGPUErrorType_NoError:
65 return "no error";
66 case WGPUErrorType_Validation:
67 return "validation";
68 case WGPUErrorType_OutOfMemory:
69 return "out of memory";
70 case WGPUErrorType_Unknown:
71 return "unknown";
72 case WGPUErrorType_DeviceLost:
73 return "device lost";
74 default:
75 return "unknown";
76 }
77}
78
79// There's something broken with Node when attempting to write more than 65536 bytes to cout.
Ben Claytone45bf9f2023-01-10 14:13:50 +000080// Split the string up into writes of 4k chunks.
Ben Clayton1604ae52022-07-11 11:45:08 +000081// Likely related: https://github.com/nodejs/node/issues/12921
82void chunkedWrite(const char* msg) {
83 while (true) {
84 auto n = printf("%.4096s", msg);
Ben Claytone45bf9f2023-01-10 14:13:50 +000085 if (n <= 0) {
Ben Clayton1604ae52022-07-11 11:45:08 +000086 break;
87 }
88 msg += n;
89 }
90}
91
dan sinclair41e4d9a2022-05-01 14:40:55 +000092class DeviceLostInfo : public interop::GPUDeviceLostInfo {
93 public:
94 DeviceLostInfo(interop::GPUDeviceLostReason reason, std::string message)
95 : reason_(reason), message_(message) {}
96 std::variant<interop::GPUDeviceLostReason, interop::UndefinedType> getReason(
97 Napi::Env env) override {
98 return reason_;
99 }
100 std::string getMessage(Napi::Env) override { return message_; }
101
102 private:
103 interop::GPUDeviceLostReason reason_;
104 std::string message_;
105};
106
Ben Claytonb8531642022-06-07 23:45:21 +0000107class OOMError : public interop::GPUOutOfMemoryError {
108 public:
109 explicit OOMError(std::string message) : message_(std::move(message)) {}
110
111 std::string getMessage(Napi::Env) override { return message_; };
112
113 private:
114 std::string message_;
115};
116
dan sinclair41e4d9a2022-05-01 14:40:55 +0000117class ValidationError : public interop::GPUValidationError {
118 public:
119 explicit ValidationError(std::string message) : message_(std::move(message)) {}
120
121 std::string getMessage(Napi::Env) override { return message_; };
122
123 private:
124 std::string message_;
125};
126
127} // namespace
128
129////////////////////////////////////////////////////////////////////////////////
130// wgpu::bindings::GPUDevice
131////////////////////////////////////////////////////////////////////////////////
132GPUDevice::GPUDevice(Napi::Env env, wgpu::Device device)
133 : env_(env),
134 device_(device),
135 async_(std::make_shared<AsyncRunner>(env, device)),
136 lost_promise_(env, PROMISE_INFO) {
137 device_.SetLoggingCallback(
138 [](WGPULoggingType type, char const* message, void* userdata) {
Ben Clayton1604ae52022-07-11 11:45:08 +0000139 printf("%s:\n", str(type));
140 chunkedWrite(message);
dan sinclair41e4d9a2022-05-01 14:40:55 +0000141 },
142 nullptr);
143 device_.SetUncapturedErrorCallback(
144 [](WGPUErrorType type, char const* message, void* userdata) {
Ben Clayton1604ae52022-07-11 11:45:08 +0000145 printf("%s:\n", str(type));
146 chunkedWrite(message);
dan sinclair41e4d9a2022-05-01 14:40:55 +0000147 },
148 nullptr);
149
150 device_.SetDeviceLostCallback(
151 [](WGPUDeviceLostReason reason, char const* message, void* userdata) {
152 auto r = interop::GPUDeviceLostReason::kDestroyed;
153 switch (reason) {
154 case WGPUDeviceLostReason_Force32:
155 UNREACHABLE("WGPUDeviceLostReason_Force32");
156 break;
157 case WGPUDeviceLostReason_Destroyed:
158 case WGPUDeviceLostReason_Undefined:
159 r = interop::GPUDeviceLostReason::kDestroyed;
160 break;
Ben Claytonbc207f72021-09-29 08:48:43 +0000161 }
dan sinclair41e4d9a2022-05-01 14:40:55 +0000162 auto* self = static_cast<GPUDevice*>(userdata);
163 if (self->lost_promise_.GetState() == interop::PromiseState::Pending) {
164 self->lost_promise_.Resolve(
165 interop::GPUDeviceLostInfo::Create<DeviceLostInfo>(self->env_, r, message));
Ben Claytonbc207f72021-09-29 08:48:43 +0000166 }
dan sinclair41e4d9a2022-05-01 14:40:55 +0000167 },
168 this);
169}
Ben Claytonbc207f72021-09-29 08:48:43 +0000170
Ben Clayton94c64952022-07-11 13:33:48 +0000171GPUDevice::~GPUDevice() {
172 // A bit of a fudge to work around the fact that the CTS doesn't destroy GPU devices.
173 // Without this, we'll get a 'Promise not resolved or rejected' fatal message as the
174 // lost_promise_ is left hanging. We'll also not clean up any GPU objects before terminating the
175 // process, which is not a good idea.
Ben Clayton316fb472022-07-28 14:11:17 +0000176 if (!destroyed_) {
Ben Claytone7043362023-01-11 21:03:45 +0000177 lost_promise_.Discard();
178 device_.Destroy();
179 destroyed_ = true;
Ben Clayton94c64952022-07-11 13:33:48 +0000180 }
181}
Ben Claytonbc207f72021-09-29 08:48:43 +0000182
dan sinclair41e4d9a2022-05-01 14:40:55 +0000183interop::Interface<interop::GPUSupportedFeatures> GPUDevice::getFeatures(Napi::Env env) {
Corentin Wallez6be7f322022-12-07 13:53:04 +0000184 size_t count = device_.EnumerateFeatures(nullptr);
185 std::vector<wgpu::FeatureName> features(count);
Ben Clayton58d1e892023-01-11 20:05:37 +0000186 if (count > 0) {
187 device_.EnumerateFeatures(features.data());
188 }
Corentin Wallez6be7f322022-12-07 13:53:04 +0000189 return interop::GPUSupportedFeatures::Create<GPUSupportedFeatures>(env, env,
190 std::move(features));
dan sinclair41e4d9a2022-05-01 14:40:55 +0000191}
Ben Claytonbc207f72021-09-29 08:48:43 +0000192
dan sinclair41e4d9a2022-05-01 14:40:55 +0000193interop::Interface<interop::GPUSupportedLimits> GPUDevice::getLimits(Napi::Env env) {
194 wgpu::SupportedLimits limits{};
195 if (!device_.GetLimits(&limits)) {
196 Napi::Error::New(env, "failed to get device limits").ThrowAsJavaScriptException();
197 }
198 return interop::GPUSupportedLimits::Create<GPUSupportedLimits>(env, limits);
199}
Ben Claytonbc207f72021-09-29 08:48:43 +0000200
dan sinclair41e4d9a2022-05-01 14:40:55 +0000201interop::Interface<interop::GPUQueue> GPUDevice::getQueue(Napi::Env env) {
202 return interop::GPUQueue::Create<GPUQueue>(env, device_.GetQueue(), async_);
203}
Ben Claytonbc207f72021-09-29 08:48:43 +0000204
dan sinclair41e4d9a2022-05-01 14:40:55 +0000205void GPUDevice::destroy(Napi::Env env) {
206 if (lost_promise_.GetState() == interop::PromiseState::Pending) {
207 lost_promise_.Resolve(interop::GPUDeviceLostInfo::Create<DeviceLostInfo>(
208 env_, interop::GPUDeviceLostReason::kDestroyed, "device was destroyed"));
209 }
210 device_.Destroy();
Ben Clayton316fb472022-07-28 14:11:17 +0000211 destroyed_ = true;
dan sinclair41e4d9a2022-05-01 14:40:55 +0000212}
Ben Claytonbc207f72021-09-29 08:48:43 +0000213
dan sinclair41e4d9a2022-05-01 14:40:55 +0000214interop::Interface<interop::GPUBuffer> GPUDevice::createBuffer(
215 Napi::Env env,
216 interop::GPUBufferDescriptor descriptor) {
217 Converter conv(env);
Ben Claytonbc207f72021-09-29 08:48:43 +0000218
dan sinclair41e4d9a2022-05-01 14:40:55 +0000219 wgpu::BufferDescriptor desc{};
220 if (!conv(desc.label, descriptor.label) ||
221 !conv(desc.mappedAtCreation, descriptor.mappedAtCreation) ||
222 !conv(desc.size, descriptor.size) || !conv(desc.usage, descriptor.usage)) {
223 return {};
224 }
225 return interop::GPUBuffer::Create<GPUBuffer>(env, device_.CreateBuffer(&desc), desc, device_,
226 async_);
227}
228
229interop::Interface<interop::GPUTexture> GPUDevice::createTexture(
230 Napi::Env env,
231 interop::GPUTextureDescriptor descriptor) {
Corentin Walleze2cdafb2022-12-05 11:50:49 +0000232 Converter conv(env, device_);
dan sinclair41e4d9a2022-05-01 14:40:55 +0000233
234 wgpu::TextureDescriptor desc{};
235 if (!conv(desc.label, descriptor.label) || !conv(desc.usage, descriptor.usage) || //
236 !conv(desc.size, descriptor.size) || //
237 !conv(desc.dimension, descriptor.dimension) || //
238 !conv(desc.mipLevelCount, descriptor.mipLevelCount) || //
239 !conv(desc.sampleCount, descriptor.sampleCount) || //
Corentin Wallez914a2df2022-05-12 15:13:26 +0000240 !conv(desc.format, descriptor.format) || //
241 !conv(desc.viewFormats, desc.viewFormatCount, descriptor.viewFormats)) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000242 return {};
243 }
Corentin Walleze2cdafb2022-12-05 11:50:49 +0000244 return interop::GPUTexture::Create<GPUTexture>(env, device_, device_.CreateTexture(&desc));
dan sinclair41e4d9a2022-05-01 14:40:55 +0000245}
246
247interop::Interface<interop::GPUSampler> GPUDevice::createSampler(
248 Napi::Env env,
249 interop::GPUSamplerDescriptor descriptor) {
250 Converter conv(env);
251
252 wgpu::SamplerDescriptor desc{};
253 if (!conv(desc.label, descriptor.label) || //
254 !conv(desc.addressModeU, descriptor.addressModeU) || //
255 !conv(desc.addressModeV, descriptor.addressModeV) || //
256 !conv(desc.addressModeW, descriptor.addressModeW) || //
257 !conv(desc.magFilter, descriptor.magFilter) || //
258 !conv(desc.minFilter, descriptor.minFilter) || //
259 !conv(desc.mipmapFilter, descriptor.mipmapFilter) || //
260 !conv(desc.lodMinClamp, descriptor.lodMinClamp) || //
261 !conv(desc.lodMaxClamp, descriptor.lodMaxClamp) || //
262 !conv(desc.compare, descriptor.compare) || //
263 !conv(desc.maxAnisotropy, descriptor.maxAnisotropy)) {
264 return {};
265 }
266 return interop::GPUSampler::Create<GPUSampler>(env, device_.CreateSampler(&desc));
267}
268
269interop::Interface<interop::GPUExternalTexture> GPUDevice::importExternalTexture(
270 Napi::Env,
271 interop::GPUExternalTextureDescriptor descriptor) {
272 UNIMPLEMENTED();
273}
274
275interop::Interface<interop::GPUBindGroupLayout> GPUDevice::createBindGroupLayout(
276 Napi::Env env,
277 interop::GPUBindGroupLayoutDescriptor descriptor) {
Corentin Walleze2cdafb2022-12-05 11:50:49 +0000278 Converter conv(env, device_);
dan sinclair41e4d9a2022-05-01 14:40:55 +0000279
280 wgpu::BindGroupLayoutDescriptor desc{};
281 if (!conv(desc.label, descriptor.label) ||
282 !conv(desc.entries, desc.entryCount, descriptor.entries)) {
283 return {};
Ben Claytonbc207f72021-09-29 08:48:43 +0000284 }
285
dan sinclair41e4d9a2022-05-01 14:40:55 +0000286 return interop::GPUBindGroupLayout::Create<GPUBindGroupLayout>(
287 env, device_.CreateBindGroupLayout(&desc));
288}
289
290interop::Interface<interop::GPUPipelineLayout> GPUDevice::createPipelineLayout(
291 Napi::Env env,
292 interop::GPUPipelineLayoutDescriptor descriptor) {
293 Converter conv(env);
294
295 wgpu::PipelineLayoutDescriptor desc{};
296 if (!conv(desc.label, descriptor.label) ||
297 !conv(desc.bindGroupLayouts, desc.bindGroupLayoutCount, descriptor.bindGroupLayouts)) {
298 return {};
Ben Claytonbc207f72021-09-29 08:48:43 +0000299 }
300
dan sinclair41e4d9a2022-05-01 14:40:55 +0000301 return interop::GPUPipelineLayout::Create<GPUPipelineLayout>(
302 env, device_.CreatePipelineLayout(&desc));
303}
304
305interop::Interface<interop::GPUBindGroup> GPUDevice::createBindGroup(
306 Napi::Env env,
307 interop::GPUBindGroupDescriptor descriptor) {
308 Converter conv(env);
309
310 wgpu::BindGroupDescriptor desc{};
311 if (!conv(desc.label, descriptor.label) || !conv(desc.layout, descriptor.layout) ||
312 !conv(desc.entries, desc.entryCount, descriptor.entries)) {
313 return {};
Ben Claytonbc207f72021-09-29 08:48:43 +0000314 }
315
dan sinclair41e4d9a2022-05-01 14:40:55 +0000316 return interop::GPUBindGroup::Create<GPUBindGroup>(env, device_.CreateBindGroup(&desc));
317}
318
319interop::Interface<interop::GPUShaderModule> GPUDevice::createShaderModule(
320 Napi::Env env,
321 interop::GPUShaderModuleDescriptor descriptor) {
322 Converter conv(env);
323
324 wgpu::ShaderModuleWGSLDescriptor wgsl_desc{};
325 wgpu::ShaderModuleDescriptor sm_desc{};
326 if (!conv(wgsl_desc.source, descriptor.code) || !conv(sm_desc.label, descriptor.label)) {
327 return {};
328 }
329 sm_desc.nextInChain = &wgsl_desc;
330
331 return interop::GPUShaderModule::Create<GPUShaderModule>(
332 env, device_.CreateShaderModule(&sm_desc), async_);
333}
334
335interop::Interface<interop::GPUComputePipeline> GPUDevice::createComputePipeline(
336 Napi::Env env,
337 interop::GPUComputePipelineDescriptor descriptor) {
338 Converter conv(env);
339
340 wgpu::ComputePipelineDescriptor desc{};
341 if (!conv(desc, descriptor)) {
342 return {};
Ben Claytonbc207f72021-09-29 08:48:43 +0000343 }
344
dan sinclair41e4d9a2022-05-01 14:40:55 +0000345 return interop::GPUComputePipeline::Create<GPUComputePipeline>(
346 env, device_.CreateComputePipeline(&desc));
347}
348
349interop::Interface<interop::GPURenderPipeline> GPUDevice::createRenderPipeline(
350 Napi::Env env,
351 interop::GPURenderPipelineDescriptor descriptor) {
Corentin Walleze2cdafb2022-12-05 11:50:49 +0000352 Converter conv(env, device_);
dan sinclair41e4d9a2022-05-01 14:40:55 +0000353
354 wgpu::RenderPipelineDescriptor desc{};
355 if (!conv(desc, descriptor)) {
356 return {};
Ben Claytonbc207f72021-09-29 08:48:43 +0000357 }
358
dan sinclair41e4d9a2022-05-01 14:40:55 +0000359 return interop::GPURenderPipeline::Create<GPURenderPipeline>(
360 env, device_.CreateRenderPipeline(&desc));
361}
Ben Claytonbc207f72021-09-29 08:48:43 +0000362
dan sinclair41e4d9a2022-05-01 14:40:55 +0000363interop::Promise<interop::Interface<interop::GPUComputePipeline>>
364GPUDevice::createComputePipelineAsync(Napi::Env env,
365 interop::GPUComputePipelineDescriptor descriptor) {
366 using Promise = interop::Promise<interop::Interface<interop::GPUComputePipeline>>;
Ben Claytonbc207f72021-09-29 08:48:43 +0000367
dan sinclair41e4d9a2022-05-01 14:40:55 +0000368 Converter conv(env);
Ben Claytonbc207f72021-09-29 08:48:43 +0000369
dan sinclair41e4d9a2022-05-01 14:40:55 +0000370 wgpu::ComputePipelineDescriptor desc{};
371 if (!conv(desc, descriptor)) {
372 Promise promise(env, PROMISE_INFO);
373 promise.Reject(Errors::OperationError(env));
Ben Claytonbc207f72021-09-29 08:48:43 +0000374 return promise;
375 }
376
dan sinclair41e4d9a2022-05-01 14:40:55 +0000377 struct Context {
378 Napi::Env env;
379 Promise promise;
380 AsyncTask task;
381 };
382 auto ctx = new Context{env, Promise(env, PROMISE_INFO), AsyncTask(async_)};
383 auto promise = ctx->promise;
Ben Claytone9cbd482021-10-19 19:18:42 +0000384
dan sinclair41e4d9a2022-05-01 14:40:55 +0000385 device_.CreateComputePipelineAsync(
386 &desc,
387 [](WGPUCreatePipelineAsyncStatus status, WGPUComputePipeline pipeline, char const* message,
388 void* userdata) {
389 auto c = std::unique_ptr<Context>(static_cast<Context*>(userdata));
Ben Claytonbc207f72021-09-29 08:48:43 +0000390
dan sinclair41e4d9a2022-05-01 14:40:55 +0000391 switch (status) {
392 case WGPUCreatePipelineAsyncStatus::WGPUCreatePipelineAsyncStatus_Success:
393 c->promise.Resolve(
394 interop::GPUComputePipeline::Create<GPUComputePipeline>(c->env, pipeline));
395 break;
396 default:
397 c->promise.Reject(Errors::OperationError(c->env));
398 break;
399 }
400 },
401 ctx);
Ben Claytonbc207f72021-09-29 08:48:43 +0000402
dan sinclair41e4d9a2022-05-01 14:40:55 +0000403 return promise;
404}
Ben Claytonbc207f72021-09-29 08:48:43 +0000405
dan sinclair41e4d9a2022-05-01 14:40:55 +0000406interop::Promise<interop::Interface<interop::GPURenderPipeline>>
407GPUDevice::createRenderPipelineAsync(Napi::Env env,
408 interop::GPURenderPipelineDescriptor descriptor) {
409 using Promise = interop::Promise<interop::Interface<interop::GPURenderPipeline>>;
Ben Claytonbc207f72021-09-29 08:48:43 +0000410
Corentin Walleze2cdafb2022-12-05 11:50:49 +0000411 Converter conv(env, device_);
Ben Claytonbc207f72021-09-29 08:48:43 +0000412
dan sinclair41e4d9a2022-05-01 14:40:55 +0000413 wgpu::RenderPipelineDescriptor desc{};
414 if (!conv(desc, descriptor)) {
415 Promise promise(env, PROMISE_INFO);
416 promise.Reject(Errors::OperationError(env));
Ben Claytonbc207f72021-09-29 08:48:43 +0000417 return promise;
418 }
419
dan sinclair41e4d9a2022-05-01 14:40:55 +0000420 struct Context {
421 Napi::Env env;
422 Promise promise;
423 AsyncTask task;
424 };
425 auto ctx = new Context{env, Promise(env, PROMISE_INFO), AsyncTask(async_)};
426 auto promise = ctx->promise;
427
428 device_.CreateRenderPipelineAsync(
429 &desc,
430 [](WGPUCreatePipelineAsyncStatus status, WGPURenderPipeline pipeline, char const* message,
431 void* userdata) {
432 auto c = std::unique_ptr<Context>(static_cast<Context*>(userdata));
433
434 switch (status) {
435 case WGPUCreatePipelineAsyncStatus::WGPUCreatePipelineAsyncStatus_Success:
436 c->promise.Resolve(
437 interop::GPURenderPipeline::Create<GPURenderPipeline>(c->env, pipeline));
438 break;
439 default:
440 c->promise.Reject(Errors::OperationError(c->env));
441 break;
442 }
443 },
444 ctx);
445
446 return promise;
447}
448
449interop::Interface<interop::GPUCommandEncoder> GPUDevice::createCommandEncoder(
450 Napi::Env env,
451 interop::GPUCommandEncoderDescriptor descriptor) {
452 wgpu::CommandEncoderDescriptor desc{};
453 return interop::GPUCommandEncoder::Create<GPUCommandEncoder>(
Corentin Walleze2cdafb2022-12-05 11:50:49 +0000454 env, device_, device_.CreateCommandEncoder(&desc));
dan sinclair41e4d9a2022-05-01 14:40:55 +0000455}
456
457interop::Interface<interop::GPURenderBundleEncoder> GPUDevice::createRenderBundleEncoder(
458 Napi::Env env,
459 interop::GPURenderBundleEncoderDescriptor descriptor) {
Corentin Walleze2cdafb2022-12-05 11:50:49 +0000460 Converter conv(env, device_);
dan sinclair41e4d9a2022-05-01 14:40:55 +0000461
462 wgpu::RenderBundleEncoderDescriptor desc{};
463 if (!conv(desc.label, descriptor.label) ||
464 !conv(desc.colorFormats, desc.colorFormatsCount, descriptor.colorFormats) ||
465 !conv(desc.depthStencilFormat, descriptor.depthStencilFormat) ||
466 !conv(desc.sampleCount, descriptor.sampleCount) ||
467 !conv(desc.depthReadOnly, descriptor.depthReadOnly) ||
468 !conv(desc.stencilReadOnly, descriptor.stencilReadOnly)) {
469 return {};
Ben Claytonbc207f72021-09-29 08:48:43 +0000470 }
471
dan sinclair41e4d9a2022-05-01 14:40:55 +0000472 return interop::GPURenderBundleEncoder::Create<GPURenderBundleEncoder>(
473 env, device_.CreateRenderBundleEncoder(&desc));
474}
Ben Claytonbc207f72021-09-29 08:48:43 +0000475
dan sinclair41e4d9a2022-05-01 14:40:55 +0000476interop::Interface<interop::GPUQuerySet> GPUDevice::createQuerySet(
477 Napi::Env env,
478 interop::GPUQuerySetDescriptor descriptor) {
Corentin Wallezc17b4f92022-12-05 13:54:44 +0000479 Converter conv(env, device_);
Ben Claytonbc207f72021-09-29 08:48:43 +0000480
dan sinclair41e4d9a2022-05-01 14:40:55 +0000481 wgpu::QuerySetDescriptor desc{};
482 if (!conv(desc.label, descriptor.label) || !conv(desc.type, descriptor.type) ||
483 !conv(desc.count, descriptor.count)) {
484 return {};
Ben Claytonbc207f72021-09-29 08:48:43 +0000485 }
486
dan sinclair41e4d9a2022-05-01 14:40:55 +0000487 return interop::GPUQuerySet::Create<GPUQuerySet>(env, device_.CreateQuerySet(&desc));
488}
Ben Claytonbc207f72021-09-29 08:48:43 +0000489
dan sinclair41e4d9a2022-05-01 14:40:55 +0000490interop::Promise<interop::Interface<interop::GPUDeviceLostInfo>> GPUDevice::getLost(Napi::Env env) {
491 return lost_promise_;
492}
Ben Claytonbc207f72021-09-29 08:48:43 +0000493
dan sinclair41e4d9a2022-05-01 14:40:55 +0000494void GPUDevice::pushErrorScope(Napi::Env env, interop::GPUErrorFilter filter) {
495 wgpu::ErrorFilter f;
496 switch (filter) {
497 case interop::GPUErrorFilter::kOutOfMemory:
498 f = wgpu::ErrorFilter::OutOfMemory;
499 break;
500 case interop::GPUErrorFilter::kValidation:
501 f = wgpu::ErrorFilter::Validation;
502 break;
Corentin Wallez06749f92022-12-02 15:36:17 +0000503 case interop::GPUErrorFilter::kInternal:
504 f = wgpu::ErrorFilter::Internal;
505 break;
dan sinclair41e4d9a2022-05-01 14:40:55 +0000506 default:
507 Napi::Error::New(env, "unhandled GPUErrorFilter value").ThrowAsJavaScriptException();
508 return;
Ben Claytonbc207f72021-09-29 08:48:43 +0000509 }
dan sinclair41e4d9a2022-05-01 14:40:55 +0000510 device_.PushErrorScope(f);
511}
Ben Claytonbc207f72021-09-29 08:48:43 +0000512
Ben Claytonb8531642022-06-07 23:45:21 +0000513interop::Promise<std::optional<interop::Interface<interop::GPUError>>> GPUDevice::popErrorScope(
514 Napi::Env env) {
515 using Promise = interop::Promise<std::optional<interop::Interface<interop::GPUError>>>;
dan sinclair41e4d9a2022-05-01 14:40:55 +0000516 struct Context {
517 Napi::Env env;
518 Promise promise;
519 AsyncTask task;
520 };
521 auto* ctx = new Context{env, Promise(env, PROMISE_INFO), AsyncTask(async_)};
522 auto promise = ctx->promise;
Ben Claytonbc207f72021-09-29 08:48:43 +0000523
dan sinclair41e4d9a2022-05-01 14:40:55 +0000524 device_.PopErrorScope(
525 [](WGPUErrorType type, char const* message, void* userdata) {
526 auto c = std::unique_ptr<Context>(static_cast<Context*>(userdata));
527 auto env = c->env;
528 switch (type) {
529 case WGPUErrorType::WGPUErrorType_NoError:
530 c->promise.Resolve({});
531 break;
Ben Claytonb8531642022-06-07 23:45:21 +0000532 case WGPUErrorType::WGPUErrorType_OutOfMemory: {
533 interop::Interface<interop::GPUError> err{
534 interop::GPUOutOfMemoryError::Create<OOMError>(env, message)};
535 c->promise.Resolve(err);
dan sinclair41e4d9a2022-05-01 14:40:55 +0000536 break;
Ben Claytonb8531642022-06-07 23:45:21 +0000537 }
538 case WGPUErrorType::WGPUErrorType_Validation: {
539 interop::Interface<interop::GPUError> err{
540 interop::GPUValidationError::Create<ValidationError>(env, message)};
541 c->promise.Resolve(err);
dan sinclair41e4d9a2022-05-01 14:40:55 +0000542 break;
Ben Claytonb8531642022-06-07 23:45:21 +0000543 }
dan sinclair41e4d9a2022-05-01 14:40:55 +0000544 case WGPUErrorType::WGPUErrorType_Unknown:
545 case WGPUErrorType::WGPUErrorType_DeviceLost:
546 c->promise.Reject(Errors::OperationError(env, message));
547 break;
548 default:
549 c->promise.Reject("unhandled error type");
550 break;
551 }
552 },
553 ctx);
Ben Claytonbc207f72021-09-29 08:48:43 +0000554
dan sinclair41e4d9a2022-05-01 14:40:55 +0000555 return promise;
556}
Ben Claytonbc207f72021-09-29 08:48:43 +0000557
Ben Clayton28299222022-05-03 20:02:53 +0000558std::string GPUDevice::getLabel(Napi::Env) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000559 UNIMPLEMENTED();
560}
Ben Claytonbc207f72021-09-29 08:48:43 +0000561
Ben Clayton28299222022-05-03 20:02:53 +0000562void GPUDevice::setLabel(Napi::Env, std::string value) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000563 UNIMPLEMENTED();
564}
Ben Claytonbc207f72021-09-29 08:48:43 +0000565
dan sinclair41e4d9a2022-05-01 14:40:55 +0000566interop::Interface<interop::EventHandler> GPUDevice::getOnuncapturederror(Napi::Env) {
567 // TODO(dawn:1348): Implement support for the "unhandlederror" event.
568 UNIMPLEMENTED();
569}
Ben Claytonbc207f72021-09-29 08:48:43 +0000570
dan sinclair41e4d9a2022-05-01 14:40:55 +0000571void GPUDevice::setOnuncapturederror(Napi::Env, interop::Interface<interop::EventHandler> value) {
572 // TODO(dawn:1348): Implement support for the "unhandlederror" event.
573 UNIMPLEMENTED();
574}
Ben Claytonbc207f72021-09-29 08:48:43 +0000575
dan sinclair41e4d9a2022-05-01 14:40:55 +0000576void GPUDevice::addEventListener(
577 Napi::Env,
578 std::string type,
579 std::optional<interop::Interface<interop::EventListener>> callback,
580 std::optional<std::variant<interop::AddEventListenerOptions, bool>> options) {
581 // TODO(dawn:1348): Implement support for the "unhandlederror" event.
582 UNIMPLEMENTED();
583}
Ben Claytonbc207f72021-09-29 08:48:43 +0000584
dan sinclair41e4d9a2022-05-01 14:40:55 +0000585void GPUDevice::removeEventListener(
586 Napi::Env,
587 std::string type,
588 std::optional<interop::Interface<interop::EventListener>> callback,
589 std::optional<std::variant<interop::EventListenerOptions, bool>> options) {
590 // TODO(dawn:1348): Implement support for the "unhandlederror" event.
591 UNIMPLEMENTED();
592}
Ben Claytonbc207f72021-09-29 08:48:43 +0000593
dan sinclair41e4d9a2022-05-01 14:40:55 +0000594bool GPUDevice::dispatchEvent(Napi::Env, interop::Interface<interop::Event> event) {
595 // TODO(dawn:1348): Implement support for the "unhandlederror" event.
596 UNIMPLEMENTED();
597}
Ben Claytonbc207f72021-09-29 08:48:43 +0000598
Corentin Wallez7f8fa042022-01-06 09:22:17 +0000599} // namespace wgpu::binding