Ben Clayton | bc207f7 | 2021-09-29 08:48:43 +0000 | [diff] [blame] | 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 | |
Ben Clayton | 902ad1f | 2022-02-04 12:51:25 +0000 | [diff] [blame] | 15 | #include "src/dawn/node/binding/GPUDevice.h" |
Ben Clayton | bc207f7 | 2021-09-29 08:48:43 +0000 | [diff] [blame] | 16 | |
| 17 | #include <memory> |
dan sinclair | 13e9699 | 2022-04-20 00:58:34 +0000 | [diff] [blame] | 18 | #include <utility> |
| 19 | #include <vector> |
Ben Clayton | bc207f7 | 2021-09-29 08:48:43 +0000 | [diff] [blame] | 20 | |
Ben Clayton | 902ad1f | 2022-02-04 12:51:25 +0000 | [diff] [blame] | 21 | #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 Wallez | 6be7f32 | 2022-12-07 13:53:04 +0000 | [diff] [blame] | 36 | #include "src/dawn/node/binding/GPUSupportedFeatures.h" |
Ben Clayton | 902ad1f | 2022-02-04 12:51:25 +0000 | [diff] [blame] | 37 | #include "src/dawn/node/binding/GPUSupportedLimits.h" |
| 38 | #include "src/dawn/node/binding/GPUTexture.h" |
| 39 | #include "src/dawn/node/utils/Debug.h" |
Ben Clayton | bc207f7 | 2021-09-29 08:48:43 +0000 | [diff] [blame] | 40 | |
Corentin Wallez | 7f8fa04 | 2022-01-06 09:22:17 +0000 | [diff] [blame] | 41 | namespace wgpu::binding { |
Ben Clayton | bc207f7 | 2021-09-29 08:48:43 +0000 | [diff] [blame] | 42 | |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 43 | namespace { |
Ben Clayton | bc207f7 | 2021-09-29 08:48:43 +0000 | [diff] [blame] | 44 | |
Ben Clayton | 1604ae5 | 2022-07-11 11:45:08 +0000 | [diff] [blame] | 45 | // Returns a string representation of the WGPULoggingType |
| 46 | const 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 |
| 62 | const 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 Clayton | e45bf9f | 2023-01-10 14:13:50 +0000 | [diff] [blame] | 80 | // Split the string up into writes of 4k chunks. |
Ben Clayton | 1604ae5 | 2022-07-11 11:45:08 +0000 | [diff] [blame] | 81 | // Likely related: https://github.com/nodejs/node/issues/12921 |
| 82 | void chunkedWrite(const char* msg) { |
| 83 | while (true) { |
| 84 | auto n = printf("%.4096s", msg); |
Ben Clayton | e45bf9f | 2023-01-10 14:13:50 +0000 | [diff] [blame] | 85 | if (n <= 0) { |
Ben Clayton | 1604ae5 | 2022-07-11 11:45:08 +0000 | [diff] [blame] | 86 | break; |
| 87 | } |
| 88 | msg += n; |
| 89 | } |
| 90 | } |
| 91 | |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 92 | class 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 Clayton | b853164 | 2022-06-07 23:45:21 +0000 | [diff] [blame] | 107 | class 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 sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 117 | class 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 | //////////////////////////////////////////////////////////////////////////////// |
| 132 | GPUDevice::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 Clayton | 1604ae5 | 2022-07-11 11:45:08 +0000 | [diff] [blame] | 139 | printf("%s:\n", str(type)); |
| 140 | chunkedWrite(message); |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 141 | }, |
| 142 | nullptr); |
| 143 | device_.SetUncapturedErrorCallback( |
| 144 | [](WGPUErrorType type, char const* message, void* userdata) { |
Ben Clayton | 1604ae5 | 2022-07-11 11:45:08 +0000 | [diff] [blame] | 145 | printf("%s:\n", str(type)); |
| 146 | chunkedWrite(message); |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 147 | }, |
| 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 Clayton | bc207f7 | 2021-09-29 08:48:43 +0000 | [diff] [blame] | 161 | } |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 162 | 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 Clayton | bc207f7 | 2021-09-29 08:48:43 +0000 | [diff] [blame] | 166 | } |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 167 | }, |
| 168 | this); |
| 169 | } |
Ben Clayton | bc207f7 | 2021-09-29 08:48:43 +0000 | [diff] [blame] | 170 | |
Ben Clayton | 94c6495 | 2022-07-11 13:33:48 +0000 | [diff] [blame] | 171 | GPUDevice::~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 Clayton | 316fb47 | 2022-07-28 14:11:17 +0000 | [diff] [blame] | 176 | if (!destroyed_) { |
Ben Clayton | e704336 | 2023-01-11 21:03:45 +0000 | [diff] [blame] | 177 | lost_promise_.Discard(); |
| 178 | device_.Destroy(); |
| 179 | destroyed_ = true; |
Ben Clayton | 94c6495 | 2022-07-11 13:33:48 +0000 | [diff] [blame] | 180 | } |
| 181 | } |
Ben Clayton | bc207f7 | 2021-09-29 08:48:43 +0000 | [diff] [blame] | 182 | |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 183 | interop::Interface<interop::GPUSupportedFeatures> GPUDevice::getFeatures(Napi::Env env) { |
Corentin Wallez | 6be7f32 | 2022-12-07 13:53:04 +0000 | [diff] [blame] | 184 | size_t count = device_.EnumerateFeatures(nullptr); |
| 185 | std::vector<wgpu::FeatureName> features(count); |
Ben Clayton | 58d1e89 | 2023-01-11 20:05:37 +0000 | [diff] [blame] | 186 | if (count > 0) { |
| 187 | device_.EnumerateFeatures(features.data()); |
| 188 | } |
Corentin Wallez | 6be7f32 | 2022-12-07 13:53:04 +0000 | [diff] [blame] | 189 | return interop::GPUSupportedFeatures::Create<GPUSupportedFeatures>(env, env, |
| 190 | std::move(features)); |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 191 | } |
Ben Clayton | bc207f7 | 2021-09-29 08:48:43 +0000 | [diff] [blame] | 192 | |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 193 | interop::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 Clayton | bc207f7 | 2021-09-29 08:48:43 +0000 | [diff] [blame] | 200 | |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 201 | interop::Interface<interop::GPUQueue> GPUDevice::getQueue(Napi::Env env) { |
| 202 | return interop::GPUQueue::Create<GPUQueue>(env, device_.GetQueue(), async_); |
| 203 | } |
Ben Clayton | bc207f7 | 2021-09-29 08:48:43 +0000 | [diff] [blame] | 204 | |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 205 | void 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 Clayton | 316fb47 | 2022-07-28 14:11:17 +0000 | [diff] [blame] | 211 | destroyed_ = true; |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 212 | } |
Ben Clayton | bc207f7 | 2021-09-29 08:48:43 +0000 | [diff] [blame] | 213 | |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 214 | interop::Interface<interop::GPUBuffer> GPUDevice::createBuffer( |
| 215 | Napi::Env env, |
| 216 | interop::GPUBufferDescriptor descriptor) { |
| 217 | Converter conv(env); |
Ben Clayton | bc207f7 | 2021-09-29 08:48:43 +0000 | [diff] [blame] | 218 | |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 219 | 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 | |
| 229 | interop::Interface<interop::GPUTexture> GPUDevice::createTexture( |
| 230 | Napi::Env env, |
| 231 | interop::GPUTextureDescriptor descriptor) { |
Corentin Wallez | e2cdafb | 2022-12-05 11:50:49 +0000 | [diff] [blame] | 232 | Converter conv(env, device_); |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 233 | |
| 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 Wallez | 914a2df | 2022-05-12 15:13:26 +0000 | [diff] [blame] | 240 | !conv(desc.format, descriptor.format) || // |
| 241 | !conv(desc.viewFormats, desc.viewFormatCount, descriptor.viewFormats)) { |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 242 | return {}; |
| 243 | } |
Corentin Wallez | e2cdafb | 2022-12-05 11:50:49 +0000 | [diff] [blame] | 244 | return interop::GPUTexture::Create<GPUTexture>(env, device_, device_.CreateTexture(&desc)); |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 245 | } |
| 246 | |
| 247 | interop::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 | |
| 269 | interop::Interface<interop::GPUExternalTexture> GPUDevice::importExternalTexture( |
| 270 | Napi::Env, |
| 271 | interop::GPUExternalTextureDescriptor descriptor) { |
| 272 | UNIMPLEMENTED(); |
| 273 | } |
| 274 | |
| 275 | interop::Interface<interop::GPUBindGroupLayout> GPUDevice::createBindGroupLayout( |
| 276 | Napi::Env env, |
| 277 | interop::GPUBindGroupLayoutDescriptor descriptor) { |
Corentin Wallez | e2cdafb | 2022-12-05 11:50:49 +0000 | [diff] [blame] | 278 | Converter conv(env, device_); |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 279 | |
| 280 | wgpu::BindGroupLayoutDescriptor desc{}; |
| 281 | if (!conv(desc.label, descriptor.label) || |
| 282 | !conv(desc.entries, desc.entryCount, descriptor.entries)) { |
| 283 | return {}; |
Ben Clayton | bc207f7 | 2021-09-29 08:48:43 +0000 | [diff] [blame] | 284 | } |
| 285 | |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 286 | return interop::GPUBindGroupLayout::Create<GPUBindGroupLayout>( |
| 287 | env, device_.CreateBindGroupLayout(&desc)); |
| 288 | } |
| 289 | |
| 290 | interop::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 Clayton | bc207f7 | 2021-09-29 08:48:43 +0000 | [diff] [blame] | 299 | } |
| 300 | |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 301 | return interop::GPUPipelineLayout::Create<GPUPipelineLayout>( |
| 302 | env, device_.CreatePipelineLayout(&desc)); |
| 303 | } |
| 304 | |
| 305 | interop::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 Clayton | bc207f7 | 2021-09-29 08:48:43 +0000 | [diff] [blame] | 314 | } |
| 315 | |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 316 | return interop::GPUBindGroup::Create<GPUBindGroup>(env, device_.CreateBindGroup(&desc)); |
| 317 | } |
| 318 | |
| 319 | interop::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 | |
| 335 | interop::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 Clayton | bc207f7 | 2021-09-29 08:48:43 +0000 | [diff] [blame] | 343 | } |
| 344 | |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 345 | return interop::GPUComputePipeline::Create<GPUComputePipeline>( |
| 346 | env, device_.CreateComputePipeline(&desc)); |
| 347 | } |
| 348 | |
| 349 | interop::Interface<interop::GPURenderPipeline> GPUDevice::createRenderPipeline( |
| 350 | Napi::Env env, |
| 351 | interop::GPURenderPipelineDescriptor descriptor) { |
Corentin Wallez | e2cdafb | 2022-12-05 11:50:49 +0000 | [diff] [blame] | 352 | Converter conv(env, device_); |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 353 | |
| 354 | wgpu::RenderPipelineDescriptor desc{}; |
| 355 | if (!conv(desc, descriptor)) { |
| 356 | return {}; |
Ben Clayton | bc207f7 | 2021-09-29 08:48:43 +0000 | [diff] [blame] | 357 | } |
| 358 | |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 359 | return interop::GPURenderPipeline::Create<GPURenderPipeline>( |
| 360 | env, device_.CreateRenderPipeline(&desc)); |
| 361 | } |
Ben Clayton | bc207f7 | 2021-09-29 08:48:43 +0000 | [diff] [blame] | 362 | |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 363 | interop::Promise<interop::Interface<interop::GPUComputePipeline>> |
| 364 | GPUDevice::createComputePipelineAsync(Napi::Env env, |
| 365 | interop::GPUComputePipelineDescriptor descriptor) { |
| 366 | using Promise = interop::Promise<interop::Interface<interop::GPUComputePipeline>>; |
Ben Clayton | bc207f7 | 2021-09-29 08:48:43 +0000 | [diff] [blame] | 367 | |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 368 | Converter conv(env); |
Ben Clayton | bc207f7 | 2021-09-29 08:48:43 +0000 | [diff] [blame] | 369 | |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 370 | wgpu::ComputePipelineDescriptor desc{}; |
| 371 | if (!conv(desc, descriptor)) { |
| 372 | Promise promise(env, PROMISE_INFO); |
| 373 | promise.Reject(Errors::OperationError(env)); |
Ben Clayton | bc207f7 | 2021-09-29 08:48:43 +0000 | [diff] [blame] | 374 | return promise; |
| 375 | } |
| 376 | |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 377 | 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 Clayton | e9cbd48 | 2021-10-19 19:18:42 +0000 | [diff] [blame] | 384 | |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 385 | 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 Clayton | bc207f7 | 2021-09-29 08:48:43 +0000 | [diff] [blame] | 390 | |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 391 | 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 Clayton | bc207f7 | 2021-09-29 08:48:43 +0000 | [diff] [blame] | 402 | |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 403 | return promise; |
| 404 | } |
Ben Clayton | bc207f7 | 2021-09-29 08:48:43 +0000 | [diff] [blame] | 405 | |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 406 | interop::Promise<interop::Interface<interop::GPURenderPipeline>> |
| 407 | GPUDevice::createRenderPipelineAsync(Napi::Env env, |
| 408 | interop::GPURenderPipelineDescriptor descriptor) { |
| 409 | using Promise = interop::Promise<interop::Interface<interop::GPURenderPipeline>>; |
Ben Clayton | bc207f7 | 2021-09-29 08:48:43 +0000 | [diff] [blame] | 410 | |
Corentin Wallez | e2cdafb | 2022-12-05 11:50:49 +0000 | [diff] [blame] | 411 | Converter conv(env, device_); |
Ben Clayton | bc207f7 | 2021-09-29 08:48:43 +0000 | [diff] [blame] | 412 | |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 413 | wgpu::RenderPipelineDescriptor desc{}; |
| 414 | if (!conv(desc, descriptor)) { |
| 415 | Promise promise(env, PROMISE_INFO); |
| 416 | promise.Reject(Errors::OperationError(env)); |
Ben Clayton | bc207f7 | 2021-09-29 08:48:43 +0000 | [diff] [blame] | 417 | return promise; |
| 418 | } |
| 419 | |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 420 | 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 | |
| 449 | interop::Interface<interop::GPUCommandEncoder> GPUDevice::createCommandEncoder( |
| 450 | Napi::Env env, |
| 451 | interop::GPUCommandEncoderDescriptor descriptor) { |
| 452 | wgpu::CommandEncoderDescriptor desc{}; |
| 453 | return interop::GPUCommandEncoder::Create<GPUCommandEncoder>( |
Corentin Wallez | e2cdafb | 2022-12-05 11:50:49 +0000 | [diff] [blame] | 454 | env, device_, device_.CreateCommandEncoder(&desc)); |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 455 | } |
| 456 | |
| 457 | interop::Interface<interop::GPURenderBundleEncoder> GPUDevice::createRenderBundleEncoder( |
| 458 | Napi::Env env, |
| 459 | interop::GPURenderBundleEncoderDescriptor descriptor) { |
Corentin Wallez | e2cdafb | 2022-12-05 11:50:49 +0000 | [diff] [blame] | 460 | Converter conv(env, device_); |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 461 | |
| 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 Clayton | bc207f7 | 2021-09-29 08:48:43 +0000 | [diff] [blame] | 470 | } |
| 471 | |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 472 | return interop::GPURenderBundleEncoder::Create<GPURenderBundleEncoder>( |
| 473 | env, device_.CreateRenderBundleEncoder(&desc)); |
| 474 | } |
Ben Clayton | bc207f7 | 2021-09-29 08:48:43 +0000 | [diff] [blame] | 475 | |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 476 | interop::Interface<interop::GPUQuerySet> GPUDevice::createQuerySet( |
| 477 | Napi::Env env, |
| 478 | interop::GPUQuerySetDescriptor descriptor) { |
Corentin Wallez | c17b4f9 | 2022-12-05 13:54:44 +0000 | [diff] [blame] | 479 | Converter conv(env, device_); |
Ben Clayton | bc207f7 | 2021-09-29 08:48:43 +0000 | [diff] [blame] | 480 | |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 481 | wgpu::QuerySetDescriptor desc{}; |
| 482 | if (!conv(desc.label, descriptor.label) || !conv(desc.type, descriptor.type) || |
| 483 | !conv(desc.count, descriptor.count)) { |
| 484 | return {}; |
Ben Clayton | bc207f7 | 2021-09-29 08:48:43 +0000 | [diff] [blame] | 485 | } |
| 486 | |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 487 | return interop::GPUQuerySet::Create<GPUQuerySet>(env, device_.CreateQuerySet(&desc)); |
| 488 | } |
Ben Clayton | bc207f7 | 2021-09-29 08:48:43 +0000 | [diff] [blame] | 489 | |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 490 | interop::Promise<interop::Interface<interop::GPUDeviceLostInfo>> GPUDevice::getLost(Napi::Env env) { |
| 491 | return lost_promise_; |
| 492 | } |
Ben Clayton | bc207f7 | 2021-09-29 08:48:43 +0000 | [diff] [blame] | 493 | |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 494 | void 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 Wallez | 06749f9 | 2022-12-02 15:36:17 +0000 | [diff] [blame] | 503 | case interop::GPUErrorFilter::kInternal: |
| 504 | f = wgpu::ErrorFilter::Internal; |
| 505 | break; |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 506 | default: |
| 507 | Napi::Error::New(env, "unhandled GPUErrorFilter value").ThrowAsJavaScriptException(); |
| 508 | return; |
Ben Clayton | bc207f7 | 2021-09-29 08:48:43 +0000 | [diff] [blame] | 509 | } |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 510 | device_.PushErrorScope(f); |
| 511 | } |
Ben Clayton | bc207f7 | 2021-09-29 08:48:43 +0000 | [diff] [blame] | 512 | |
Ben Clayton | b853164 | 2022-06-07 23:45:21 +0000 | [diff] [blame] | 513 | interop::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 sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 516 | 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 Clayton | bc207f7 | 2021-09-29 08:48:43 +0000 | [diff] [blame] | 523 | |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 524 | 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 Clayton | b853164 | 2022-06-07 23:45:21 +0000 | [diff] [blame] | 532 | case WGPUErrorType::WGPUErrorType_OutOfMemory: { |
| 533 | interop::Interface<interop::GPUError> err{ |
| 534 | interop::GPUOutOfMemoryError::Create<OOMError>(env, message)}; |
| 535 | c->promise.Resolve(err); |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 536 | break; |
Ben Clayton | b853164 | 2022-06-07 23:45:21 +0000 | [diff] [blame] | 537 | } |
| 538 | case WGPUErrorType::WGPUErrorType_Validation: { |
| 539 | interop::Interface<interop::GPUError> err{ |
| 540 | interop::GPUValidationError::Create<ValidationError>(env, message)}; |
| 541 | c->promise.Resolve(err); |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 542 | break; |
Ben Clayton | b853164 | 2022-06-07 23:45:21 +0000 | [diff] [blame] | 543 | } |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 544 | 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 Clayton | bc207f7 | 2021-09-29 08:48:43 +0000 | [diff] [blame] | 554 | |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 555 | return promise; |
| 556 | } |
Ben Clayton | bc207f7 | 2021-09-29 08:48:43 +0000 | [diff] [blame] | 557 | |
Ben Clayton | 2829922 | 2022-05-03 20:02:53 +0000 | [diff] [blame] | 558 | std::string GPUDevice::getLabel(Napi::Env) { |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 559 | UNIMPLEMENTED(); |
| 560 | } |
Ben Clayton | bc207f7 | 2021-09-29 08:48:43 +0000 | [diff] [blame] | 561 | |
Ben Clayton | 2829922 | 2022-05-03 20:02:53 +0000 | [diff] [blame] | 562 | void GPUDevice::setLabel(Napi::Env, std::string value) { |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 563 | UNIMPLEMENTED(); |
| 564 | } |
Ben Clayton | bc207f7 | 2021-09-29 08:48:43 +0000 | [diff] [blame] | 565 | |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 566 | interop::Interface<interop::EventHandler> GPUDevice::getOnuncapturederror(Napi::Env) { |
| 567 | // TODO(dawn:1348): Implement support for the "unhandlederror" event. |
| 568 | UNIMPLEMENTED(); |
| 569 | } |
Ben Clayton | bc207f7 | 2021-09-29 08:48:43 +0000 | [diff] [blame] | 570 | |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 571 | void GPUDevice::setOnuncapturederror(Napi::Env, interop::Interface<interop::EventHandler> value) { |
| 572 | // TODO(dawn:1348): Implement support for the "unhandlederror" event. |
| 573 | UNIMPLEMENTED(); |
| 574 | } |
Ben Clayton | bc207f7 | 2021-09-29 08:48:43 +0000 | [diff] [blame] | 575 | |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 576 | void 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 Clayton | bc207f7 | 2021-09-29 08:48:43 +0000 | [diff] [blame] | 584 | |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 585 | void 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 Clayton | bc207f7 | 2021-09-29 08:48:43 +0000 | [diff] [blame] | 593 | |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 594 | bool GPUDevice::dispatchEvent(Napi::Env, interop::Interface<interop::Event> event) { |
| 595 | // TODO(dawn:1348): Implement support for the "unhandlederror" event. |
| 596 | UNIMPLEMENTED(); |
| 597 | } |
Ben Clayton | bc207f7 | 2021-09-29 08:48:43 +0000 | [diff] [blame] | 598 | |
Corentin Wallez | 7f8fa04 | 2022-01-06 09:22:17 +0000 | [diff] [blame] | 599 | } // namespace wgpu::binding |