From b42ed0c58b31a6ba04e6dd9121129df7a701519f Mon Sep 17 00:00:00 2001 From: Aaron O'Mullan Date: Mon, 17 Jan 2022 21:54:10 +0100 Subject: [PATCH 01/16] experiment: wgpu sync --- Cargo.lock | 87 ++- ext/webgpu/01_webgpu.js | 102 ++- ext/webgpu/02_idl_types.js | 71 +- ext/webgpu/Cargo.toml | 15 +- ext/webgpu/LICENSE.md | 20 + ext/webgpu/binding.rs | 367 ---------- ext/webgpu/buffer.rs | 229 ------ ext/webgpu/bundle.rs | 461 ------------ ext/webgpu/command_encoder.rs | 656 ----------------- ext/webgpu/compute_pass.rs | 354 --------- ext/webgpu/error.rs | 285 -------- ext/webgpu/lib.deno_webgpu.d.ts | 1132 ----------------------------- ext/webgpu/lib.rs | 986 ------------------------- ext/webgpu/pipeline.rs | 791 -------------------- ext/webgpu/queue.rs | 142 ---- ext/webgpu/render_pass.rs | 665 ----------------- ext/webgpu/sampler.rs | 132 ---- ext/webgpu/shader.rs | 51 -- ext/webgpu/src/binding.rs | 327 +++++++++ ext/webgpu/src/buffer.rs | 223 ++++++ ext/webgpu/src/bundle.rs | 443 +++++++++++ ext/webgpu/src/command_encoder.rs | 622 ++++++++++++++++ ext/webgpu/src/compute_pass.rs | 349 +++++++++ ext/webgpu/src/error.rs | 289 ++++++++ ext/webgpu/src/lib.rs | 888 ++++++++++++++++++++++ ext/webgpu/src/pipeline.rs | 418 +++++++++++ ext/webgpu/src/queue.rs | 137 ++++ ext/webgpu/src/render_pass.rs | 643 ++++++++++++++++ ext/webgpu/src/sampler.rs | 68 ++ ext/webgpu/src/shader.rs | 51 ++ ext/webgpu/src/texture.rs | 108 +++ ext/webgpu/texture.rs | 419 ----------- ext/webgpu/webgpu.idl | 187 +++-- tools/wgpu_sync.js | 59 ++ 34 files changed, 4937 insertions(+), 6840 deletions(-) create mode 100644 ext/webgpu/LICENSE.md delete mode 100644 ext/webgpu/binding.rs delete mode 100644 ext/webgpu/buffer.rs delete mode 100644 ext/webgpu/bundle.rs delete mode 100644 ext/webgpu/command_encoder.rs delete mode 100644 ext/webgpu/compute_pass.rs delete mode 100644 ext/webgpu/error.rs delete mode 100644 ext/webgpu/lib.deno_webgpu.d.ts delete mode 100644 ext/webgpu/lib.rs delete mode 100644 ext/webgpu/pipeline.rs delete mode 100644 ext/webgpu/queue.rs delete mode 100644 ext/webgpu/render_pass.rs delete mode 100644 ext/webgpu/sampler.rs delete mode 100644 ext/webgpu/shader.rs create mode 100644 ext/webgpu/src/binding.rs create mode 100644 ext/webgpu/src/buffer.rs create mode 100644 ext/webgpu/src/bundle.rs create mode 100644 ext/webgpu/src/command_encoder.rs create mode 100644 ext/webgpu/src/compute_pass.rs create mode 100644 ext/webgpu/src/error.rs create mode 100644 ext/webgpu/src/lib.rs create mode 100644 ext/webgpu/src/pipeline.rs create mode 100644 ext/webgpu/src/queue.rs create mode 100644 ext/webgpu/src/render_pass.rs create mode 100644 ext/webgpu/src/sampler.rs create mode 100644 ext/webgpu/src/shader.rs create mode 100644 ext/webgpu/src/texture.rs delete mode 100644 ext/webgpu/texture.rs create mode 100755 tools/wgpu_sync.js diff --git a/Cargo.lock b/Cargo.lock index 02537e57531e26..117d6c40a53c96 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -136,9 +136,9 @@ dependencies = [ [[package]] name = "ash" -version = "0.33.3+1.2.191" +version = "0.34.0+1.2.203" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc4f1d82f164f838ae413296d1131aa6fa79b917d25bebaa7033d25620c09219" +checksum = "b0f780da53d0063880d45554306489f09dd8d1bda47688b4a57bc579119356df" dependencies = [ "libloading", ] @@ -283,6 +283,16 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +[[package]] +name = "bitflags_serde_shim" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25c3d626f0280ec39b33a6fc5c6c1067432b4c41e94aee40ded197a6649bf025" +dependencies = [ + "bitflags", + "serde", +] + [[package]] name = "block" version = "0.1.6" @@ -1427,12 +1437,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d" -[[package]] -name = "fixedbitset" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "279fb028e20b3c4c320317955b77c5e0c9701f05a1d309905d6fc702cdc5053e" - [[package]] name = "flaky_test" version = "0.1.0" @@ -1796,6 +1800,12 @@ dependencies = [ "libc", ] +[[package]] +name = "hexf-parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df" + [[package]] name = "hmac" version = "0.11.0" @@ -2357,17 +2367,18 @@ dependencies = [ [[package]] name = "naga" -version = "0.6.3" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c5859e55c51da10b98e7a73068e0a0c5da7bbcae4fc38f86043d0c6d1b917cf" +checksum = "a4419062f8aa39fb25938169486341945758679e260ddbc1f94bfd1f33924dc2" dependencies = [ "bit-set", "bitflags", "codespan-reporting", - "fxhash", + "hexf-parse", + "indexmap", "log", "num-traits", - "petgraph 0.6.0", + "rustc-hash", "serde", "spirv", "thiserror", @@ -2659,17 +2670,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "467d164a6de56270bd7c4d070df81d07beace25012d5103ced4e9ff08d6afdb7" dependencies = [ - "fixedbitset 0.2.0", - "indexmap", -] - -[[package]] -name = "petgraph" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a13a2fa9d0b63e5f22328828741e523766fff0ee9e779316902290dff3f824f" -dependencies = [ - "fixedbitset 0.4.1", + "fixedbitset", "indexmap", ] @@ -3037,16 +3038,6 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "63e935c45e09cc6dcf00d2f0b2d630a58f4095320223d47fc68918722f0538b6" -[[package]] -name = "raw-window-handle" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e28f55143d0548dad60bb4fbdc835a3d7ac6acc3324506450c5fdd6e42903a76" -dependencies = [ - "libc", - "raw-window-handle 0.4.2", -] - [[package]] name = "raw-window-handle" version = "0.4.2" @@ -3182,9 +3173,9 @@ dependencies = [ [[package]] name = "ron" -version = "0.6.6" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86018df177b1beef6c7c8ef949969c4f7cb9a9344181b92486b23c79995bdaa4" +checksum = "1b861ecaade43ac97886a512b360d01d66be9f41f3c61088b42cedf92e03d678" dependencies = [ "base64 0.13.0", "bitflags", @@ -3729,7 +3720,7 @@ dependencies = [ "is-macro", "once_cell", "parking_lot", - "petgraph 0.5.1", + "petgraph", "radix_fmt", "relative-path", "retain_mut", @@ -4080,7 +4071,7 @@ checksum = "1d53bbcbb4b055c547f283af1f84211f425b95ac59e02d8b70c94b8a63a4704f" dependencies = [ "ahash", "indexmap", - "petgraph 0.5.1", + "petgraph", "swc_common", ] @@ -4092,7 +4083,7 @@ checksum = "83b42a8b13068dd90dec954ec44576d5922914687bc34277f3b0f8d0bbeb4e83" dependencies = [ "ahash", "auto_impl", - "petgraph 0.5.1", + "petgraph", "swc_fast_graph", "tracing", ] @@ -4902,13 +4893,14 @@ dependencies = [ [[package]] name = "wgpu-core" -version = "0.10.4" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f963c62473a36e3cef6c58181f2ed6d0d38d2043d970dbed46cb197190090c99" +checksum = "c4688c000eb841ca55f7b35db659b78d6e1cd77d7caf8fb929f4e181f754047d" dependencies = [ "arrayvec 0.7.2", "bitflags", "cfg_aliases", + "codespan-reporting", "copyless", "fxhash", "log", @@ -4925,9 +4917,9 @@ dependencies = [ [[package]] name = "wgpu-hal" -version = "0.10.7" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27cd894b17bff1958ee93da1cc991fd64bf99667746d4bd2a7403855f4d37fe2" +checksum = "92e33cb9c380dd1166f316dfc511ad9646f72cf2deb47e90bd714db3617a6998" dependencies = [ "arrayvec 0.7.2", "ash", @@ -4942,6 +4934,7 @@ dependencies = [ "gpu-alloc", "gpu-descriptor", "inplace_it", + "js-sys", "khronos-egl", "libloading", "log", @@ -4949,21 +4942,25 @@ dependencies = [ "naga", "objc", "parking_lot", + "profiling", "range-alloc", - "raw-window-handle 0.3.4", + "raw-window-handle", "renderdoc-sys", "thiserror", + "wasm-bindgen", + "web-sys", "wgpu-types", "winapi 0.3.9", ] [[package]] name = "wgpu-types" -version = "0.10.0" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25feb2fbf24ab3219a9f10890ceb8e1ef02b13314ed89d64a9ae99dcad883e18" +checksum = "549533d9e1cdd4b4cda7718d33ff500fc4c34b5467b71d76b547ae0324f3b2a2" dependencies = [ "bitflags", + "bitflags_serde_shim", "serde", ] diff --git a/ext/webgpu/01_webgpu.js b/ext/webgpu/01_webgpu.js index f1d3eb120a3735..ec1c5a81393eed 100644 --- a/ext/webgpu/01_webgpu.js +++ b/ext/webgpu/01_webgpu.js @@ -1,4 +1,4 @@ -// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. // @ts-check /// @@ -219,10 +219,10 @@ */ /** - * @param {string} name - * @param {InnerGPUAdapter} inner - * @returns {GPUAdapter} - */ + * @param {string} name + * @param {InnerGPUAdapter} inner + * @returns {GPUAdapter} + */ function createGPUAdapter(name, inner) { /** @type {GPUAdapter} */ const adapter = webidl.createBranded(GPUAdapter); @@ -544,6 +544,7 @@ const _message = Symbol("[[message]]"); /** + * * @param {string | undefined} reason * @param {string} message * @returns {GPUDeviceLostInfo} @@ -849,7 +850,7 @@ descriptor.usage, options, ); - device.trackResource(buffer); + device.trackResource((buffer)); return buffer; } @@ -878,7 +879,7 @@ device, rid, ); - device.trackResource(texture); + device.trackResource((texture)); return texture; } @@ -905,7 +906,7 @@ device, rid, ); - device.trackResource(sampler); + device.trackResource((sampler)); return sampler; } @@ -948,7 +949,7 @@ device, rid, ); - device.trackResource(bindGroupLayout); + device.trackResource((bindGroupLayout)); return bindGroupLayout; } @@ -990,7 +991,7 @@ device, rid, ); - device.trackResource(pipelineLayout); + device.trackResource((pipelineLayout)); return pipelineLayout; } @@ -1083,7 +1084,7 @@ device, rid, ); - device.trackResource(bindGroup); + device.trackResource((bindGroup)); return bindGroup; } @@ -1115,7 +1116,7 @@ device, rid, ); - device.trackResource(shaderModule); + device.trackResource((shaderModule)); return shaderModule; } @@ -1172,7 +1173,7 @@ device, rid, ); - device.trackResource(computePipeline); + device.trackResource((computePipeline)); return computePipeline; } @@ -1247,7 +1248,7 @@ device, rid, ); - device.trackResource(renderPipeline); + device.trackResource((renderPipeline)); return renderPipeline; } @@ -1284,7 +1285,7 @@ device, rid, ); - device.trackResource(commandEncoder); + device.trackResource((commandEncoder)); return commandEncoder; } @@ -1319,7 +1320,7 @@ device, rid, ); - device.trackResource(renderBundleEncoder); + device.trackResource((renderBundleEncoder)); return renderBundleEncoder; } @@ -1351,7 +1352,7 @@ rid, descriptor, ); - device.trackResource(querySet); + device.trackResource((querySet)); return querySet; } @@ -2268,8 +2269,8 @@ /** * @param {string | null} label - * @param {InnerGPUDevice} device - * @param {number} rid + * @param {InnerGPUDevice} device + * @param {number} rid * @returns {GPUBindGroup} */ function createGPUBindGroup(label, device, rid) { @@ -2311,8 +2312,8 @@ /** * @param {string | null} label - * @param {InnerGPUDevice} device - * @param {number} rid + * @param {InnerGPUDevice} device + * @param {number} rid * @returns {GPUShaderModule} */ function createGPUShaderModule(label, device, rid) { @@ -2436,7 +2437,7 @@ device, rid, ); - device.trackResource(bindGroupLayout); + device.trackResource((bindGroupLayout)); return bindGroupLayout; } @@ -2511,7 +2512,7 @@ device, rid, ); - device.trackResource(bindGroupLayout); + device.trackResource((bindGroupLayout)); return bindGroupLayout; } @@ -3060,6 +3061,49 @@ device.pushError(err); } + /** + * @param {GPUBuffer} destination + * @param {GPUSize64} destinationOffset + * @param {GPUSize64} size + */ + clearBuffer(destination, destinationOffset, size) { + webidl.assertBranded(this, GPUCommandEncoder); + const prefix = + "Failed to execute 'clearBuffer' on 'GPUCommandEncoder'"; + webidl.requiredArguments(arguments.length, 3, { prefix }); + destination = webidl.converters.GPUBuffer(destination, { + prefix, + context: "Argument 1", + }); + destinationOffset = webidl.converters.GPUSize64(destinationOffset, { + prefix, + context: "Argument 2", + }); + size = webidl.converters.GPUSize64(size, { + prefix, + context: "Argument 3", + }); + const device = assertDevice(this, { prefix, context: "this" }); + const commandEncoderRid = assertResource(this, { + prefix, + context: "this", + }); + const destinationRid = assertResource(destination, { + prefix, + context: "Argument 1", + }); + const { err } = core.opSync( + "op_webgpu_command_encoder_clear_buffer", + { + commandEncoderRid, + destinationRid, + destinationOffset, + size, + }, + ); + device.pushError(err); + } + /** * @param {string} groupLabel */ @@ -3203,7 +3247,7 @@ prefix, context: "Argument 3", }); - destination = webidl.converters.GPUQuerySet(destination, { + destination = webidl.converters.GPUBuffer(destination, { prefix, context: "Argument 4", }); @@ -3277,7 +3321,7 @@ device, rid, ); - device.trackResource(commandBuffer); + device.trackResource((commandBuffer)); return commandBuffer; } @@ -3376,6 +3420,7 @@ } /** + * * @param {number} x * @param {number} y * @param {number} width @@ -4527,15 +4572,10 @@ webidl.illegalConstructor(); } - get executionTime() { - throw new Error("Not yet implemented"); - } - [SymbolFor("Deno.privateCustomInspect")](inspect) { return `${this.constructor.name} ${ inspect({ label: this.label, - // TODO(crowlKats): executionTime }) }`; } @@ -4606,7 +4646,7 @@ device, rid, ); - device.trackResource(renderBundle); + device.trackResource((renderBundle)); return renderBundle; } diff --git a/ext/webgpu/02_idl_types.js b/ext/webgpu/02_idl_types.js index 3c49c18884bb4b..0dcf849032b637 100644 --- a/ext/webgpu/02_idl_types.js +++ b/ext/webgpu/02_idl_types.js @@ -1,4 +1,4 @@ -// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. // @ts-check /// @@ -111,28 +111,35 @@ webidl.converters["GPUFeatureName"] = webidl.createEnumConverter( "GPUFeatureName", [ - "depth-clamping", + "depth-clip-control", "depth24unorm-stencil8", "depth32float-stencil8", "pipeline-statistics-query", "texture-compression-bc", + "texture-compression-etc2", + "texture-compression-astc", "timestamp-query", + "indirect-first-instance", // extended from spec "mappable-primary-buffers", - "sampled-texture-binding-array", - "sampled-texture-array-dynamic-indexing", - "sampled-texture-array-non-uniform-indexing", + "texture-binding-array", + "buffer-binding-array", + "storage-resource-binding-array", + "sampled-texture-and-storage-buffer-array-non-uniform-indexing", + "uniform-buffer-and-storage-buffer-texture-non-uniform-indexing", "unsized-binding-array", "multi-draw-indirect", "multi-draw-indirect-count", "push-constants", "address-mode-clamp-to-border", - "non-fill-polygon-mode", - "texture-compression-etc2", - "texture-compression-astc-ldr", "texture-adapter-specific-format-features", "shader-float64", "vertex-attribute-64bit", + "conservative-rasterization", + "vertex-writable-storage", + "clear-commands", + "spirv-shader-passthrough", + "shader-primitive-index", ], ); @@ -348,6 +355,44 @@ "bc6h-rgb-float", "bc7-rgba-unorm", "bc7-rgba-unorm-srgb", + "etc2-rgb8unorm", + "etc2-rgb8unorm-srgb", + "etc2-rgb8a1unorm", + "etc2-rgb8a1unorm-srgb", + "etc2-rgba8unorm", + "etc2-rgba8unorm-srgb", + "eac-r11unorm", + "eac-r11snorm", + "eac-rg11unorm", + "eac-rg11snorm", + "astc-4x4-unorm", + "astc-4x4-unorm-srgb", + "astc-5x4-unorm", + "astc-5x4-unorm-srgb", + "astc-5x5-unorm", + "astc-5x5-unorm-srgb", + "astc-6x5-unorm", + "astc-6x5-unorm-srgb", + "astc-6x6-unorm", + "astc-6x6-unorm-srgb", + "astc-8x5-unorm", + "astc-8x5-unorm-srgb", + "astc-8x6-unorm", + "astc-8x6-unorm-srgb", + "astc-8x8-unorm", + "astc-8x8-unorm-srgb", + "astc-10x5-unorm", + "astc-10x5-unorm-srgb", + "astc-10x6-unorm", + "astc-10x6-unorm-srgb", + "astc-10x8-unorm", + "astc-10x8-unorm-srgb", + "astc-10x10-unorm", + "astc-10x10-unorm-srgb", + "astc-12x10-unorm", + "astc-12x10-unorm-srgb", + "astc-12x12-unorm", + "astc-12x12-unorm-srgb", "depth24unorm-stencil8", "depth32float-stencil8", ], @@ -1131,7 +1176,7 @@ defaultValue: "none", }, { - key: "clampDepth", + key: "unclippedDepth", converter: webidl.converters["boolean"], defaultValue: false, }, @@ -1458,13 +1503,7 @@ ); // DICTIONARY: GPUCommandEncoderDescriptor - const dictMembersGPUCommandEncoderDescriptor = [ - { - key: "measureExecutionTime", - converter: webidl.converters["boolean"], - defaultValue: false, - }, - ]; + const dictMembersGPUCommandEncoderDescriptor = []; webidl.converters["GPUCommandEncoderDescriptor"] = webidl .createDictionaryConverter( "GPUCommandEncoderDescriptor", diff --git a/ext/webgpu/Cargo.toml b/ext/webgpu/Cargo.toml index 284f81278a8594..de5bf7ed4c45ef 100644 --- a/ext/webgpu/Cargo.toml +++ b/ext/webgpu/Cargo.toml @@ -1,4 +1,4 @@ -# Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. +# Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. [package] name = "deno_webgpu" @@ -7,15 +7,12 @@ authors = ["the Deno authors"] edition = "2021" license = "MIT" readme = "README.md" -repository = "https://github.com/denoland/deno" +repository = "https://github.com/gfx-rs/wgpu" description = "WebGPU implementation for Deno" -[lib] -path = "lib.rs" - [dependencies] deno_core = { version = "0.114.0", path = "../../core" } -serde = { version = "1.0.129", features = ["derive"] } -tokio = { version = "1.10.1", features = ["full"] } -wgpu-core = { version = "0.10.1", features = ["trace"] } -wgpu-types = "0.10.0" +serde = { version = "1.0", features = ["derive"] } +tokio = { version = "1.10", features = ["full"] } +wgpu-core = { version = "0.12.0", features = ["trace", "replay", "serde"] } +wgpu-types = { version = "0.12.0", features = ["trace", "replay", "serde"] } diff --git a/ext/webgpu/LICENSE.md b/ext/webgpu/LICENSE.md new file mode 100644 index 00000000000000..bbf190721dbda3 --- /dev/null +++ b/ext/webgpu/LICENSE.md @@ -0,0 +1,20 @@ +MIT License + +Copyright 2018-2021 the Deno authors + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/ext/webgpu/binding.rs b/ext/webgpu/binding.rs deleted file mode 100644 index fea99fc163583a..00000000000000 --- a/ext/webgpu/binding.rs +++ /dev/null @@ -1,367 +0,0 @@ -// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. - -use deno_core::error::AnyError; -use deno_core::ResourceId; -use deno_core::{OpState, Resource}; -use serde::Deserialize; -use std::borrow::Cow; - -use crate::texture::{GpuTextureFormat, GpuTextureViewDimension}; - -use super::error::WebGpuResult; - -pub(crate) struct WebGpuBindGroupLayout( - pub(crate) wgpu_core::id::BindGroupLayoutId, -); -impl Resource for WebGpuBindGroupLayout { - fn name(&self) -> Cow { - "webGPUBindGroupLayout".into() - } -} - -pub(crate) struct WebGpuBindGroup(pub(crate) wgpu_core::id::BindGroupId); -impl Resource for WebGpuBindGroup { - fn name(&self) -> Cow { - "webGPUBindGroup".into() - } -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -struct GpuBufferBindingLayout { - r#type: GpuBufferBindingType, - has_dynamic_offset: bool, - min_binding_size: u64, -} - -#[derive(Deserialize)] -#[serde(rename_all = "kebab-case")] -enum GpuBufferBindingType { - Uniform, - Storage, - ReadOnlyStorage, -} - -impl From for wgpu_types::BufferBindingType { - fn from(binding_type: GpuBufferBindingType) -> Self { - match binding_type { - GpuBufferBindingType::Uniform => wgpu_types::BufferBindingType::Uniform, - GpuBufferBindingType::Storage => { - wgpu_types::BufferBindingType::Storage { read_only: false } - } - GpuBufferBindingType::ReadOnlyStorage => { - wgpu_types::BufferBindingType::Storage { read_only: true } - } - } - } -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -struct GpuSamplerBindingLayout { - r#type: GpuSamplerBindingType, -} - -#[derive(Deserialize)] -#[serde(rename_all = "kebab-case")] -enum GpuSamplerBindingType { - Filtering, - NonFiltering, - Comparison, -} - -impl From for wgpu_types::BindingType { - fn from(binding_type: GpuSamplerBindingType) -> Self { - match binding_type { - GpuSamplerBindingType::Filtering => wgpu_types::BindingType::Sampler { - filtering: true, - comparison: false, - }, - GpuSamplerBindingType::NonFiltering => wgpu_types::BindingType::Sampler { - filtering: false, - comparison: false, - }, - GpuSamplerBindingType::Comparison => wgpu_types::BindingType::Sampler { - filtering: true, - comparison: true, - }, - } - } -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -struct GpuTextureBindingLayout { - sample_type: GpuTextureSampleType, - view_dimension: GpuTextureViewDimension, - multisampled: bool, -} - -#[derive(Deserialize)] -#[serde(rename_all = "kebab-case")] -enum GpuTextureSampleType { - Float, - UnfilterableFloat, - Depth, - Sint, - Uint, -} - -impl From for wgpu_types::TextureSampleType { - fn from(sample_type: GpuTextureSampleType) -> Self { - match sample_type { - GpuTextureSampleType::Float => { - wgpu_types::TextureSampleType::Float { filterable: true } - } - GpuTextureSampleType::UnfilterableFloat => { - wgpu_types::TextureSampleType::Float { filterable: false } - } - GpuTextureSampleType::Depth => wgpu_types::TextureSampleType::Depth, - GpuTextureSampleType::Sint => wgpu_types::TextureSampleType::Sint, - GpuTextureSampleType::Uint => wgpu_types::TextureSampleType::Uint, - } - } -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -struct GpuStorageTextureBindingLayout { - access: GpuStorageTextureAccess, - format: GpuTextureFormat, - view_dimension: GpuTextureViewDimension, -} - -#[derive(Deserialize)] -#[serde(rename_all = "kebab-case")] -enum GpuStorageTextureAccess { - WriteOnly, -} - -impl From for wgpu_types::StorageTextureAccess { - fn from(access: GpuStorageTextureAccess) -> Self { - match access { - GpuStorageTextureAccess::WriteOnly => { - wgpu_types::StorageTextureAccess::WriteOnly - } - } - } -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -struct GpuBindGroupLayoutEntry { - binding: u32, - visibility: u32, - #[serde(flatten)] - binding_type: GpuBindingType, -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -enum GpuBindingType { - Buffer(GpuBufferBindingLayout), - Sampler(GpuSamplerBindingLayout), - Texture(GpuTextureBindingLayout), - StorageTexture(GpuStorageTextureBindingLayout), -} - -impl TryFrom for wgpu_types::BindingType { - type Error = AnyError; - - fn try_from( - binding_type: GpuBindingType, - ) -> Result { - let binding_type = match binding_type { - GpuBindingType::Buffer(buffer) => wgpu_types::BindingType::Buffer { - ty: buffer.r#type.into(), - has_dynamic_offset: buffer.has_dynamic_offset, - min_binding_size: std::num::NonZeroU64::new(buffer.min_binding_size), - }, - GpuBindingType::Sampler(sampler) => sampler.r#type.into(), - GpuBindingType::Texture(texture) => wgpu_types::BindingType::Texture { - sample_type: texture.sample_type.into(), - view_dimension: texture.view_dimension.into(), - multisampled: texture.multisampled, - }, - GpuBindingType::StorageTexture(storage_texture) => { - wgpu_types::BindingType::StorageTexture { - access: storage_texture.access.into(), - format: storage_texture.format.try_into()?, - view_dimension: storage_texture.view_dimension.into(), - } - } - }; - Ok(binding_type) - } -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct CreateBindGroupLayoutArgs { - device_rid: ResourceId, - label: Option, - entries: Vec, -} - -pub fn op_webgpu_create_bind_group_layout( - state: &mut OpState, - args: CreateBindGroupLayoutArgs, - _: (), -) -> Result { - let instance = state.borrow::(); - let device_resource = state - .resource_table - .get::(args.device_rid)?; - let device = device_resource.0; - - let mut entries = vec![]; - - for entry in args.entries { - entries.push(wgpu_types::BindGroupLayoutEntry { - binding: entry.binding, - visibility: wgpu_types::ShaderStages::from_bits(entry.visibility) - .unwrap(), - ty: entry.binding_type.try_into()?, - count: None, // native-only - }); - } - - let descriptor = wgpu_core::binding_model::BindGroupLayoutDescriptor { - label: args.label.map(Cow::from), - entries: Cow::from(entries), - }; - - gfx_put!(device => instance.device_create_bind_group_layout( - device, - &descriptor, - std::marker::PhantomData - ) => state, WebGpuBindGroupLayout) -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct CreatePipelineLayoutArgs { - device_rid: ResourceId, - label: Option, - bind_group_layouts: Vec, -} - -pub fn op_webgpu_create_pipeline_layout( - state: &mut OpState, - args: CreatePipelineLayoutArgs, - _: (), -) -> Result { - let instance = state.borrow::(); - let device_resource = state - .resource_table - .get::(args.device_rid)?; - let device = device_resource.0; - - let mut bind_group_layouts = vec![]; - - for rid in &args.bind_group_layouts { - let bind_group_layout = - state.resource_table.get::(*rid)?; - bind_group_layouts.push(bind_group_layout.0); - } - - let descriptor = wgpu_core::binding_model::PipelineLayoutDescriptor { - label: args.label.map(Cow::from), - bind_group_layouts: Cow::from(bind_group_layouts), - push_constant_ranges: Default::default(), - }; - - gfx_put!(device => instance.device_create_pipeline_layout( - device, - &descriptor, - std::marker::PhantomData - ) => state, super::pipeline::WebGpuPipelineLayout) -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -struct GpuBindGroupEntry { - binding: u32, - kind: String, - resource: ResourceId, - offset: Option, - size: Option, -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct CreateBindGroupArgs { - device_rid: ResourceId, - label: Option, - layout: ResourceId, - entries: Vec, -} - -pub fn op_webgpu_create_bind_group( - state: &mut OpState, - args: CreateBindGroupArgs, - _: (), -) -> Result { - let instance = state.borrow::(); - let device_resource = state - .resource_table - .get::(args.device_rid)?; - let device = device_resource.0; - - let mut entries = vec![]; - - for entry in &args.entries { - let e = wgpu_core::binding_model::BindGroupEntry { - binding: entry.binding, - resource: match entry.kind.as_str() { - "GPUSampler" => { - let sampler_resource = - state - .resource_table - .get::(entry.resource)?; - wgpu_core::binding_model::BindingResource::Sampler(sampler_resource.0) - } - "GPUTextureView" => { - let texture_view_resource = - state - .resource_table - .get::(entry.resource)?; - wgpu_core::binding_model::BindingResource::TextureView( - texture_view_resource.0, - ) - } - "GPUBufferBinding" => { - let buffer_resource = - state - .resource_table - .get::(entry.resource)?; - wgpu_core::binding_model::BindingResource::Buffer( - wgpu_core::binding_model::BufferBinding { - buffer_id: buffer_resource.0, - offset: entry.offset.unwrap_or(0), - size: std::num::NonZeroU64::new(entry.size.unwrap_or(0)), - }, - ) - } - _ => unreachable!(), - }, - }; - entries.push(e); - } - - let bind_group_layout = state - .resource_table - .get::(args.layout)?; - - let descriptor = wgpu_core::binding_model::BindGroupDescriptor { - label: args.label.map(Cow::from), - layout: bind_group_layout.0, - entries: Cow::from(entries), - }; - - gfx_put!(device => instance.device_create_bind_group( - device, - &descriptor, - std::marker::PhantomData - ) => state, WebGpuBindGroup) -} diff --git a/ext/webgpu/buffer.rs b/ext/webgpu/buffer.rs deleted file mode 100644 index 3f2c078831ffcd..00000000000000 --- a/ext/webgpu/buffer.rs +++ /dev/null @@ -1,229 +0,0 @@ -// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. - -use deno_core::error::type_error; -use deno_core::error::AnyError; -use deno_core::futures::channel::oneshot; -use deno_core::OpState; -use deno_core::Resource; -use deno_core::ResourceId; -use deno_core::ZeroCopyBuf; -use serde::Deserialize; -use std::borrow::Cow; -use std::cell::RefCell; -use std::rc::Rc; -use std::time::Duration; - -use super::error::DomExceptionOperationError; -use super::error::WebGpuResult; - -pub(crate) struct WebGpuBuffer(pub(crate) wgpu_core::id::BufferId); -impl Resource for WebGpuBuffer { - fn name(&self) -> Cow { - "webGPUBuffer".into() - } -} - -struct WebGpuBufferMapped(*mut u8, usize); -impl Resource for WebGpuBufferMapped { - fn name(&self) -> Cow { - "webGPUBufferMapped".into() - } -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct CreateBufferArgs { - device_rid: ResourceId, - label: Option, - size: u64, - usage: u32, - mapped_at_creation: bool, -} - -pub fn op_webgpu_create_buffer( - state: &mut OpState, - args: CreateBufferArgs, - _: (), -) -> Result { - let instance = state.borrow::(); - let device_resource = state - .resource_table - .get::(args.device_rid)?; - let device = device_resource.0; - - let descriptor = wgpu_core::resource::BufferDescriptor { - label: args.label.map(Cow::from), - size: args.size, - usage: wgpu_types::BufferUsages::from_bits(args.usage) - .ok_or_else(|| type_error("usage is not valid"))?, - mapped_at_creation: args.mapped_at_creation, - }; - - gfx_put!(device => instance.device_create_buffer( - device, - &descriptor, - std::marker::PhantomData - ) => state, WebGpuBuffer) -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct BufferGetMapAsyncArgs { - buffer_rid: ResourceId, - device_rid: ResourceId, - mode: u32, - offset: u64, - size: u64, -} - -pub async fn op_webgpu_buffer_get_map_async( - state: Rc>, - args: BufferGetMapAsyncArgs, - _: (), -) -> Result { - let (sender, receiver) = oneshot::channel::>(); - - let device; - { - let state_ = state.borrow(); - let instance = state_.borrow::(); - let buffer_resource = - state_.resource_table.get::(args.buffer_rid)?; - let buffer = buffer_resource.0; - let device_resource = state_ - .resource_table - .get::(args.device_rid)?; - device = device_resource.0; - - let boxed_sender = Box::new(sender); - let sender_ptr = Box::into_raw(boxed_sender) as *mut u8; - - extern "C" fn buffer_map_future_wrapper( - status: wgpu_core::resource::BufferMapAsyncStatus, - user_data: *mut u8, - ) { - let sender_ptr = user_data as *mut oneshot::Sender>; - let boxed_sender = unsafe { Box::from_raw(sender_ptr) }; - boxed_sender - .send(match status { - wgpu_core::resource::BufferMapAsyncStatus::Success => Ok(()), - _ => unreachable!(), // TODO - }) - .unwrap(); - } - - // TODO(lucacasonato): error handling - let maybe_err = gfx_select!(buffer => instance.buffer_map_async( - buffer, - args.offset..(args.offset + args.size), - wgpu_core::resource::BufferMapOperation { - host: match args.mode { - 1 => wgpu_core::device::HostMap::Read, - 2 => wgpu_core::device::HostMap::Write, - _ => unreachable!(), - }, - callback: buffer_map_future_wrapper, - user_data: sender_ptr, - } - )) - .err(); - - if maybe_err.is_some() { - return Ok(WebGpuResult::maybe_err(maybe_err)); - } - } - - let done = Rc::new(RefCell::new(false)); - let done_ = done.clone(); - let device_poll_fut = async move { - while !*done.borrow() { - { - let state = state.borrow(); - let instance = state.borrow::(); - gfx_select!(device => instance.device_poll(device, false)).unwrap() - } - tokio::time::sleep(Duration::from_millis(10)).await; - } - Ok::<(), AnyError>(()) - }; - - let receiver_fut = async move { - receiver.await??; - let mut done = done_.borrow_mut(); - *done = true; - Ok::<(), AnyError>(()) - }; - - tokio::try_join!(device_poll_fut, receiver_fut)?; - - Ok(WebGpuResult::empty()) -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct BufferGetMappedRangeArgs { - buffer_rid: ResourceId, - offset: u64, - size: Option, -} - -pub fn op_webgpu_buffer_get_mapped_range( - state: &mut OpState, - args: BufferGetMappedRangeArgs, - mut zero_copy: ZeroCopyBuf, -) -> Result { - let instance = state.borrow::(); - let buffer_resource = - state.resource_table.get::(args.buffer_rid)?; - let buffer = buffer_resource.0; - - let (slice_pointer, range_size) = - gfx_select!(buffer => instance.buffer_get_mapped_range( - buffer, - args.offset, - args.size - )) - .map_err(|e| DomExceptionOperationError::new(&e.to_string()))?; - - let slice = unsafe { - std::slice::from_raw_parts_mut(slice_pointer, range_size as usize) - }; - zero_copy.copy_from_slice(slice); - - let rid = state - .resource_table - .add(WebGpuBufferMapped(slice_pointer, range_size as usize)); - - Ok(WebGpuResult::rid(rid)) -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct BufferUnmapArgs { - buffer_rid: ResourceId, - mapped_rid: ResourceId, -} - -pub fn op_webgpu_buffer_unmap( - state: &mut OpState, - args: BufferUnmapArgs, - zero_copy: Option, -) -> Result { - let mapped_resource = state - .resource_table - .take::(args.mapped_rid)?; - let instance = state.borrow::(); - let buffer_resource = - state.resource_table.get::(args.buffer_rid)?; - let buffer = buffer_resource.0; - - let slice_pointer = mapped_resource.0; - let size = mapped_resource.1; - - if let Some(buffer) = zero_copy { - let slice = unsafe { std::slice::from_raw_parts_mut(slice_pointer, size) }; - slice.copy_from_slice(&buffer); - } - - gfx_ok!(buffer => instance.buffer_unmap(buffer)) -} diff --git a/ext/webgpu/bundle.rs b/ext/webgpu/bundle.rs deleted file mode 100644 index 7b32c1ecefc1c9..00000000000000 --- a/ext/webgpu/bundle.rs +++ /dev/null @@ -1,461 +0,0 @@ -// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. - -use deno_core::error::AnyError; -use deno_core::ResourceId; -use deno_core::ZeroCopyBuf; -use deno_core::{OpState, Resource}; -use serde::Deserialize; -use std::borrow::Cow; -use std::cell::RefCell; -use std::rc::Rc; - -use crate::pipeline::GpuIndexFormat; -use crate::texture::GpuTextureFormat; - -use super::error::WebGpuResult; - -struct WebGpuRenderBundleEncoder( - RefCell, -); -impl Resource for WebGpuRenderBundleEncoder { - fn name(&self) -> Cow { - "webGPURenderBundleEncoder".into() - } -} - -pub(crate) struct WebGpuRenderBundle(pub(crate) wgpu_core::id::RenderBundleId); -impl Resource for WebGpuRenderBundle { - fn name(&self) -> Cow { - "webGPURenderBundle".into() - } -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct CreateRenderBundleEncoderArgs { - device_rid: ResourceId, - label: Option, - color_formats: Vec, - depth_stencil_format: Option, - sample_count: u32, - depth_read_only: bool, - stencil_read_only: bool, -} - -pub fn op_webgpu_create_render_bundle_encoder( - state: &mut OpState, - args: CreateRenderBundleEncoderArgs, - _: (), -) -> Result { - let device_resource = state - .resource_table - .get::(args.device_rid)?; - let device = device_resource.0; - - let mut color_formats = vec![]; - - for format in args.color_formats { - color_formats.push(format.try_into()?); - } - - let depth_stencil = if let Some(format) = args.depth_stencil_format { - Some(wgpu_types::RenderBundleDepthStencil { - format: format.try_into()?, - depth_read_only: args.depth_read_only, - stencil_read_only: args.stencil_read_only, - }) - } else { - None - }; - - let descriptor = wgpu_core::command::RenderBundleEncoderDescriptor { - label: args.label.map(Cow::from), - color_formats: Cow::from(color_formats), - sample_count: args.sample_count, - depth_stencil, - }; - - let res = - wgpu_core::command::RenderBundleEncoder::new(&descriptor, device, None); - let (render_bundle_encoder, maybe_err) = match res { - Ok(encoder) => (encoder, None), - Err(e) => ( - wgpu_core::command::RenderBundleEncoder::dummy(device), - Some(e), - ), - }; - - let rid = state - .resource_table - .add(WebGpuRenderBundleEncoder(RefCell::new( - render_bundle_encoder, - ))); - - Ok(WebGpuResult::rid_err(rid, maybe_err)) -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct RenderBundleEncoderFinishArgs { - render_bundle_encoder_rid: ResourceId, - label: Option, -} - -pub fn op_webgpu_render_bundle_encoder_finish( - state: &mut OpState, - args: RenderBundleEncoderFinishArgs, - _: (), -) -> Result { - let render_bundle_encoder_resource = - state - .resource_table - .take::(args.render_bundle_encoder_rid)?; - let render_bundle_encoder = Rc::try_unwrap(render_bundle_encoder_resource) - .ok() - .expect("unwrapping render_bundle_encoder_resource should succeed") - .0 - .into_inner(); - let instance = state.borrow::(); - - gfx_put!(render_bundle_encoder.parent() => instance.render_bundle_encoder_finish( - render_bundle_encoder, - &wgpu_core::command::RenderBundleDescriptor { - label: args.label.map(Cow::from), - }, - std::marker::PhantomData - ) => state, WebGpuRenderBundle) -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct RenderBundleEncoderSetBindGroupArgs { - render_bundle_encoder_rid: ResourceId, - index: u32, - bind_group: ResourceId, - dynamic_offsets_data: ZeroCopyBuf, - dynamic_offsets_data_start: usize, - dynamic_offsets_data_length: usize, -} - -pub fn op_webgpu_render_bundle_encoder_set_bind_group( - state: &mut OpState, - args: RenderBundleEncoderSetBindGroupArgs, - _: (), -) -> Result { - let bind_group_resource = - state - .resource_table - .get::(args.bind_group)?; - let render_bundle_encoder_resource = - state - .resource_table - .get::(args.render_bundle_encoder_rid)?; - - // Align the data - assert!(args.dynamic_offsets_data.len() % std::mem::size_of::() == 0); - // SAFETY: A u8 to u32 cast is safe because we asserted that the length is a - // multiple of 4. - let (prefix, dynamic_offsets_data, suffix) = - unsafe { args.dynamic_offsets_data.align_to::() }; - assert!(prefix.is_empty()); - assert!(suffix.is_empty()); - - let start = args.dynamic_offsets_data_start; - let len = args.dynamic_offsets_data_length; - - // Assert that length and start are both in bounds - assert!(start <= dynamic_offsets_data.len()); - assert!(len <= dynamic_offsets_data.len() - start); - - let dynamic_offsets_data: &[u32] = &dynamic_offsets_data[start..start + len]; - - // SAFETY: the raw pointer and length are of the same slice, and that slice - // lives longer than the below function invocation. - unsafe { - wgpu_core::command::bundle_ffi::wgpu_render_bundle_set_bind_group( - &mut render_bundle_encoder_resource.0.borrow_mut(), - args.index, - bind_group_resource.0, - dynamic_offsets_data.as_ptr(), - dynamic_offsets_data.len(), - ); - } - - Ok(WebGpuResult::empty()) -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct RenderBundleEncoderPushDebugGroupArgs { - render_bundle_encoder_rid: ResourceId, - group_label: String, -} - -pub fn op_webgpu_render_bundle_encoder_push_debug_group( - state: &mut OpState, - args: RenderBundleEncoderPushDebugGroupArgs, - _: (), -) -> Result { - let render_bundle_encoder_resource = - state - .resource_table - .get::(args.render_bundle_encoder_rid)?; - - let label = std::ffi::CString::new(args.group_label).unwrap(); - // SAFETY: the string the raw pointer points to lives longer than the below - // function invocation. - unsafe { - wgpu_core::command::bundle_ffi::wgpu_render_bundle_push_debug_group( - &mut render_bundle_encoder_resource.0.borrow_mut(), - label.as_ptr(), - ); - } - - Ok(WebGpuResult::empty()) -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct RenderBundleEncoderPopDebugGroupArgs { - render_bundle_encoder_rid: ResourceId, -} - -pub fn op_webgpu_render_bundle_encoder_pop_debug_group( - state: &mut OpState, - args: RenderBundleEncoderPopDebugGroupArgs, - _: (), -) -> Result { - let render_bundle_encoder_resource = - state - .resource_table - .get::(args.render_bundle_encoder_rid)?; - - wgpu_core::command::bundle_ffi::wgpu_render_bundle_pop_debug_group( - &mut render_bundle_encoder_resource.0.borrow_mut(), - ); - - Ok(WebGpuResult::empty()) -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct RenderBundleEncoderInsertDebugMarkerArgs { - render_bundle_encoder_rid: ResourceId, - marker_label: String, -} - -pub fn op_webgpu_render_bundle_encoder_insert_debug_marker( - state: &mut OpState, - args: RenderBundleEncoderInsertDebugMarkerArgs, - _: (), -) -> Result { - let render_bundle_encoder_resource = - state - .resource_table - .get::(args.render_bundle_encoder_rid)?; - - let label = std::ffi::CString::new(args.marker_label).unwrap(); - // SAFETY: the string the raw pointer points to lives longer than the below - // function invocation. - unsafe { - wgpu_core::command::bundle_ffi::wgpu_render_bundle_insert_debug_marker( - &mut render_bundle_encoder_resource.0.borrow_mut(), - label.as_ptr(), - ); - } - - Ok(WebGpuResult::empty()) -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct RenderBundleEncoderSetPipelineArgs { - render_bundle_encoder_rid: ResourceId, - pipeline: ResourceId, -} - -pub fn op_webgpu_render_bundle_encoder_set_pipeline( - state: &mut OpState, - args: RenderBundleEncoderSetPipelineArgs, - _: (), -) -> Result { - let render_pipeline_resource = - state - .resource_table - .get::(args.pipeline)?; - let render_bundle_encoder_resource = - state - .resource_table - .get::(args.render_bundle_encoder_rid)?; - - wgpu_core::command::bundle_ffi::wgpu_render_bundle_set_pipeline( - &mut render_bundle_encoder_resource.0.borrow_mut(), - render_pipeline_resource.0, - ); - - Ok(WebGpuResult::empty()) -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct RenderBundleEncoderSetIndexBufferArgs { - render_bundle_encoder_rid: ResourceId, - buffer: ResourceId, - index_format: GpuIndexFormat, - offset: u64, - size: u64, -} - -pub fn op_webgpu_render_bundle_encoder_set_index_buffer( - state: &mut OpState, - args: RenderBundleEncoderSetIndexBufferArgs, - _: (), -) -> Result { - let buffer_resource = state - .resource_table - .get::(args.buffer)?; - let render_bundle_encoder_resource = - state - .resource_table - .get::(args.render_bundle_encoder_rid)?; - - render_bundle_encoder_resource - .0 - .borrow_mut() - .set_index_buffer( - buffer_resource.0, - args.index_format.into(), - args.offset, - std::num::NonZeroU64::new(args.size), - ); - - Ok(WebGpuResult::empty()) -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct RenderBundleEncoderSetVertexBufferArgs { - render_bundle_encoder_rid: ResourceId, - slot: u32, - buffer: ResourceId, - offset: u64, - size: u64, -} - -pub fn op_webgpu_render_bundle_encoder_set_vertex_buffer( - state: &mut OpState, - args: RenderBundleEncoderSetVertexBufferArgs, - _: (), -) -> Result { - let buffer_resource = state - .resource_table - .get::(args.buffer)?; - let render_bundle_encoder_resource = - state - .resource_table - .get::(args.render_bundle_encoder_rid)?; - - wgpu_core::command::bundle_ffi::wgpu_render_bundle_set_vertex_buffer( - &mut render_bundle_encoder_resource.0.borrow_mut(), - args.slot, - buffer_resource.0, - args.offset, - std::num::NonZeroU64::new(args.size), - ); - - Ok(WebGpuResult::empty()) -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct RenderBundleEncoderDrawArgs { - render_bundle_encoder_rid: ResourceId, - vertex_count: u32, - instance_count: u32, - first_vertex: u32, - first_instance: u32, -} - -pub fn op_webgpu_render_bundle_encoder_draw( - state: &mut OpState, - args: RenderBundleEncoderDrawArgs, - _: (), -) -> Result { - let render_bundle_encoder_resource = - state - .resource_table - .get::(args.render_bundle_encoder_rid)?; - - wgpu_core::command::bundle_ffi::wgpu_render_bundle_draw( - &mut render_bundle_encoder_resource.0.borrow_mut(), - args.vertex_count, - args.instance_count, - args.first_vertex, - args.first_instance, - ); - - Ok(WebGpuResult::empty()) -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct RenderBundleEncoderDrawIndexedArgs { - render_bundle_encoder_rid: ResourceId, - index_count: u32, - instance_count: u32, - first_index: u32, - base_vertex: i32, - first_instance: u32, -} - -pub fn op_webgpu_render_bundle_encoder_draw_indexed( - state: &mut OpState, - args: RenderBundleEncoderDrawIndexedArgs, - _: (), -) -> Result { - let render_bundle_encoder_resource = - state - .resource_table - .get::(args.render_bundle_encoder_rid)?; - - wgpu_core::command::bundle_ffi::wgpu_render_bundle_draw_indexed( - &mut render_bundle_encoder_resource.0.borrow_mut(), - args.index_count, - args.instance_count, - args.first_index, - args.base_vertex, - args.first_instance, - ); - - Ok(WebGpuResult::empty()) -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct RenderBundleEncoderDrawIndirectArgs { - render_bundle_encoder_rid: ResourceId, - indirect_buffer: ResourceId, - indirect_offset: u64, -} - -pub fn op_webgpu_render_bundle_encoder_draw_indirect( - state: &mut OpState, - args: RenderBundleEncoderDrawIndirectArgs, - _: (), -) -> Result { - let buffer_resource = state - .resource_table - .get::(args.indirect_buffer)?; - let render_bundle_encoder_resource = - state - .resource_table - .get::(args.render_bundle_encoder_rid)?; - - wgpu_core::command::bundle_ffi::wgpu_render_bundle_draw_indirect( - &mut render_bundle_encoder_resource.0.borrow_mut(), - buffer_resource.0, - args.indirect_offset, - ); - - Ok(WebGpuResult::empty()) -} diff --git a/ext/webgpu/command_encoder.rs b/ext/webgpu/command_encoder.rs deleted file mode 100644 index cbd57f694e8015..00000000000000 --- a/ext/webgpu/command_encoder.rs +++ /dev/null @@ -1,656 +0,0 @@ -// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. - -use deno_core::error::AnyError; -use deno_core::ResourceId; -use deno_core::{OpState, Resource}; -use serde::Deserialize; -use std::borrow::Cow; -use std::cell::RefCell; -use std::num::NonZeroU32; - -use crate::texture::GpuTextureAspect; - -use super::error::WebGpuResult; - -pub(crate) struct WebGpuCommandEncoder( - pub(crate) wgpu_core::id::CommandEncoderId, -); -impl Resource for WebGpuCommandEncoder { - fn name(&self) -> Cow { - "webGPUCommandEncoder".into() - } -} - -pub(crate) struct WebGpuCommandBuffer( - pub(crate) wgpu_core::id::CommandBufferId, -); -impl Resource for WebGpuCommandBuffer { - fn name(&self) -> Cow { - "webGPUCommandBuffer".into() - } -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct CreateCommandEncoderArgs { - device_rid: ResourceId, - label: Option, - _measure_execution_time: Option, // not yet implemented -} - -pub fn op_webgpu_create_command_encoder( - state: &mut OpState, - args: CreateCommandEncoderArgs, - _: (), -) -> Result { - let instance = state.borrow::(); - let device_resource = state - .resource_table - .get::(args.device_rid)?; - let device = device_resource.0; - - let descriptor = wgpu_types::CommandEncoderDescriptor { - label: args.label.map(Cow::from), - }; - - gfx_put!(device => instance.device_create_command_encoder( - device, - &descriptor, - std::marker::PhantomData - ) => state, WebGpuCommandEncoder) -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct GpuRenderPassColorAttachment { - view: ResourceId, - resolve_target: Option, - load_op: GpuLoadOp, - store_op: GpuStoreOp, -} - -#[derive(Deserialize)] -#[serde(rename_all = "kebab-case")] -enum GpuLoadOp { - Load, - Clear(T), -} - -#[derive(Deserialize)] -#[serde(rename_all = "kebab-case")] -enum GpuStoreOp { - Store, - Discard, -} - -impl From for wgpu_core::command::StoreOp { - fn from(value: GpuStoreOp) -> wgpu_core::command::StoreOp { - match value { - GpuStoreOp::Store => wgpu_core::command::StoreOp::Store, - GpuStoreOp::Discard => wgpu_core::command::StoreOp::Discard, - } - } -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -struct GpuRenderPassDepthStencilAttachment { - view: ResourceId, - depth_load_op: GpuLoadOp, - depth_store_op: GpuStoreOp, - depth_read_only: bool, - stencil_load_op: GpuLoadOp, - stencil_store_op: GpuStoreOp, - stencil_read_only: bool, -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct CommandEncoderBeginRenderPassArgs { - command_encoder_rid: ResourceId, - label: Option, - color_attachments: Vec, - depth_stencil_attachment: Option, - _occlusion_query_set: Option, // not yet implemented -} - -pub fn op_webgpu_command_encoder_begin_render_pass( - state: &mut OpState, - args: CommandEncoderBeginRenderPassArgs, - _: (), -) -> Result { - let command_encoder_resource = state - .resource_table - .get::(args.command_encoder_rid)?; - - let mut color_attachments = vec![]; - - for color_attachment in args.color_attachments { - let texture_view_resource = - state - .resource_table - .get::(color_attachment.view)?; - - let resolve_target = color_attachment - .resolve_target - .map(|rid| { - state - .resource_table - .get::(rid) - }) - .transpose()? - .map(|texture| texture.0); - - let attachment = wgpu_core::command::RenderPassColorAttachment { - view: texture_view_resource.0, - resolve_target, - channel: match color_attachment.load_op { - GpuLoadOp::Load => wgpu_core::command::PassChannel { - load_op: wgpu_core::command::LoadOp::Load, - store_op: color_attachment.store_op.into(), - clear_value: Default::default(), - read_only: false, - }, - GpuLoadOp::Clear(color) => wgpu_core::command::PassChannel { - load_op: wgpu_core::command::LoadOp::Clear, - store_op: color_attachment.store_op.into(), - clear_value: wgpu_types::Color { - r: color.r, - g: color.g, - b: color.b, - a: color.a, - }, - read_only: false, - }, - }, - }; - - color_attachments.push(attachment) - } - - let mut depth_stencil_attachment = None; - - if let Some(attachment) = args.depth_stencil_attachment { - let texture_view_resource = - state - .resource_table - .get::(attachment.view)?; - - depth_stencil_attachment = - Some(wgpu_core::command::RenderPassDepthStencilAttachment { - view: texture_view_resource.0, - depth: match attachment.depth_load_op { - GpuLoadOp::Load => wgpu_core::command::PassChannel { - load_op: wgpu_core::command::LoadOp::Load, - store_op: attachment.depth_store_op.into(), - clear_value: 0.0, - read_only: attachment.depth_read_only, - }, - GpuLoadOp::Clear(value) => wgpu_core::command::PassChannel { - load_op: wgpu_core::command::LoadOp::Clear, - store_op: attachment.depth_store_op.into(), - clear_value: value, - read_only: attachment.depth_read_only, - }, - }, - stencil: match attachment.stencil_load_op { - GpuLoadOp::Load => wgpu_core::command::PassChannel { - load_op: wgpu_core::command::LoadOp::Load, - store_op: attachment.stencil_store_op.into(), - clear_value: 0, - read_only: attachment.stencil_read_only, - }, - GpuLoadOp::Clear(value) => wgpu_core::command::PassChannel { - load_op: wgpu_core::command::LoadOp::Clear, - store_op: attachment.stencil_store_op.into(), - clear_value: value, - read_only: attachment.stencil_read_only, - }, - }, - }); - } - - let descriptor = wgpu_core::command::RenderPassDescriptor { - label: args.label.map(Cow::from), - color_attachments: Cow::from(color_attachments), - depth_stencil_attachment: depth_stencil_attachment.as_ref(), - }; - - let render_pass = wgpu_core::command::RenderPass::new( - command_encoder_resource.0, - &descriptor, - ); - - let rid = state - .resource_table - .add(super::render_pass::WebGpuRenderPass(RefCell::new( - render_pass, - ))); - - Ok(WebGpuResult::rid(rid)) -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct CommandEncoderBeginComputePassArgs { - command_encoder_rid: ResourceId, - label: Option, -} - -pub fn op_webgpu_command_encoder_begin_compute_pass( - state: &mut OpState, - args: CommandEncoderBeginComputePassArgs, - _: (), -) -> Result { - let command_encoder_resource = state - .resource_table - .get::(args.command_encoder_rid)?; - - let descriptor = wgpu_core::command::ComputePassDescriptor { - label: args.label.map(Cow::from), - }; - - let compute_pass = wgpu_core::command::ComputePass::new( - command_encoder_resource.0, - &descriptor, - ); - - let rid = state - .resource_table - .add(super::compute_pass::WebGpuComputePass(RefCell::new( - compute_pass, - ))); - - Ok(WebGpuResult::rid(rid)) -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct CommandEncoderCopyBufferToBufferArgs { - command_encoder_rid: ResourceId, - source: ResourceId, - source_offset: u64, - destination: ResourceId, - destination_offset: u64, - size: u64, -} - -pub fn op_webgpu_command_encoder_copy_buffer_to_buffer( - state: &mut OpState, - args: CommandEncoderCopyBufferToBufferArgs, - _: (), -) -> Result { - let instance = state.borrow::(); - let command_encoder_resource = state - .resource_table - .get::(args.command_encoder_rid)?; - let command_encoder = command_encoder_resource.0; - let source_buffer_resource = - state - .resource_table - .get::(args.source)?; - let source_buffer = source_buffer_resource.0; - let destination_buffer_resource = - state - .resource_table - .get::(args.destination)?; - let destination_buffer = destination_buffer_resource.0; - - gfx_ok!(command_encoder => instance.command_encoder_copy_buffer_to_buffer( - command_encoder, - source_buffer, - args.source_offset, - destination_buffer, - args.destination_offset, - args.size - )) -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct GpuImageCopyBuffer { - buffer: ResourceId, - offset: u64, - bytes_per_row: Option, - rows_per_image: Option, -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct GpuOrigin3D { - pub x: u32, - pub y: u32, - pub z: u32, -} - -impl From for wgpu_types::Origin3d { - fn from(origin: GpuOrigin3D) -> wgpu_types::Origin3d { - wgpu_types::Origin3d { - x: origin.x, - y: origin.y, - z: origin.z, - } - } -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct GpuImageCopyTexture { - pub texture: ResourceId, - pub mip_level: u32, - pub origin: GpuOrigin3D, - pub aspect: GpuTextureAspect, -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct CommandEncoderCopyBufferToTextureArgs { - command_encoder_rid: ResourceId, - source: GpuImageCopyBuffer, - destination: GpuImageCopyTexture, - copy_size: super::texture::GpuExtent3D, -} - -pub fn op_webgpu_command_encoder_copy_buffer_to_texture( - state: &mut OpState, - args: CommandEncoderCopyBufferToTextureArgs, - _: (), -) -> Result { - let instance = state.borrow::(); - let command_encoder_resource = state - .resource_table - .get::(args.command_encoder_rid)?; - let command_encoder = command_encoder_resource.0; - let source_buffer_resource = - state - .resource_table - .get::(args.source.buffer)?; - let destination_texture_resource = - state - .resource_table - .get::(args.destination.texture)?; - - let source = wgpu_core::command::ImageCopyBuffer { - buffer: source_buffer_resource.0, - layout: wgpu_types::ImageDataLayout { - offset: args.source.offset, - bytes_per_row: NonZeroU32::new(args.source.bytes_per_row.unwrap_or(0)), - rows_per_image: NonZeroU32::new(args.source.rows_per_image.unwrap_or(0)), - }, - }; - let destination = wgpu_core::command::ImageCopyTexture { - texture: destination_texture_resource.0, - mip_level: args.destination.mip_level, - origin: args.destination.origin.into(), - aspect: args.destination.aspect.into(), - }; - gfx_ok!(command_encoder => instance.command_encoder_copy_buffer_to_texture( - command_encoder, - &source, - &destination, - &args.copy_size.into() - )) -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct CommandEncoderCopyTextureToBufferArgs { - command_encoder_rid: ResourceId, - source: GpuImageCopyTexture, - destination: GpuImageCopyBuffer, - copy_size: super::texture::GpuExtent3D, -} - -pub fn op_webgpu_command_encoder_copy_texture_to_buffer( - state: &mut OpState, - args: CommandEncoderCopyTextureToBufferArgs, - _: (), -) -> Result { - let instance = state.borrow::(); - let command_encoder_resource = state - .resource_table - .get::(args.command_encoder_rid)?; - let command_encoder = command_encoder_resource.0; - let source_texture_resource = - state - .resource_table - .get::(args.source.texture)?; - let destination_buffer_resource = - state - .resource_table - .get::(args.destination.buffer)?; - - let source = wgpu_core::command::ImageCopyTexture { - texture: source_texture_resource.0, - mip_level: args.source.mip_level, - origin: args.source.origin.into(), - aspect: args.source.aspect.into(), - }; - let destination = wgpu_core::command::ImageCopyBuffer { - buffer: destination_buffer_resource.0, - layout: wgpu_types::ImageDataLayout { - offset: args.destination.offset, - bytes_per_row: NonZeroU32::new( - args.destination.bytes_per_row.unwrap_or(0), - ), - rows_per_image: NonZeroU32::new( - args.destination.rows_per_image.unwrap_or(0), - ), - }, - }; - gfx_ok!(command_encoder => instance.command_encoder_copy_texture_to_buffer( - command_encoder, - &source, - &destination, - &args.copy_size.into() - )) -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct CommandEncoderCopyTextureToTextureArgs { - command_encoder_rid: ResourceId, - source: GpuImageCopyTexture, - destination: GpuImageCopyTexture, - copy_size: super::texture::GpuExtent3D, -} - -pub fn op_webgpu_command_encoder_copy_texture_to_texture( - state: &mut OpState, - args: CommandEncoderCopyTextureToTextureArgs, - _: (), -) -> Result { - let instance = state.borrow::(); - let command_encoder_resource = state - .resource_table - .get::(args.command_encoder_rid)?; - let command_encoder = command_encoder_resource.0; - let source_texture_resource = - state - .resource_table - .get::(args.source.texture)?; - let destination_texture_resource = - state - .resource_table - .get::(args.destination.texture)?; - - let source = wgpu_core::command::ImageCopyTexture { - texture: source_texture_resource.0, - mip_level: args.source.mip_level, - origin: args.source.origin.into(), - aspect: args.source.aspect.into(), - }; - let destination = wgpu_core::command::ImageCopyTexture { - texture: destination_texture_resource.0, - mip_level: args.destination.mip_level, - origin: args.destination.origin.into(), - aspect: args.destination.aspect.into(), - }; - gfx_ok!(command_encoder => instance.command_encoder_copy_texture_to_texture( - command_encoder, - &source, - &destination, - &args.copy_size.into() - )) -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct CommandEncoderPushDebugGroupArgs { - command_encoder_rid: ResourceId, - group_label: String, -} - -pub fn op_webgpu_command_encoder_push_debug_group( - state: &mut OpState, - args: CommandEncoderPushDebugGroupArgs, - _: (), -) -> Result { - let instance = state.borrow::(); - let command_encoder_resource = state - .resource_table - .get::(args.command_encoder_rid)?; - let command_encoder = command_encoder_resource.0; - - gfx_ok!(command_encoder => instance - .command_encoder_push_debug_group(command_encoder, &args.group_label)) -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct CommandEncoderPopDebugGroupArgs { - command_encoder_rid: ResourceId, -} - -pub fn op_webgpu_command_encoder_pop_debug_group( - state: &mut OpState, - args: CommandEncoderPopDebugGroupArgs, - _: (), -) -> Result { - let instance = state.borrow::(); - let command_encoder_resource = state - .resource_table - .get::(args.command_encoder_rid)?; - let command_encoder = command_encoder_resource.0; - - gfx_ok!(command_encoder => instance.command_encoder_pop_debug_group(command_encoder)) -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct CommandEncoderInsertDebugMarkerArgs { - command_encoder_rid: ResourceId, - marker_label: String, -} - -pub fn op_webgpu_command_encoder_insert_debug_marker( - state: &mut OpState, - args: CommandEncoderInsertDebugMarkerArgs, - _: (), -) -> Result { - let instance = state.borrow::(); - let command_encoder_resource = state - .resource_table - .get::(args.command_encoder_rid)?; - let command_encoder = command_encoder_resource.0; - - gfx_ok!(command_encoder => instance.command_encoder_insert_debug_marker( - command_encoder, - &args.marker_label - )) -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct CommandEncoderWriteTimestampArgs { - command_encoder_rid: ResourceId, - query_set: ResourceId, - query_index: u32, -} - -pub fn op_webgpu_command_encoder_write_timestamp( - state: &mut OpState, - args: CommandEncoderWriteTimestampArgs, - _: (), -) -> Result { - let instance = state.borrow::(); - let command_encoder_resource = state - .resource_table - .get::(args.command_encoder_rid)?; - let command_encoder = command_encoder_resource.0; - let query_set_resource = state - .resource_table - .get::(args.query_set)?; - - gfx_ok!(command_encoder => instance.command_encoder_write_timestamp( - command_encoder, - query_set_resource.0, - args.query_index - )) -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct CommandEncoderResolveQuerySetArgs { - command_encoder_rid: ResourceId, - query_set: ResourceId, - first_query: u32, - query_count: u32, - destination: ResourceId, - destination_offset: u64, -} - -pub fn op_webgpu_command_encoder_resolve_query_set( - state: &mut OpState, - args: CommandEncoderResolveQuerySetArgs, - _: (), -) -> Result { - let instance = state.borrow::(); - let command_encoder_resource = state - .resource_table - .get::(args.command_encoder_rid)?; - let command_encoder = command_encoder_resource.0; - let query_set_resource = state - .resource_table - .get::(args.query_set)?; - let destination_resource = state - .resource_table - .get::(args.destination)?; - - gfx_ok!(command_encoder => instance.command_encoder_resolve_query_set( - command_encoder, - query_set_resource.0, - args.first_query, - args.query_count, - destination_resource.0, - args.destination_offset - )) -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct CommandEncoderFinishArgs { - command_encoder_rid: ResourceId, - label: Option, -} - -pub fn op_webgpu_command_encoder_finish( - state: &mut OpState, - args: CommandEncoderFinishArgs, - _: (), -) -> Result { - let command_encoder_resource = state - .resource_table - .take::(args.command_encoder_rid)?; - let command_encoder = command_encoder_resource.0; - let instance = state.borrow::(); - - let descriptor = wgpu_types::CommandBufferDescriptor { - label: args.label.map(Cow::from), - }; - - gfx_put!(command_encoder => instance.command_encoder_finish( - command_encoder, - &descriptor - ) => state, WebGpuCommandBuffer) -} diff --git a/ext/webgpu/compute_pass.rs b/ext/webgpu/compute_pass.rs deleted file mode 100644 index e52db461c7a8bf..00000000000000 --- a/ext/webgpu/compute_pass.rs +++ /dev/null @@ -1,354 +0,0 @@ -// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. - -use deno_core::error::AnyError; -use deno_core::ResourceId; -use deno_core::ZeroCopyBuf; -use deno_core::{OpState, Resource}; -use serde::Deserialize; -use std::borrow::Cow; -use std::cell::RefCell; - -use super::error::WebGpuResult; - -pub(crate) struct WebGpuComputePass( - pub(crate) RefCell, -); -impl Resource for WebGpuComputePass { - fn name(&self) -> Cow { - "webGPUComputePass".into() - } -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct ComputePassSetPipelineArgs { - compute_pass_rid: ResourceId, - pipeline: ResourceId, -} - -pub fn op_webgpu_compute_pass_set_pipeline( - state: &mut OpState, - args: ComputePassSetPipelineArgs, - _: (), -) -> Result { - let compute_pipeline_resource = - state - .resource_table - .get::(args.pipeline)?; - let compute_pass_resource = state - .resource_table - .get::(args.compute_pass_rid)?; - - wgpu_core::command::compute_ffi::wgpu_compute_pass_set_pipeline( - &mut compute_pass_resource.0.borrow_mut(), - compute_pipeline_resource.0, - ); - - Ok(WebGpuResult::empty()) -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct ComputePassDispatchArgs { - compute_pass_rid: ResourceId, - x: u32, - y: u32, - z: u32, -} - -pub fn op_webgpu_compute_pass_dispatch( - state: &mut OpState, - args: ComputePassDispatchArgs, - _: (), -) -> Result { - let compute_pass_resource = state - .resource_table - .get::(args.compute_pass_rid)?; - - wgpu_core::command::compute_ffi::wgpu_compute_pass_dispatch( - &mut compute_pass_resource.0.borrow_mut(), - args.x, - args.y, - args.z, - ); - - Ok(WebGpuResult::empty()) -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct ComputePassDispatchIndirectArgs { - compute_pass_rid: ResourceId, - indirect_buffer: ResourceId, - indirect_offset: u64, -} - -pub fn op_webgpu_compute_pass_dispatch_indirect( - state: &mut OpState, - args: ComputePassDispatchIndirectArgs, - _: (), -) -> Result { - let buffer_resource = state - .resource_table - .get::(args.indirect_buffer)?; - let compute_pass_resource = state - .resource_table - .get::(args.compute_pass_rid)?; - - wgpu_core::command::compute_ffi::wgpu_compute_pass_dispatch_indirect( - &mut compute_pass_resource.0.borrow_mut(), - buffer_resource.0, - args.indirect_offset, - ); - - Ok(WebGpuResult::empty()) -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct ComputePassBeginPipelineStatisticsQueryArgs { - compute_pass_rid: ResourceId, - query_set: ResourceId, - query_index: u32, -} - -pub fn op_webgpu_compute_pass_begin_pipeline_statistics_query( - state: &mut OpState, - args: ComputePassBeginPipelineStatisticsQueryArgs, - _: (), -) -> Result { - let compute_pass_resource = state - .resource_table - .get::(args.compute_pass_rid)?; - let query_set_resource = state - .resource_table - .get::(args.query_set)?; - - wgpu_core::command::compute_ffi::wgpu_compute_pass_begin_pipeline_statistics_query( - &mut compute_pass_resource.0.borrow_mut(), - query_set_resource.0, - args.query_index, - ); - - Ok(WebGpuResult::empty()) -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct ComputePassEndPipelineStatisticsQueryArgs { - compute_pass_rid: ResourceId, -} - -pub fn op_webgpu_compute_pass_end_pipeline_statistics_query( - state: &mut OpState, - args: ComputePassEndPipelineStatisticsQueryArgs, - _: (), -) -> Result { - let compute_pass_resource = state - .resource_table - .get::(args.compute_pass_rid)?; - - wgpu_core::command::compute_ffi::wgpu_compute_pass_end_pipeline_statistics_query( - &mut compute_pass_resource.0.borrow_mut(), - ); - - Ok(WebGpuResult::empty()) -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct ComputePassWriteTimestampArgs { - compute_pass_rid: ResourceId, - query_set: ResourceId, - query_index: u32, -} - -pub fn op_webgpu_compute_pass_write_timestamp( - state: &mut OpState, - args: ComputePassWriteTimestampArgs, - _: (), -) -> Result { - let compute_pass_resource = state - .resource_table - .get::(args.compute_pass_rid)?; - let query_set_resource = state - .resource_table - .get::(args.query_set)?; - - wgpu_core::command::compute_ffi::wgpu_compute_pass_write_timestamp( - &mut compute_pass_resource.0.borrow_mut(), - query_set_resource.0, - args.query_index, - ); - - Ok(WebGpuResult::empty()) -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct ComputePassEndPassArgs { - command_encoder_rid: ResourceId, - compute_pass_rid: ResourceId, -} - -pub fn op_webgpu_compute_pass_end_pass( - state: &mut OpState, - args: ComputePassEndPassArgs, - _: (), -) -> Result { - let command_encoder_resource = state - .resource_table - .get::( - args.command_encoder_rid, - )?; - let command_encoder = command_encoder_resource.0; - let compute_pass_resource = state - .resource_table - .take::(args.compute_pass_rid)?; - let compute_pass = &compute_pass_resource.0.borrow(); - let instance = state.borrow::(); - - gfx_ok!(command_encoder => instance.command_encoder_run_compute_pass( - command_encoder, - compute_pass - )) -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct ComputePassSetBindGroupArgs { - compute_pass_rid: ResourceId, - index: u32, - bind_group: ResourceId, - dynamic_offsets_data: ZeroCopyBuf, - dynamic_offsets_data_start: usize, - dynamic_offsets_data_length: usize, -} - -pub fn op_webgpu_compute_pass_set_bind_group( - state: &mut OpState, - args: ComputePassSetBindGroupArgs, - _: (), -) -> Result { - let bind_group_resource = - state - .resource_table - .get::(args.bind_group)?; - let compute_pass_resource = state - .resource_table - .get::(args.compute_pass_rid)?; - - // Align the data - assert!(args.dynamic_offsets_data_start % std::mem::size_of::() == 0); - // SAFETY: A u8 to u32 cast is safe because we asserted that the length is a - // multiple of 4. - let (prefix, dynamic_offsets_data, suffix) = - unsafe { args.dynamic_offsets_data.align_to::() }; - assert!(prefix.is_empty()); - assert!(suffix.is_empty()); - - let start = args.dynamic_offsets_data_start; - let len = args.dynamic_offsets_data_length; - - // Assert that length and start are both in bounds - assert!(start <= dynamic_offsets_data.len()); - assert!(len <= dynamic_offsets_data.len() - start); - - let dynamic_offsets_data: &[u32] = &dynamic_offsets_data[start..start + len]; - - // SAFETY: the raw pointer and length are of the same slice, and that slice - // lives longer than the below function invocation. - unsafe { - wgpu_core::command::compute_ffi::wgpu_compute_pass_set_bind_group( - &mut compute_pass_resource.0.borrow_mut(), - args.index, - bind_group_resource.0, - dynamic_offsets_data.as_ptr(), - dynamic_offsets_data.len(), - ); - } - - Ok(WebGpuResult::empty()) -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct ComputePassPushDebugGroupArgs { - compute_pass_rid: ResourceId, - group_label: String, -} - -pub fn op_webgpu_compute_pass_push_debug_group( - state: &mut OpState, - args: ComputePassPushDebugGroupArgs, - _: (), -) -> Result { - let compute_pass_resource = state - .resource_table - .get::(args.compute_pass_rid)?; - - let label = std::ffi::CString::new(args.group_label).unwrap(); - // SAFETY: the string the raw pointer points to lives longer than the below - // function invocation. - unsafe { - wgpu_core::command::compute_ffi::wgpu_compute_pass_push_debug_group( - &mut compute_pass_resource.0.borrow_mut(), - label.as_ptr(), - 0, // wgpu#975 - ); - } - - Ok(WebGpuResult::empty()) -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct ComputePassPopDebugGroupArgs { - compute_pass_rid: ResourceId, -} - -pub fn op_webgpu_compute_pass_pop_debug_group( - state: &mut OpState, - args: ComputePassPopDebugGroupArgs, - _: (), -) -> Result { - let compute_pass_resource = state - .resource_table - .get::(args.compute_pass_rid)?; - - wgpu_core::command::compute_ffi::wgpu_compute_pass_pop_debug_group( - &mut compute_pass_resource.0.borrow_mut(), - ); - - Ok(WebGpuResult::empty()) -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct ComputePassInsertDebugMarkerArgs { - compute_pass_rid: ResourceId, - marker_label: String, -} - -pub fn op_webgpu_compute_pass_insert_debug_marker( - state: &mut OpState, - args: ComputePassInsertDebugMarkerArgs, - _: (), -) -> Result { - let compute_pass_resource = state - .resource_table - .get::(args.compute_pass_rid)?; - - let label = std::ffi::CString::new(args.marker_label).unwrap(); - // SAFETY: the string the raw pointer points to lives longer than the below - // function invocation. - unsafe { - wgpu_core::command::compute_ffi::wgpu_compute_pass_insert_debug_marker( - &mut compute_pass_resource.0.borrow_mut(), - label.as_ptr(), - 0, // wgpu#975 - ); - } - - Ok(WebGpuResult::empty()) -} diff --git a/ext/webgpu/error.rs b/ext/webgpu/error.rs deleted file mode 100644 index 18ffdf1a8225ed..00000000000000 --- a/ext/webgpu/error.rs +++ /dev/null @@ -1,285 +0,0 @@ -// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. -use deno_core::error::AnyError; -use deno_core::ResourceId; -use serde::Serialize; -use std::convert::From; -use std::fmt; -use wgpu_core::binding_model::CreateBindGroupError; -use wgpu_core::binding_model::CreateBindGroupLayoutError; -use wgpu_core::binding_model::CreatePipelineLayoutError; -use wgpu_core::binding_model::GetBindGroupLayoutError; -use wgpu_core::command::CommandEncoderError; -use wgpu_core::command::ComputePassError; -use wgpu_core::command::CopyError; -use wgpu_core::command::CreateRenderBundleError; -use wgpu_core::command::QueryError; -use wgpu_core::command::RenderBundleError; -use wgpu_core::command::RenderPassError; -use wgpu_core::device::queue::QueueSubmitError; -use wgpu_core::device::queue::QueueWriteError; -use wgpu_core::device::DeviceError; -use wgpu_core::pipeline::CreateComputePipelineError; -use wgpu_core::pipeline::CreateRenderPipelineError; -use wgpu_core::pipeline::CreateShaderModuleError; -use wgpu_core::resource::BufferAccessError; -use wgpu_core::resource::CreateBufferError; -use wgpu_core::resource::CreateQuerySetError; -use wgpu_core::resource::CreateSamplerError; -use wgpu_core::resource::CreateTextureError; -use wgpu_core::resource::CreateTextureViewError; - -#[derive(Serialize)] -pub struct WebGpuResult { - pub rid: Option, - pub err: Option, -} - -impl WebGpuResult { - pub fn rid(rid: ResourceId) -> Self { - Self { - rid: Some(rid), - err: None, - } - } - - pub fn rid_err>( - rid: ResourceId, - err: Option, - ) -> Self { - Self { - rid: Some(rid), - err: err.map(|e| e.into()), - } - } - - pub fn maybe_err>(err: Option) -> Self { - Self { - rid: None, - err: err.map(|e| e.into()), - } - } - - pub fn empty() -> Self { - Self { - rid: None, - err: None, - } - } -} - -#[derive(Serialize)] -#[serde(tag = "type", content = "value")] -#[serde(rename_all = "kebab-case")] -pub enum WebGpuError { - Lost, - OutOfMemory, - Validation(String), -} - -impl From for WebGpuError { - fn from(err: CreateBufferError) -> Self { - match err { - CreateBufferError::Device(err) => err.into(), - CreateBufferError::AccessError(err) => err.into(), - err => WebGpuError::Validation(err.to_string()), - } - } -} - -impl From for WebGpuError { - fn from(err: DeviceError) -> Self { - match err { - DeviceError::Lost => WebGpuError::Lost, - DeviceError::OutOfMemory => WebGpuError::OutOfMemory, - DeviceError::Invalid => WebGpuError::Validation(err.to_string()), - } - } -} - -impl From for WebGpuError { - fn from(err: BufferAccessError) -> Self { - match err { - BufferAccessError::Device(err) => err.into(), - err => WebGpuError::Validation(err.to_string()), - } - } -} - -impl From for WebGpuError { - fn from(err: CreateBindGroupLayoutError) -> Self { - match err { - CreateBindGroupLayoutError::Device(err) => err.into(), - err => WebGpuError::Validation(err.to_string()), - } - } -} - -impl From for WebGpuError { - fn from(err: CreatePipelineLayoutError) -> Self { - match err { - CreatePipelineLayoutError::Device(err) => err.into(), - err => WebGpuError::Validation(err.to_string()), - } - } -} - -impl From for WebGpuError { - fn from(err: CreateBindGroupError) -> Self { - match err { - CreateBindGroupError::Device(err) => err.into(), - err => WebGpuError::Validation(err.to_string()), - } - } -} - -impl From for WebGpuError { - fn from(err: RenderBundleError) -> Self { - WebGpuError::Validation(err.to_string()) - } -} - -impl From for WebGpuError { - fn from(err: CreateRenderBundleError) -> Self { - WebGpuError::Validation(err.to_string()) - } -} - -impl From for WebGpuError { - fn from(err: CopyError) -> Self { - WebGpuError::Validation(err.to_string()) - } -} - -impl From for WebGpuError { - fn from(err: CommandEncoderError) -> Self { - WebGpuError::Validation(err.to_string()) - } -} - -impl From for WebGpuError { - fn from(err: QueryError) -> Self { - WebGpuError::Validation(err.to_string()) - } -} - -impl From for WebGpuError { - fn from(err: ComputePassError) -> Self { - WebGpuError::Validation(err.to_string()) - } -} - -impl From for WebGpuError { - fn from(err: CreateComputePipelineError) -> Self { - match err { - CreateComputePipelineError::Device(err) => err.into(), - err => WebGpuError::Validation(err.to_string()), - } - } -} - -impl From for WebGpuError { - fn from(err: GetBindGroupLayoutError) -> Self { - WebGpuError::Validation(err.to_string()) - } -} - -impl From for WebGpuError { - fn from(err: CreateRenderPipelineError) -> Self { - match err { - CreateRenderPipelineError::Device(err) => err.into(), - err => WebGpuError::Validation(err.to_string()), - } - } -} - -impl From for WebGpuError { - fn from(err: RenderPassError) -> Self { - WebGpuError::Validation(err.to_string()) - } -} - -impl From for WebGpuError { - fn from(err: CreateSamplerError) -> Self { - match err { - CreateSamplerError::Device(err) => err.into(), - err => WebGpuError::Validation(err.to_string()), - } - } -} - -impl From for WebGpuError { - fn from(err: CreateShaderModuleError) -> Self { - match err { - CreateShaderModuleError::Device(err) => err.into(), - err => WebGpuError::Validation(err.to_string()), - } - } -} - -impl From for WebGpuError { - fn from(err: CreateTextureError) -> Self { - match err { - CreateTextureError::Device(err) => err.into(), - err => WebGpuError::Validation(err.to_string()), - } - } -} - -impl From for WebGpuError { - fn from(err: CreateTextureViewError) -> Self { - WebGpuError::Validation(err.to_string()) - } -} - -impl From for WebGpuError { - fn from(err: CreateQuerySetError) -> Self { - match err { - CreateQuerySetError::Device(err) => err.into(), - err => WebGpuError::Validation(err.to_string()), - } - } -} - -impl From for WebGpuError { - fn from(err: QueueSubmitError) -> Self { - match err { - QueueSubmitError::Queue(err) => err.into(), - err => WebGpuError::Validation(err.to_string()), - } - } -} - -impl From for WebGpuError { - fn from(err: QueueWriteError) -> Self { - match err { - QueueWriteError::Queue(err) => err.into(), - err => WebGpuError::Validation(err.to_string()), - } - } -} - -#[derive(Debug)] -pub struct DomExceptionOperationError { - pub msg: String, -} - -impl DomExceptionOperationError { - pub fn new(msg: &str) -> Self { - DomExceptionOperationError { - msg: msg.to_string(), - } - } -} - -impl fmt::Display for DomExceptionOperationError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.pad(&self.msg) - } -} - -impl std::error::Error for DomExceptionOperationError {} - -pub fn get_error_class_name(e: &AnyError) -> Option<&'static str> { - e.downcast_ref::() - .map(|_| "DOMExceptionOperationError") -} diff --git a/ext/webgpu/lib.deno_webgpu.d.ts b/ext/webgpu/lib.deno_webgpu.d.ts deleted file mode 100644 index 001b3c1f003a19..00000000000000 --- a/ext/webgpu/lib.deno_webgpu.d.ts +++ /dev/null @@ -1,1132 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. - -// deno-lint-ignore-file no-explicit-any no-empty-interface - -/// -/// - -// 8cc98b6f10b7f354473a08c3773bb1de839845b9 - -interface GPUObjectBase { - label: string | null; -} - -declare interface GPUObjectDescriptorBase { - label?: string; -} - -declare class GPUSupportedLimits { - maxTextureDimension1D?: number; - maxTextureDimension2D?: number; - maxTextureDimension3D?: number; - maxTextureArrayLayers?: number; - maxBindGroups?: number; - maxDynamicUniformBuffersPerPipelineLayout?: number; - maxDynamicStorageBuffersPerPipelineLayout?: number; - maxSampledTexturesPerShaderStage?: number; - maxSamplersPerShaderStage?: number; - maxStorageBuffersPerShaderStage?: number; - maxStorageTexturesPerShaderStage?: number; - maxUniformBuffersPerShaderStage?: number; - maxUniformBufferBindingSize?: number; - maxStorageBufferBindingSize?: number; - minUniformBufferOffsetAlignment?: number; - minStorageBufferOffsetAlignment?: number; - maxVertexBuffers?: number; - maxVertexAttributes?: number; - maxVertexBufferArrayStride?: number; - maxInterStageShaderComponents?: number; - maxComputeWorkgroupStorageSize?: number; - maxComputeInvocationsPerWorkgroup?: number; - maxComputeWorkgroupSizeX?: number; - maxComputeWorkgroupSizeY?: number; - maxComputeWorkgroupSizeZ?: number; - maxComputeWorkgroupsPerDimension?: number; -} - -declare class GPUSupportedFeatures { - forEach( - callbackfn: ( - value: GPUFeatureName, - value2: GPUFeatureName, - set: Set, - ) => void, - thisArg?: any, - ): void; - has(value: GPUFeatureName): boolean; - size: number; - [ - Symbol - .iterator - ](): IterableIterator; - entries(): IterableIterator<[GPUFeatureName, GPUFeatureName]>; - keys(): IterableIterator; - values(): IterableIterator; -} - -declare class GPU { - requestAdapter( - options?: GPURequestAdapterOptions, - ): Promise; -} - -declare interface GPURequestAdapterOptions { - powerPreference?: GPUPowerPreference; - forceFallbackAdapter?: boolean; -} - -declare type GPUPowerPreference = "low-power" | "high-performance"; - -declare class GPUAdapter { - readonly name: string; - readonly features: GPUSupportedFeatures; - readonly limits: GPUSupportedLimits; - readonly isFallbackAdapter: boolean; - - requestDevice(descriptor?: GPUDeviceDescriptor): Promise; -} - -declare interface GPUDeviceDescriptor extends GPUObjectDescriptorBase { - requiredFeatures?: GPUFeatureName[]; - requiredLimits?: Record; -} - -declare type GPUFeatureName = - | "depth-clamping" - | "depth24unorm-stencil8" - | "depth32float-stencil8" - | "pipeline-statistics-query" - | "texture-compression-bc" - | "timestamp-query" - // extended from spec - | "mappable-primary-buffers" - | "sampled-texture-binding-array" - | "sampled-texture-array-dynamic-indexing" - | "sampled-texture-array-non-uniform-indexing" - | "unsized-binding-array" - | "multi-draw-indirect" - | "multi-draw-indirect-count" - | "push-constants" - | "address-mode-clamp-to-border" - | "non-fill-polygon-mode" - | "texture-compression-etc2" - | "texture-compression-astc-ldr" - | "texture-adapter-specific-format-features" - | "shader-float64" - | "vertex-attribute-64bit"; - -declare class GPUDevice extends EventTarget implements GPUObjectBase { - label: string | null; - - readonly lost: Promise; - pushErrorScope(filter: GPUErrorFilter): undefined; - popErrorScope(): Promise; - onuncapturederror: - | ((this: GPUDevice, ev: GPUUncapturedErrorEvent) => any) - | null; - - readonly features: ReadonlyArray; - readonly limits: Record; - readonly queue: GPUQueue; - - destroy(): undefined; - - createBuffer(descriptor: GPUBufferDescriptor): GPUBuffer; - createTexture(descriptor: GPUTextureDescriptor): GPUTexture; - createSampler(descriptor?: GPUSamplerDescriptor): GPUSampler; - - createBindGroupLayout( - descriptor: GPUBindGroupLayoutDescriptor, - ): GPUBindGroupLayout; - createPipelineLayout( - descriptor: GPUPipelineLayoutDescriptor, - ): GPUPipelineLayout; - createBindGroup(descriptor: GPUBindGroupDescriptor): GPUBindGroup; - - createShaderModule(descriptor: GPUShaderModuleDescriptor): GPUShaderModule; - createComputePipeline( - descriptor: GPUComputePipelineDescriptor, - ): GPUComputePipeline; - createRenderPipeline( - descriptor: GPURenderPipelineDescriptor, - ): GPURenderPipeline; - createComputePipelineAsync( - descriptor: GPUComputePipelineDescriptor, - ): Promise; - createRenderPipelineAsync( - descriptor: GPURenderPipelineDescriptor, - ): Promise; - - createCommandEncoder( - descriptor?: GPUCommandEncoderDescriptor, - ): GPUCommandEncoder; - createRenderBundleEncoder( - descriptor: GPURenderBundleEncoderDescriptor, - ): GPURenderBundleEncoder; - - createQuerySet(descriptor: GPUQuerySetDescriptor): GPUQuerySet; -} - -declare class GPUBuffer implements GPUObjectBase { - label: string | null; - - mapAsync( - mode: GPUMapModeFlags, - offset?: number, - size?: number, - ): Promise; - getMappedRange(offset?: number, size?: number): ArrayBuffer; - unmap(): undefined; - - destroy(): undefined; -} - -declare interface GPUBufferDescriptor extends GPUObjectDescriptorBase { - size: number; - usage: GPUBufferUsageFlags; - mappedAtCreation?: boolean; -} - -declare type GPUBufferUsageFlags = number; -declare class GPUBufferUsage { - static MAP_READ: 0x0001; - static MAP_WRITE: 0x0002; - static COPY_SRC: 0x0004; - static COPY_DST: 0x0008; - static INDEX: 0x0010; - static VERTEX: 0x0020; - static UNIFORM: 0x0040; - static STORAGE: 0x0080; - static INDIRECT: 0x0100; - static QUERY_RESOLVE: 0x0200; -} - -declare type GPUMapModeFlags = number; -declare class GPUMapMode { - static READ: 0x0001; - static WRITE: 0x0002; -} - -declare class GPUTexture implements GPUObjectBase { - label: string | null; - - createView(descriptor?: GPUTextureViewDescriptor): GPUTextureView; - destroy(): undefined; -} - -declare interface GPUTextureDescriptor extends GPUObjectDescriptorBase { - size: GPUExtent3D; - mipLevelCount?: number; - sampleCount?: number; - dimension?: GPUTextureDimension; - format: GPUTextureFormat; - usage: GPUTextureUsageFlags; -} - -declare type GPUTextureDimension = "1d" | "2d" | "3d"; - -declare type GPUTextureUsageFlags = number; -declare class GPUTextureUsage { - static COPY_SRC: 0x01; - static COPY_DST: 0x02; - static TEXTURE_BINDING: 0x04; - static STORAGE_BINDING: 0x08; - static RENDER_ATTACHMENT: 0x10; -} - -declare class GPUTextureView implements GPUObjectBase { - label: string | null; -} - -declare interface GPUTextureViewDescriptor extends GPUObjectDescriptorBase { - format?: GPUTextureFormat; - dimension?: GPUTextureViewDimension; - aspect?: GPUTextureAspect; - baseMipLevel?: number; - mipLevelCount?: number; - baseArrayLayer?: number; - arrayLayerCount?: number; -} - -declare type GPUTextureViewDimension = - | "1d" - | "2d" - | "2d-array" - | "cube" - | "cube-array" - | "3d"; - -declare type GPUTextureAspect = "all" | "stencil-only" | "depth-only"; - -declare type GPUTextureFormat = - | "r8unorm" - | "r8snorm" - | "r8uint" - | "r8sint" - | "r16uint" - | "r16sint" - | "r16float" - | "rg8unorm" - | "rg8snorm" - | "rg8uint" - | "rg8sint" - | "r32uint" - | "r32sint" - | "r32float" - | "rg16uint" - | "rg16sint" - | "rg16float" - | "rgba8unorm" - | "rgba8unorm-srgb" - | "rgba8snorm" - | "rgba8uint" - | "rgba8sint" - | "bgra8unorm" - | "bgra8unorm-srgb" - | "rgb9e5ufloat" - | "rgb10a2unorm" - | "rg11b10ufloat" - | "rg32uint" - | "rg32sint" - | "rg32float" - | "rgba16uint" - | "rgba16sint" - | "rgba16float" - | "rgba32uint" - | "rgba32sint" - | "rgba32float" - | "stencil8" - | "depth16unorm" - | "depth24plus" - | "depth24plus-stencil8" - | "depth32float" - | "bc1-rgba-unorm" - | "bc1-rgba-unorm-srgb" - | "bc2-rgba-unorm" - | "bc2-rgba-unorm-srgb" - | "bc3-rgba-unorm" - | "bc3-rgba-unorm-srgb" - | "bc4-r-unorm" - | "bc4-r-snorm" - | "bc5-rg-unorm" - | "bc5-rg-snorm" - | "bc6h-rgb-ufloat" - | "bc6h-rgb-float" - | "bc7-rgba-unorm" - | "bc7-rgba-unorm-srgb" - | "depth24unorm-stencil8" - | "depth32float-stencil8"; - -declare class GPUSampler implements GPUObjectBase { - label: string | null; -} - -declare interface GPUSamplerDescriptor extends GPUObjectDescriptorBase { - addressModeU?: GPUAddressMode; - addressModeV?: GPUAddressMode; - addressModeW?: GPUAddressMode; - magFilter?: GPUFilterMode; - minFilter?: GPUFilterMode; - mipmapFilter?: GPUFilterMode; - lodMinClamp?: number; - lodMaxClamp?: number; - compare?: GPUCompareFunction; - maxAnisotropy?: number; -} - -declare type GPUAddressMode = "clamp-to-edge" | "repeat" | "mirror-repeat"; - -declare type GPUFilterMode = "nearest" | "linear"; - -declare type GPUCompareFunction = - | "never" - | "less" - | "equal" - | "less-equal" - | "greater" - | "not-equal" - | "greater-equal" - | "always"; - -declare class GPUBindGroupLayout implements GPUObjectBase { - label: string | null; -} - -declare interface GPUBindGroupLayoutDescriptor extends GPUObjectDescriptorBase { - entries: GPUBindGroupLayoutEntry[]; -} - -declare interface GPUBindGroupLayoutEntry { - binding: number; - visibility: GPUShaderStageFlags; - - buffer?: GPUBufferBindingLayout; - sampler?: GPUSamplerBindingLayout; - texture?: GPUTextureBindingLayout; - storageTexture?: GPUStorageTextureBindingLayout; -} - -declare type GPUShaderStageFlags = number; -declare class GPUShaderStage { - static VERTEX: 0x1; - static FRAGMENT: 0x2; - static COMPUTE: 0x4; -} - -declare interface GPUBufferBindingLayout { - type?: GPUBufferBindingType; - hasDynamicOffset?: boolean; - minBindingSize?: number; -} - -declare type GPUBufferBindingType = "uniform" | "storage" | "read-only-storage"; - -declare interface GPUSamplerBindingLayout { - type?: GPUSamplerBindingType; -} - -declare type GPUSamplerBindingType = - | "filtering" - | "non-filtering" - | "comparison"; - -declare interface GPUTextureBindingLayout { - sampleType?: GPUTextureSampleType; - viewDimension?: GPUTextureViewDimension; - multisampled?: boolean; -} - -declare type GPUTextureSampleType = - | "float" - | "unfilterable-float" - | "depth" - | "sint" - | "uint"; - -declare type GPUStorageTextureAccess = "write-only"; - -declare interface GPUStorageTextureBindingLayout { - access: GPUStorageTextureAccess; - format: GPUTextureFormat; - viewDimension?: GPUTextureViewDimension; -} - -declare class GPUBindGroup implements GPUObjectBase { - label: string | null; -} - -declare interface GPUBindGroupDescriptor extends GPUObjectDescriptorBase { - layout: GPUBindGroupLayout; - entries: GPUBindGroupEntry[]; -} - -declare type GPUBindingResource = - | GPUSampler - | GPUTextureView - | GPUBufferBinding; - -declare interface GPUBindGroupEntry { - binding: number; - resource: GPUBindingResource; -} - -declare interface GPUBufferBinding { - buffer: GPUBuffer; - offset?: number; - size?: number; -} - -declare class GPUPipelineLayout implements GPUObjectBase { - label: string | null; -} - -declare interface GPUPipelineLayoutDescriptor extends GPUObjectDescriptorBase { - bindGroupLayouts: GPUBindGroupLayout[]; -} - -declare type GPUCompilationMessageType = "error" | "warning" | "info"; - -declare interface GPUCompilationMessage { - readonly message: string; - readonly type: GPUCompilationMessageType; - readonly lineNum: number; - readonly linePos: number; -} - -declare interface GPUCompilationInfo { - readonly messages: ReadonlyArray; -} - -declare class GPUShaderModule implements GPUObjectBase { - label: string | null; - - compilationInfo(): Promise; -} - -declare interface GPUShaderModuleDescriptor extends GPUObjectDescriptorBase { - code: string; - sourceMap?: any; -} - -declare interface GPUPipelineDescriptorBase extends GPUObjectDescriptorBase { - layout?: GPUPipelineLayout; -} - -declare interface GPUPipelineBase { - getBindGroupLayout(index: number): GPUBindGroupLayout; -} - -declare interface GPUProgrammableStage { - module: GPUShaderModule; - entryPoint: string; -} - -declare class GPUComputePipeline implements GPUObjectBase, GPUPipelineBase { - label: string | null; - - getBindGroupLayout(index: number): GPUBindGroupLayout; -} - -declare interface GPUComputePipelineDescriptor - extends GPUPipelineDescriptorBase { - compute: GPUProgrammableStage; -} - -declare class GPURenderPipeline implements GPUObjectBase, GPUPipelineBase { - label: string | null; - - getBindGroupLayout(index: number): GPUBindGroupLayout; -} - -declare interface GPURenderPipelineDescriptor - extends GPUPipelineDescriptorBase { - vertex: GPUVertexState; - primitive?: GPUPrimitiveState; - depthStencil?: GPUDepthStencilState; - multisample?: GPUMultisampleState; - fragment?: GPUFragmentState; -} - -declare type GPUPrimitiveTopology = - | "point-list" - | "line-list" - | "line-strip" - | "triangle-list" - | "triangle-strip"; - -declare interface GPUPrimitiveState { - topology?: GPUPrimitiveTopology; - stripIndexFormat?: GPUIndexFormat; - frontFace?: GPUFrontFace; - cullMode?: GPUCullMode; - clampDepth?: boolean; -} - -declare type GPUFrontFace = "ccw" | "cw"; - -declare type GPUCullMode = "none" | "front" | "back"; - -declare interface GPUMultisampleState { - count?: number; - mask?: number; - alphaToCoverageEnabled?: boolean; -} - -declare interface GPUFragmentState extends GPUProgrammableStage { - targets: GPUColorTargetState[]; -} - -declare interface GPUColorTargetState { - format: GPUTextureFormat; - - blend?: GPUBlendState; - writeMask?: GPUColorWriteFlags; -} - -declare interface GPUBlendState { - color: GPUBlendComponent; - alpha: GPUBlendComponent; -} - -declare type GPUColorWriteFlags = number; -declare class GPUColorWrite { - static RED: 0x1; - static GREEN: 0x2; - static BLUE: 0x4; - static ALPHA: 0x8; - static ALL: 0xF; -} - -declare interface GPUBlendComponent { - srcFactor: GPUBlendFactor; - dstFactor: GPUBlendFactor; - operation: GPUBlendOperation; -} - -declare type GPUBlendFactor = - | "zero" - | "one" - | "src" - | "one-minus-src" - | "src-alpha" - | "one-minus-src-alpha" - | "dst" - | "one-minus-dst" - | "dst-alpha" - | "one-minus-dst-alpha" - | "src-alpha-saturated" - | "constant" - | "one-minus-constant"; - -declare type GPUBlendOperation = - | "add" - | "subtract" - | "reverse-subtract" - | "min" - | "max"; - -declare interface GPUDepthStencilState { - format: GPUTextureFormat; - - depthWriteEnabled?: boolean; - depthCompare?: GPUCompareFunction; - - stencilFront?: GPUStencilFaceState; - stencilBack?: GPUStencilFaceState; - - stencilReadMask?: number; - stencilWriteMask?: number; - - depthBias?: number; - depthBiasSlopeScale?: number; - depthBiasClamp?: number; -} - -declare interface GPUStencilFaceState { - compare?: GPUCompareFunction; - failOp?: GPUStencilOperation; - depthFailOp?: GPUStencilOperation; - passOp?: GPUStencilOperation; -} - -declare type GPUStencilOperation = - | "keep" - | "zero" - | "replace" - | "invert" - | "increment-clamp" - | "decrement-clamp" - | "increment-wrap" - | "decrement-wrap"; - -declare type GPUIndexFormat = "uint16" | "uint32"; - -declare type GPUVertexFormat = - | "uint8x2" - | "uint8x4" - | "sint8x2" - | "sint8x4" - | "unorm8x2" - | "unorm8x4" - | "snorm8x2" - | "snorm8x4" - | "uint16x2" - | "uint16x4" - | "sint16x2" - | "sint16x4" - | "unorm16x2" - | "unorm16x4" - | "snorm16x2" - | "snorm16x4" - | "float16x2" - | "float16x4" - | "float32" - | "float32x2" - | "float32x3" - | "float32x4" - | "uint32" - | "uint32x2" - | "uint32x3" - | "uint32x4" - | "sint32" - | "sint32x2" - | "sint32x3" - | "sint32x4"; -declare type GPUVertexStepMode = "vertex" | "instance"; - -declare interface GPUVertexState extends GPUProgrammableStage { - buffers?: (GPUVertexBufferLayout | null)[]; -} - -declare interface GPUVertexBufferLayout { - arrayStride: number; - stepMode?: GPUVertexStepMode; - attributes: GPUVertexAttribute[]; -} - -declare interface GPUVertexAttribute { - format: GPUVertexFormat; - offset: number; - - shaderLocation: number; -} - -declare class GPUCommandBuffer implements GPUObjectBase { - label: string | null; - - readonly executionTime: Promise; -} - -declare interface GPUCommandBufferDescriptor extends GPUObjectDescriptorBase {} - -declare class GPUCommandEncoder implements GPUObjectBase { - label: string | null; - - beginRenderPass(descriptor: GPURenderPassDescriptor): GPURenderPassEncoder; - beginComputePass( - descriptor?: GPUComputePassDescriptor, - ): GPUComputePassEncoder; - - copyBufferToBuffer( - source: GPUBuffer, - sourceOffset: number, - destination: GPUBuffer, - destinationOffset: number, - size: number, - ): undefined; - - copyBufferToTexture( - source: GPUImageCopyBuffer, - destination: GPUImageCopyTexture, - copySize: GPUExtent3D, - ): undefined; - - copyTextureToBuffer( - source: GPUImageCopyTexture, - destination: GPUImageCopyBuffer, - copySize: GPUExtent3D, - ): undefined; - - copyTextureToTexture( - source: GPUImageCopyTexture, - destination: GPUImageCopyTexture, - copySize: GPUExtent3D, - ): undefined; - - pushDebugGroup(groupLabel: string): undefined; - popDebugGroup(): undefined; - insertDebugMarker(markerLabel: string): undefined; - - writeTimestamp(querySet: GPUQuerySet, queryIndex: number): undefined; - - resolveQuerySet( - querySet: GPUQuerySet, - firstQuery: number, - queryCount: number, - destination: GPUBuffer, - destinationOffset: number, - ): undefined; - - finish(descriptor?: GPUCommandBufferDescriptor): GPUCommandBuffer; -} - -declare interface GPUCommandEncoderDescriptor extends GPUObjectDescriptorBase { - measureExecutionTime?: boolean; -} - -declare interface GPUImageDataLayout { - offset?: number; - bytesPerRow?: number; - rowsPerImage?: number; -} - -declare interface GPUImageCopyBuffer extends GPUImageDataLayout { - buffer: GPUBuffer; -} - -declare interface GPUImageCopyTexture { - texture: GPUTexture; - mipLevel?: number; - origin?: GPUOrigin3D; - aspect?: GPUTextureAspect; -} - -interface GPUProgrammablePassEncoder { - setBindGroup( - index: number, - bindGroup: GPUBindGroup, - dynamicOffsets?: number[], - ): undefined; - - setBindGroup( - index: number, - bindGroup: GPUBindGroup, - dynamicOffsetsData: Uint32Array, - dynamicOffsetsDataStart: number, - dynamicOffsetsDataLength: number, - ): undefined; - - pushDebugGroup(groupLabel: string): undefined; - popDebugGroup(): undefined; - insertDebugMarker(markerLabel: string): undefined; -} - -declare class GPUComputePassEncoder - implements GPUObjectBase, GPUProgrammablePassEncoder { - label: string | null; - setBindGroup( - index: number, - bindGroup: GPUBindGroup, - dynamicOffsets?: number[], - ): undefined; - setBindGroup( - index: number, - bindGroup: GPUBindGroup, - dynamicOffsetsData: Uint32Array, - dynamicOffsetsDataStart: number, - dynamicOffsetsDataLength: number, - ): undefined; - pushDebugGroup(groupLabel: string): undefined; - popDebugGroup(): undefined; - insertDebugMarker(markerLabel: string): undefined; - setPipeline(pipeline: GPUComputePipeline): undefined; - dispatch(x: number, y?: number, z?: number): undefined; - dispatchIndirect( - indirectBuffer: GPUBuffer, - indirectOffset: number, - ): undefined; - - beginPipelineStatisticsQuery( - querySet: GPUQuerySet, - queryIndex: number, - ): undefined; - endPipelineStatisticsQuery(): undefined; - - writeTimestamp(querySet: GPUQuerySet, queryIndex: number): undefined; - - endPass(): undefined; -} - -declare interface GPUComputePassDescriptor extends GPUObjectDescriptorBase {} - -interface GPURenderEncoderBase { - setPipeline(pipeline: GPURenderPipeline): undefined; - - setIndexBuffer( - buffer: GPUBuffer, - indexFormat: GPUIndexFormat, - offset?: number, - size?: number, - ): undefined; - setVertexBuffer( - slot: number, - buffer: GPUBuffer, - offset?: number, - size?: number, - ): undefined; - - draw( - vertexCount: number, - instanceCount?: number, - firstVertex?: number, - firstInstance?: number, - ): undefined; - drawIndexed( - indexCount: number, - instanceCount?: number, - firstIndex?: number, - baseVertex?: number, - firstInstance?: number, - ): undefined; - - drawIndirect(indirectBuffer: GPUBuffer, indirectOffset: number): undefined; - drawIndexedIndirect( - indirectBuffer: GPUBuffer, - indirectOffset: number, - ): undefined; -} - -declare class GPURenderPassEncoder - implements GPUObjectBase, GPUProgrammablePassEncoder, GPURenderEncoderBase { - label: string | null; - setBindGroup( - index: number, - bindGroup: GPUBindGroup, - dynamicOffsets?: number[], - ): undefined; - setBindGroup( - index: number, - bindGroup: GPUBindGroup, - dynamicOffsetsData: Uint32Array, - dynamicOffsetsDataStart: number, - dynamicOffsetsDataLength: number, - ): undefined; - pushDebugGroup(groupLabel: string): undefined; - popDebugGroup(): undefined; - insertDebugMarker(markerLabel: string): undefined; - setPipeline(pipeline: GPURenderPipeline): undefined; - setIndexBuffer( - buffer: GPUBuffer, - indexFormat: GPUIndexFormat, - offset?: number, - size?: number, - ): undefined; - setVertexBuffer( - slot: number, - buffer: GPUBuffer, - offset?: number, - size?: number, - ): undefined; - draw( - vertexCount: number, - instanceCount?: number, - firstVertex?: number, - firstInstance?: number, - ): undefined; - drawIndexed( - indexCount: number, - instanceCount?: number, - firstIndex?: number, - baseVertex?: number, - firstInstance?: number, - ): undefined; - drawIndirect(indirectBuffer: GPUBuffer, indirectOffset: number): undefined; - drawIndexedIndirect( - indirectBuffer: GPUBuffer, - indirectOffset: number, - ): undefined; - - setViewport( - x: number, - y: number, - width: number, - height: number, - minDepth: number, - maxDepth: number, - ): undefined; - - setScissorRect( - x: number, - y: number, - width: number, - height: number, - ): undefined; - - setBlendConstant(color: GPUColor): undefined; - setStencilReference(reference: number): undefined; - - beginOcclusionQuery(queryIndex: number): undefined; - endOcclusionQuery(): undefined; - - beginPipelineStatisticsQuery( - querySet: GPUQuerySet, - queryIndex: number, - ): undefined; - endPipelineStatisticsQuery(): undefined; - - writeTimestamp(querySet: GPUQuerySet, queryIndex: number): undefined; - - executeBundles(bundles: GPURenderBundle[]): undefined; - endPass(): undefined; -} - -declare interface GPURenderPassDescriptor extends GPUObjectDescriptorBase { - colorAttachments: GPURenderPassColorAttachment[]; - depthStencilAttachment?: GPURenderPassDepthStencilAttachment; - occlusionQuerySet?: GPUQuerySet; -} - -declare interface GPURenderPassColorAttachment { - view: GPUTextureView; - resolveTarget?: GPUTextureView; - - loadValue: GPULoadOp | GPUColor; - storeOp?: GPUStoreOp; -} - -declare interface GPURenderPassDepthStencilAttachment { - view: GPUTextureView; - - depthLoadValue: GPULoadOp | number; - depthStoreOp: GPUStoreOp; - depthReadOnly?: boolean; - - stencilLoadValue: GPULoadOp | number; - stencilStoreOp: GPUStoreOp; - stencilReadOnly?: boolean; -} - -declare type GPULoadOp = "load"; - -declare type GPUStoreOp = "store" | "discard"; - -declare class GPURenderBundle implements GPUObjectBase { - label: string | null; -} - -declare interface GPURenderBundleDescriptor extends GPUObjectDescriptorBase {} - -declare class GPURenderBundleEncoder - implements GPUObjectBase, GPUProgrammablePassEncoder, GPURenderEncoderBase { - label: string | null; - draw( - vertexCount: number, - instanceCount?: number, - firstVertex?: number, - firstInstance?: number, - ): undefined; - drawIndexed( - indexCount: number, - instanceCount?: number, - firstIndex?: number, - baseVertex?: number, - firstInstance?: number, - ): undefined; - drawIndexedIndirect( - indirectBuffer: GPUBuffer, - indirectOffset: number, - ): undefined; - drawIndirect(indirectBuffer: GPUBuffer, indirectOffset: number): undefined; - insertDebugMarker(markerLabel: string): undefined; - popDebugGroup(): undefined; - pushDebugGroup(groupLabel: string): undefined; - setBindGroup( - index: number, - bindGroup: GPUBindGroup, - dynamicOffsets?: number[], - ): undefined; - setBindGroup( - index: number, - bindGroup: GPUBindGroup, - dynamicOffsetsData: Uint32Array, - dynamicOffsetsDataStart: number, - dynamicOffsetsDataLength: number, - ): undefined; - setIndexBuffer( - buffer: GPUBuffer, - indexFormat: GPUIndexFormat, - offset?: number, - size?: number, - ): undefined; - setPipeline(pipeline: GPURenderPipeline): undefined; - setVertexBuffer( - slot: number, - buffer: GPUBuffer, - offset?: number, - size?: number, - ): undefined; - - finish(descriptor?: GPURenderBundleDescriptor): GPURenderBundle; -} - -declare interface GPURenderPassLayout extends GPUObjectDescriptorBase { - colorFormats: GPUTextureFormat[]; - depthStencilFormat?: GPUTextureFormat; - sampleCount?: number; -} - -declare interface GPURenderBundleEncoderDescriptor extends GPURenderPassLayout { - depthReadOnly?: boolean; - stencilReadOnly?: boolean; -} - -declare class GPUQueue implements GPUObjectBase { - label: string | null; - - submit(commandBuffers: GPUCommandBuffer[]): undefined; - - onSubmittedWorkDone(): Promise; - - writeBuffer( - buffer: GPUBuffer, - bufferOffset: number, - data: BufferSource, - dataOffset?: number, - size?: number, - ): undefined; - - writeTexture( - destination: GPUImageCopyTexture, - data: BufferSource, - dataLayout: GPUImageDataLayout, - size: GPUExtent3D, - ): undefined; -} - -declare class GPUQuerySet implements GPUObjectBase { - label: string | null; - - destroy(): undefined; -} - -declare interface GPUQuerySetDescriptor extends GPUObjectDescriptorBase { - type: GPUQueryType; - count: number; - pipelineStatistics?: GPUPipelineStatisticName[]; -} - -declare type GPUQueryType = "occlusion" | "pipeline-statistics" | "timestamp"; - -declare type GPUPipelineStatisticName = - | "vertex-shader-invocations" - | "clipper-invocations" - | "clipper-primitives-out" - | "fragment-shader-invocations" - | "compute-shader-invocations"; - -declare type GPUDeviceLostReason = "destroyed"; - -declare interface GPUDeviceLostInfo { - readonly reason: GPUDeviceLostReason | undefined; - readonly message: string; -} - -declare type GPUErrorFilter = "out-of-memory" | "validation"; - -declare class GPUOutOfMemoryError { - constructor(); -} - -declare class GPUValidationError { - constructor(message: string); - readonly message: string; -} - -declare type GPUError = GPUOutOfMemoryError | GPUValidationError; - -declare class GPUUncapturedErrorEvent extends Event { - constructor( - type: string, - gpuUncapturedErrorEventInitDict: GPUUncapturedErrorEventInit, - ); - readonly error: GPUError; -} - -declare interface GPUUncapturedErrorEventInit extends EventInit { - error?: GPUError; -} - -declare interface GPUColorDict { - r: number; - g: number; - b: number; - a: number; -} - -declare type GPUColor = number[] | GPUColorDict; - -declare interface GPUOrigin3DDict { - x?: number; - y?: number; - z?: number; -} - -declare type GPUOrigin3D = number[] | GPUOrigin3DDict; - -declare interface GPUExtent3DDict { - width: number; - height?: number; - depthOrArrayLayers?: number; -} - -declare type GPUExtent3D = number[] | GPUExtent3DDict; diff --git a/ext/webgpu/lib.rs b/ext/webgpu/lib.rs deleted file mode 100644 index 81f84f6bf934ee..00000000000000 --- a/ext/webgpu/lib.rs +++ /dev/null @@ -1,986 +0,0 @@ -// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. - -use deno_core::error::AnyError; -use deno_core::include_js_files; -use deno_core::op_async; -use deno_core::op_sync; -use deno_core::Extension; -use deno_core::OpFn; -use deno_core::OpState; -use deno_core::Resource; -use deno_core::ResourceId; -use serde::Deserialize; -use serde::Serialize; -use std::borrow::Cow; -use std::cell::RefCell; -use std::collections::HashSet; -use std::path::PathBuf; -use std::rc::Rc; -pub use wgpu_core; -pub use wgpu_types; -use wgpu_types::PowerPreference; - -use error::DomExceptionOperationError; -use error::WebGpuResult; - -#[macro_use] -mod macros { - macro_rules! gfx_select { - ($id:expr => $global:ident.$method:ident( $($param:expr),* )) => { - match $id.backend() { - #[cfg(not(target_os = "macos"))] - wgpu_types::Backend::Vulkan => $global.$method::( $($param),* ), - #[cfg(target_os = "macos")] - wgpu_types::Backend::Metal => $global.$method::( $($param),* ), - #[cfg(windows)] - wgpu_types::Backend::Dx12 => $global.$method::( $($param),* ), - #[cfg(all(unix, not(target_os = "macos")))] - wgpu_types::Backend::Gl => $global.$method::( $($param),+ ), - other => panic!("Unexpected backend {:?}", other), - } - }; - } - - macro_rules! gfx_put { - ($id:expr => $global:ident.$method:ident( $($param:expr),* ) => $state:expr, $rc:expr) => {{ - let (val, maybe_err) = gfx_select!($id => $global.$method($($param),*)); - let rid = $state.resource_table.add($rc(val)); - Ok(WebGpuResult::rid_err(rid, maybe_err)) - }}; - } - - macro_rules! gfx_ok { - ($id:expr => $global:ident.$method:ident( $($param:expr),* )) => {{ - let maybe_err = gfx_select!($id => $global.$method($($param),*)).err(); - Ok(WebGpuResult::maybe_err(maybe_err)) - }}; - } -} - -pub mod binding; -pub mod buffer; -pub mod bundle; -pub mod command_encoder; -pub mod compute_pass; -pub mod error; -pub mod pipeline; -pub mod queue; -pub mod render_pass; -pub mod sampler; -pub mod shader; -pub mod texture; - -pub struct Unstable(pub bool); - -fn check_unstable(state: &OpState, api_name: &str) { - let unstable = state.borrow::(); - if !unstable.0 { - eprintln!( - "Unstable API '{}'. The --unstable flag must be provided.", - api_name - ); - std::process::exit(70); - } -} - -type Instance = wgpu_core::hub::Global; - -struct WebGpuAdapter(wgpu_core::id::AdapterId); -impl Resource for WebGpuAdapter { - fn name(&self) -> Cow { - "webGPUAdapter".into() - } -} - -struct WebGpuDevice(wgpu_core::id::DeviceId); -impl Resource for WebGpuDevice { - fn name(&self) -> Cow { - "webGPUDevice".into() - } -} - -struct WebGpuQuerySet(wgpu_core::id::QuerySetId); -impl Resource for WebGpuQuerySet { - fn name(&self) -> Cow { - "webGPUQuerySet".into() - } -} - -pub fn init(unstable: bool) -> Extension { - Extension::builder() - .js(include_js_files!( - prefix "deno:ext/webgpu", - "01_webgpu.js", - "02_idl_types.js", - )) - .ops(declare_webgpu_ops()) - .state(move |state| { - // TODO: check & possibly streamline this - // Unstable might be able to be OpMiddleware - // let unstable_checker = state.borrow::(); - // let unstable = unstable_checker.unstable; - state.put(Unstable(unstable)); - Ok(()) - }) - .build() -} - -pub fn get_declaration() -> PathBuf { - PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("lib.deno_webgpu.d.ts") -} - -fn deserialize_features(features: &wgpu_types::Features) -> Vec<&'static str> { - let mut return_features: Vec<&'static str> = vec![]; - - if features.contains(wgpu_types::Features::DEPTH_CLAMPING) { - return_features.push("depth-clamping"); - } - if features.contains(wgpu_types::Features::PIPELINE_STATISTICS_QUERY) { - return_features.push("pipeline-statistics-query"); - } - if features.contains(wgpu_types::Features::TEXTURE_COMPRESSION_BC) { - return_features.push("texture-compression-bc"); - } - if features.contains(wgpu_types::Features::TIMESTAMP_QUERY) { - return_features.push("timestamp-query"); - } - - // extended from spec - if features.contains(wgpu_types::Features::MAPPABLE_PRIMARY_BUFFERS) { - return_features.push("mappable-primary-buffers"); - } - if features.contains(wgpu_types::Features::TEXTURE_BINDING_ARRAY) { - return_features.push("texture-binding-array"); - } - if features.contains(wgpu_types::Features::BUFFER_BINDING_ARRAY) { - return_features.push("buffer-binding-array"); - } - if features.contains(wgpu_types::Features::STORAGE_RESOURCE_BINDING_ARRAY) { - return_features.push("storage-resource-binding-array"); - } - if features.contains(wgpu_types::Features::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING) { - return_features.push("sampled-texture-and-storage-buffer-array-non-uniform-indexing"); - } - if features.contains(wgpu_types::Features::UNIFORM_BUFFER_AND_STORAGE_TEXTURE_ARRAY_NON_UNIFORM_INDEXING) { - return_features.push("uniform-buffer-and-storage-buffer-texture-non-uniform-indexing"); - } - if features.contains(wgpu_types::Features::UNSIZED_BINDING_ARRAY) { - return_features.push("unsized-binding-array"); - } - if features.contains(wgpu_types::Features::MULTI_DRAW_INDIRECT) { - return_features.push("multi-draw-indirect"); - } - if features.contains(wgpu_types::Features::MULTI_DRAW_INDIRECT_COUNT) { - return_features.push("multi-draw-indirect-count"); - } - if features.contains(wgpu_types::Features::PUSH_CONSTANTS) { - return_features.push("push-constants"); - } - if features.contains(wgpu_types::Features::ADDRESS_MODE_CLAMP_TO_BORDER) { - return_features.push("address-mode-clamp-to-border"); - } - if features.contains(wgpu_types::Features::NON_FILL_POLYGON_MODE) { - return_features.push("non-fill-polygon-mode"); - } - if features.contains(wgpu_types::Features::TEXTURE_COMPRESSION_ETC2) { - return_features.push("texture-compression-etc2"); - } - if features.contains(wgpu_types::Features::TEXTURE_COMPRESSION_ASTC_LDR) { - return_features.push("texture-compression-astc-ldr"); - } - if features - .contains(wgpu_types::Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES) - { - return_features.push("texture-adapter-specific-format-features"); - } - if features.contains(wgpu_types::Features::SHADER_FLOAT64) { - return_features.push("shader-float64"); - } - if features.contains(wgpu_types::Features::VERTEX_ATTRIBUTE_64BIT) { - return_features.push("vertex-attribute-64bit"); - } - if features.contains(wgpu_types::Features::CONSERVATIVE_RASTERIZATION) { - return_features.push("conservative-rasterization"); - } - if features.contains(wgpu_types::Features::VERTEX_WRITABLE_STORAGE) { - return_features.push("vertex-writable-storage"); - } - if features.contains(wgpu_types::Features::CLEAR_COMMANDS) { - return_features.push("clear-commands"); - } - if features.contains(wgpu_types::Features::SPIRV_SHADER_PASSTHROUGH) { - return_features.push("spirv-shader-passthrough"); - } - if features.contains(wgpu_types::Features::SHADER_PRIMITIVE_INDEX) { - return_features.push("shader-primitive-index"); - } - - return_features -} - -#[derive(Deserialize)] -#[serde(rename_all = "kebab-case")] -enum GpuPowerPreference { - LowPower, - HighPerformance, -} - -impl From for wgpu_types::PowerPreference { - fn from(value: GpuPowerPreference) -> wgpu_types::PowerPreference { - match value { - GpuPowerPreference::LowPower => wgpu_types::PowerPreference::LowPower, - GpuPowerPreference::HighPerformance => { - wgpu_types::PowerPreference::HighPerformance - } - } - } -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct RequestAdapterArgs { - power_preference: Option, -} - -#[derive(Serialize)] -#[serde(untagged)] -pub enum GpuAdapterDeviceOrErr { - Error { err: String }, - Features(GpuAdapterDevice), -} - -#[derive(Serialize)] -#[serde(rename_all = "camelCase")] -pub struct GpuAdapterDevice { - rid: ResourceId, - name: Option, - limits: wgpu_types::Limits, - features: Vec<&'static str>, - is_software: bool, -} - -pub async fn op_webgpu_request_adapter( - state: Rc>, - args: RequestAdapterArgs, - _: (), -) -> Result { - let mut state = state.borrow_mut(); - check_unstable(&state, "navigator.gpu.requestAdapter"); - let instance = if let Some(instance) = state.try_borrow::() { - instance - } else { - state.put(wgpu_core::hub::Global::new( - "webgpu", - wgpu_core::hub::IdentityManagerFactory, - wgpu_types::Backends::PRIMARY, - )); - state.borrow::() - }; - - let descriptor = wgpu_core::instance::RequestAdapterOptions { - power_preference: match args.power_preference { - Some(power_preference) => power_preference.into(), - None => PowerPreference::default(), - }, - // TODO(lucacasonato): respect forceFallbackAdapter - compatible_surface: None, // windowless - }; - let res = instance.request_adapter( - &descriptor, - wgpu_core::instance::AdapterInputs::Mask( - wgpu_types::Backends::PRIMARY, - |_| std::marker::PhantomData, - ), - ); - - let adapter = match res { - Ok(adapter) => adapter, - Err(err) => { - return Ok(GpuAdapterDeviceOrErr::Error { - err: err.to_string(), - }) - } - }; - let name = gfx_select!(adapter => instance.adapter_get_info(adapter))?.name; - let adapter_features = - gfx_select!(adapter => instance.adapter_features(adapter))?; - let features = deserialize_features(&adapter_features); - let adapter_limits = - gfx_select!(adapter => instance.adapter_limits(adapter))?; - - let rid = state.resource_table.add(WebGpuAdapter(adapter)); - - Ok(GpuAdapterDeviceOrErr::Features(GpuAdapterDevice { - rid, - name: Some(name), - features, - limits: adapter_limits, - is_software: false, - })) -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -struct GpuLimits { - max_texture_dimension_1d: Option, - max_texture_dimension_2d: Option, - max_texture_dimension_3d: Option, - max_texture_array_layers: Option, - max_bind_groups: Option, - max_dynamic_uniform_buffers_per_pipeline_layout: Option, - max_dynamic_storage_buffers_per_pipeline_layout: Option, - max_sampled_textures_per_shader_stage: Option, - max_samplers_per_shader_stage: Option, - max_storage_buffers_per_shader_stage: Option, - max_storage_textures_per_shader_stage: Option, - max_uniform_buffers_per_shader_stage: Option, - max_uniform_buffer_binding_size: Option, // TODO(@crowlkats): u64 - max_storage_buffer_binding_size: Option, // TODO(@crowlkats): u64 - // min_uniform_buffer_offset_alignment: Option, - // min_storage_buffer_offset_alignment: Option, - max_vertex_buffers: Option, - max_vertex_attributes: Option, - max_vertex_buffer_array_stride: Option, - // max_inter_stage_shader_components: Option, - // max_compute_workgroup_storage_size: Option, - // max_compute_invocations_per_workgroup: Option, - // max_compute_workgroup_size_x: Option, - // max_compute_workgroup_size_y: Option, - // max_compute_workgroup_size_z: Option, - // max_compute_workgroups_per_dimension: Option, -} - -impl From for wgpu_types::Limits { - fn from(limits: GpuLimits) -> wgpu_types::Limits { - wgpu_types::Limits { - max_texture_dimension_1d: limits.max_texture_dimension_1d.unwrap_or(8192), - max_texture_dimension_2d: limits.max_texture_dimension_2d.unwrap_or(8192), - max_texture_dimension_3d: limits.max_texture_dimension_3d.unwrap_or(2048), - max_texture_array_layers: limits.max_texture_array_layers.unwrap_or(2048), - max_bind_groups: limits.max_bind_groups.unwrap_or(4), - max_dynamic_uniform_buffers_per_pipeline_layout: limits - .max_dynamic_uniform_buffers_per_pipeline_layout - .unwrap_or(8), - max_dynamic_storage_buffers_per_pipeline_layout: limits - .max_dynamic_storage_buffers_per_pipeline_layout - .unwrap_or(4), - max_sampled_textures_per_shader_stage: limits - .max_sampled_textures_per_shader_stage - .unwrap_or(16), - max_samplers_per_shader_stage: limits - .max_samplers_per_shader_stage - .unwrap_or(16), - max_storage_buffers_per_shader_stage: limits - .max_storage_buffers_per_shader_stage - .unwrap_or(4), - max_storage_textures_per_shader_stage: limits - .max_storage_textures_per_shader_stage - .unwrap_or(4), - max_uniform_buffers_per_shader_stage: limits - .max_uniform_buffers_per_shader_stage - .unwrap_or(12), - max_uniform_buffer_binding_size: limits - .max_uniform_buffer_binding_size - .unwrap_or(16384), - max_storage_buffer_binding_size: limits - .max_storage_buffer_binding_size - .unwrap_or(134217728), - // min_uniform_buffer_offset_alignment: limits - // .min_uniform_buffer_offset_alignment - // .unwrap_or(default), - // min_storage_buffer_offset_alignment: limits - // .min_storage_buffer_offset_alignment - // .unwrap_or(default), - max_vertex_buffers: limits.max_vertex_buffers.unwrap_or(8), - max_vertex_attributes: limits.max_vertex_attributes.unwrap_or(16), - max_vertex_buffer_array_stride: limits - .max_vertex_buffer_array_stride - .unwrap_or(2048), - // max_inter_stage_shader_components: limits - // .max_inter_stage_shader_components - // .unwrap_or(default), - // max_compute_workgroup_storage_size: limits - // .max_compute_workgroup_storage_size - // .unwrap_or(default), - // max_compute_invocations_per_workgroup: limits - // .max_compute_invocations_per_workgroup - // .unwrap_or(default), - // max_compute_workgroup_size_x: limits - // .max_compute_workgroup_size_x - // .unwrap_or(default), - // max_compute_workgroup_size_y: limits - // .max_compute_workgroup_size_y - // .unwrap_or(default), - // max_compute_workgroup_size_z: limits - // .max_compute_workgroup_size_z - // .unwrap_or(default), - // max_compute_workgroups_per_dimension: limits - // .max_compute_workgroups_per_dimension - // .unwrap_or(default), - max_push_constant_size: 0, - } - } -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct RequestDeviceArgs { - adapter_rid: ResourceId, - label: Option, - required_features: Option, - required_limits: Option, -} - -#[derive(Deserialize)] -pub struct GpuRequiredFeatures(HashSet); - -impl From for wgpu_types::Features { - fn from(required_features: GpuRequiredFeatures) -> wgpu_types::Features { - let mut features: wgpu_types::Features = wgpu_types::Features::empty(); - - if required_features.0.contains("depth-clamping") { - features.set(wgpu_types::Features::DEPTH_CLAMPING, true); - } - if required_features.0.contains("pipeline-statistics-query") { - features.set(wgpu_types::Features::PIPELINE_STATISTICS_QUERY, true); - } - if required_features.0.contains("texture-compression-bc") { - features.set(wgpu_types::Features::TEXTURE_COMPRESSION_BC, true); - } - if required_features.0.contains("timestamp-query") { - features.set(wgpu_types::Features::TIMESTAMP_QUERY, true); - } - - // extended from spec - if required_features.0.contains("mappable-primary-buffers") { - features.set(wgpu_types::Features::MAPPABLE_PRIMARY_BUFFERS, true); - } - if required_features.0.contains("texture-binding-array") { - features.set(wgpu_types::Features::TEXTURE_BINDING_ARRAY, true); - } - if required_features.0.contains("buffer-binding-array") { - features.set(wgpu_types::Features::BUFFER_BINDING_ARRAY, true); - } - if required_features - .0 - .contains("storage-resource-binding-array") - { - features.set(wgpu_types::Features::STORAGE_RESOURCE_BINDING_ARRAY, true); - } - if required_features - .0 - .contains("sampled-texture-and-storage-buffer-array-non-uniform-indexing") - { - features.set(wgpu_types::Features::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING, true); - } - if required_features.0.contains( - "uniform-buffer-and-storage-buffer-texture-non-uniform-indexing", - ) { - features.set(wgpu_types::Features::UNIFORM_BUFFER_AND_STORAGE_TEXTURE_ARRAY_NON_UNIFORM_INDEXING, true); - } - if required_features.0.contains("unsized-binding-array") { - features.set(wgpu_types::Features::UNSIZED_BINDING_ARRAY, true); - } - if required_features.0.contains("multi-draw-indirect") { - features.set(wgpu_types::Features::MULTI_DRAW_INDIRECT, true); - } - if required_features.0.contains("multi-draw-indirect-count") { - features.set(wgpu_types::Features::MULTI_DRAW_INDIRECT_COUNT, true); - } - if required_features.0.contains("push-constants") { - features.set(wgpu_types::Features::PUSH_CONSTANTS, true); - } - if required_features.0.contains("address-mode-clamp-to-border") { - features.set(wgpu_types::Features::ADDRESS_MODE_CLAMP_TO_BORDER, true); - } - if required_features.0.contains("non-fill-polygon-mode") { - features.set(wgpu_types::Features::NON_FILL_POLYGON_MODE, true); - } - if required_features.0.contains("texture-compression-etc2") { - features.set(wgpu_types::Features::TEXTURE_COMPRESSION_ETC2, true); - } - if required_features.0.contains("texture-compression-astc-ldr") { - features.set(wgpu_types::Features::TEXTURE_COMPRESSION_ASTC_LDR, true); - } - if required_features - .0 - .contains("texture-adapter-specific-format-features") - { - features.set( - wgpu_types::Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES, - true, - ); - } - if required_features.0.contains("shader-float64") { - features.set(wgpu_types::Features::SHADER_FLOAT64, true); - } - if required_features.0.contains("vertex-attribute-64bit") { - features.set(wgpu_types::Features::VERTEX_ATTRIBUTE_64BIT, true); - } - if required_features.0.contains("conservative-rasterization") { - features.set(wgpu_types::Features::CONSERVATIVE_RASTERIZATION, true); - } - if required_features.0.contains("vertex-writable-storage") { - features.set(wgpu_types::Features::VERTEX_WRITABLE_STORAGE, true); - } - if required_features.0.contains("clear-commands") { - features.set(wgpu_types::Features::CLEAR_COMMANDS, true); - } - if required_features.0.contains("spirv-shader-passthrough") { - features.set(wgpu_types::Features::SPIRV_SHADER_PASSTHROUGH, true); - } - if required_features.0.contains("shader-primitive-index") { - features.set(wgpu_types::Features::SHADER_PRIMITIVE_INDEX, true); - } - - features - } -} - -pub async fn op_webgpu_request_device( - state: Rc>, - args: RequestDeviceArgs, - _: (), -) -> Result { - let mut state = state.borrow_mut(); - let adapter_resource = state - .resource_table - .get::(args.adapter_rid)?; - let adapter = adapter_resource.0; - let instance = state.borrow::(); - - let descriptor = wgpu_types::DeviceDescriptor { - label: args.label.map(Cow::from), - features: args.required_features.map(Into::into).unwrap_or_default(), - limits: args.required_limits.map(Into::into).unwrap_or_default(), - }; - - let (device, maybe_err) = gfx_select!(adapter => instance.adapter_request_device( - adapter, - &descriptor, - std::env::var("DENO_WEBGPU_TRACE").ok().as_ref().map(std::path::Path::new), - std::marker::PhantomData - )); - if let Some(err) = maybe_err { - return Err(DomExceptionOperationError::new(&err.to_string()).into()); - } - - let device_features = - gfx_select!(device => instance.device_features(device))?; - let features = deserialize_features(&device_features); - let limits = gfx_select!(device => instance.device_limits(device))?; - - let rid = state.resource_table.add(WebGpuDevice(device)); - - Ok(GpuAdapterDevice { - rid, - name: None, - features, - limits, - // TODO(lucacasonato): report correctly from wgpu - is_software: false, - }) -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct CreateQuerySetArgs { - device_rid: ResourceId, - label: Option, - #[serde(flatten)] - r#type: GpuQueryType, - count: u32, -} - -#[derive(Deserialize)] -#[serde(rename_all = "kebab-case", tag = "type")] -enum GpuQueryType { - Occlusion, - #[serde(rename_all = "camelCase")] - PipelineStatistics { - pipeline_statistics: HashSet, - }, - Timestamp, -} - -impl From for wgpu_types::QueryType { - fn from(query_type: GpuQueryType) -> Self { - match query_type { - GpuQueryType::Occlusion => wgpu_types::QueryType::Occlusion, - GpuQueryType::PipelineStatistics { - pipeline_statistics, - } => { - use wgpu_types::PipelineStatisticsTypes; - - let mut types = PipelineStatisticsTypes::empty(); - - if pipeline_statistics.contains("vertex-shader-invocations") { - types.set(PipelineStatisticsTypes::VERTEX_SHADER_INVOCATIONS, true); - } - if pipeline_statistics.contains("clipper-invocations") { - types.set(PipelineStatisticsTypes::CLIPPER_INVOCATIONS, true); - } - if pipeline_statistics.contains("clipper-primitives-out") { - types.set(PipelineStatisticsTypes::CLIPPER_PRIMITIVES_OUT, true); - } - if pipeline_statistics.contains("fragment-shader-invocations") { - types.set(PipelineStatisticsTypes::FRAGMENT_SHADER_INVOCATIONS, true); - } - if pipeline_statistics.contains("compute-shader-invocations") { - types.set(PipelineStatisticsTypes::COMPUTE_SHADER_INVOCATIONS, true); - } - - wgpu_types::QueryType::PipelineStatistics(types) - } - GpuQueryType::Timestamp => wgpu_types::QueryType::Timestamp, - } - } -} - -pub fn op_webgpu_create_query_set( - state: &mut OpState, - args: CreateQuerySetArgs, - _: (), -) -> Result { - let device_resource = - state.resource_table.get::(args.device_rid)?; - let device = device_resource.0; - let instance = &state.borrow::(); - - let descriptor = wgpu_types::QuerySetDescriptor { - label: args.label.map(Cow::from), - ty: args.r#type.into(), - count: args.count, - }; - - gfx_put!(device => instance.device_create_query_set( - device, - &descriptor, - std::marker::PhantomData - ) => state, WebGpuQuerySet) -} - -fn declare_webgpu_ops() -> Vec<(&'static str, Box)> { - vec![ - // Request device/adapter - ( - "op_webgpu_request_adapter", - op_async(op_webgpu_request_adapter), - ), - ( - "op_webgpu_request_device", - op_async(op_webgpu_request_device), - ), - // Query Set - ( - "op_webgpu_create_query_set", - op_sync(op_webgpu_create_query_set), - ), - // buffer - ( - "op_webgpu_create_buffer", - op_sync(buffer::op_webgpu_create_buffer), - ), - ( - "op_webgpu_buffer_get_mapped_range", - op_sync(buffer::op_webgpu_buffer_get_mapped_range), - ), - ( - "op_webgpu_buffer_unmap", - op_sync(buffer::op_webgpu_buffer_unmap), - ), - // buffer async - ( - "op_webgpu_buffer_get_map_async", - op_async(buffer::op_webgpu_buffer_get_map_async), - ), - // remaining sync ops - - // texture - ( - "op_webgpu_create_texture", - op_sync(texture::op_webgpu_create_texture), - ), - ( - "op_webgpu_create_texture_view", - op_sync(texture::op_webgpu_create_texture_view), - ), - // sampler - ( - "op_webgpu_create_sampler", - op_sync(sampler::op_webgpu_create_sampler), - ), - // binding - ( - "op_webgpu_create_bind_group_layout", - op_sync(binding::op_webgpu_create_bind_group_layout), - ), - ( - "op_webgpu_create_pipeline_layout", - op_sync(binding::op_webgpu_create_pipeline_layout), - ), - ( - "op_webgpu_create_bind_group", - op_sync(binding::op_webgpu_create_bind_group), - ), - // pipeline - ( - "op_webgpu_create_compute_pipeline", - op_sync(pipeline::op_webgpu_create_compute_pipeline), - ), - ( - "op_webgpu_compute_pipeline_get_bind_group_layout", - op_sync(pipeline::op_webgpu_compute_pipeline_get_bind_group_layout), - ), - ( - "op_webgpu_create_render_pipeline", - op_sync(pipeline::op_webgpu_create_render_pipeline), - ), - ( - "op_webgpu_render_pipeline_get_bind_group_layout", - op_sync(pipeline::op_webgpu_render_pipeline_get_bind_group_layout), - ), - // command_encoder - ( - "op_webgpu_create_command_encoder", - op_sync(command_encoder::op_webgpu_create_command_encoder), - ), - ( - "op_webgpu_command_encoder_begin_render_pass", - op_sync(command_encoder::op_webgpu_command_encoder_begin_render_pass), - ), - ( - "op_webgpu_command_encoder_begin_compute_pass", - op_sync(command_encoder::op_webgpu_command_encoder_begin_compute_pass), - ), - ( - "op_webgpu_command_encoder_copy_buffer_to_buffer", - op_sync(command_encoder::op_webgpu_command_encoder_copy_buffer_to_buffer), - ), - ( - "op_webgpu_command_encoder_copy_buffer_to_texture", - op_sync( - command_encoder::op_webgpu_command_encoder_copy_buffer_to_texture, - ), - ), - ( - "op_webgpu_command_encoder_copy_texture_to_buffer", - op_sync( - command_encoder::op_webgpu_command_encoder_copy_texture_to_buffer, - ), - ), - ( - "op_webgpu_command_encoder_copy_texture_to_texture", - op_sync( - command_encoder::op_webgpu_command_encoder_copy_texture_to_texture, - ), - ), - ( - "op_webgpu_command_encoder_push_debug_group", - op_sync(command_encoder::op_webgpu_command_encoder_push_debug_group), - ), - ( - "op_webgpu_command_encoder_pop_debug_group", - op_sync(command_encoder::op_webgpu_command_encoder_pop_debug_group), - ), - ( - "op_webgpu_command_encoder_insert_debug_marker", - op_sync(command_encoder::op_webgpu_command_encoder_insert_debug_marker), - ), - ( - "op_webgpu_command_encoder_write_timestamp", - op_sync(command_encoder::op_webgpu_command_encoder_write_timestamp), - ), - ( - "op_webgpu_command_encoder_resolve_query_set", - op_sync(command_encoder::op_webgpu_command_encoder_resolve_query_set), - ), - ( - "op_webgpu_command_encoder_finish", - op_sync(command_encoder::op_webgpu_command_encoder_finish), - ), - // render_pass - ( - "op_webgpu_render_pass_set_viewport", - op_sync(render_pass::op_webgpu_render_pass_set_viewport), - ), - ( - "op_webgpu_render_pass_set_scissor_rect", - op_sync(render_pass::op_webgpu_render_pass_set_scissor_rect), - ), - ( - "op_webgpu_render_pass_set_blend_constant", - op_sync(render_pass::op_webgpu_render_pass_set_blend_constant), - ), - ( - "op_webgpu_render_pass_set_stencil_reference", - op_sync(render_pass::op_webgpu_render_pass_set_stencil_reference), - ), - ( - "op_webgpu_render_pass_begin_pipeline_statistics_query", - op_sync( - render_pass::op_webgpu_render_pass_begin_pipeline_statistics_query, - ), - ), - ( - "op_webgpu_render_pass_end_pipeline_statistics_query", - op_sync(render_pass::op_webgpu_render_pass_end_pipeline_statistics_query), - ), - ( - "op_webgpu_render_pass_write_timestamp", - op_sync(render_pass::op_webgpu_render_pass_write_timestamp), - ), - ( - "op_webgpu_render_pass_execute_bundles", - op_sync(render_pass::op_webgpu_render_pass_execute_bundles), - ), - ( - "op_webgpu_render_pass_end_pass", - op_sync(render_pass::op_webgpu_render_pass_end_pass), - ), - ( - "op_webgpu_render_pass_set_bind_group", - op_sync(render_pass::op_webgpu_render_pass_set_bind_group), - ), - ( - "op_webgpu_render_pass_push_debug_group", - op_sync(render_pass::op_webgpu_render_pass_push_debug_group), - ), - ( - "op_webgpu_render_pass_pop_debug_group", - op_sync(render_pass::op_webgpu_render_pass_pop_debug_group), - ), - ( - "op_webgpu_render_pass_insert_debug_marker", - op_sync(render_pass::op_webgpu_render_pass_insert_debug_marker), - ), - ( - "op_webgpu_render_pass_set_pipeline", - op_sync(render_pass::op_webgpu_render_pass_set_pipeline), - ), - ( - "op_webgpu_render_pass_set_index_buffer", - op_sync(render_pass::op_webgpu_render_pass_set_index_buffer), - ), - ( - "op_webgpu_render_pass_set_vertex_buffer", - op_sync(render_pass::op_webgpu_render_pass_set_vertex_buffer), - ), - ( - "op_webgpu_render_pass_draw", - op_sync(render_pass::op_webgpu_render_pass_draw), - ), - ( - "op_webgpu_render_pass_draw_indexed", - op_sync(render_pass::op_webgpu_render_pass_draw_indexed), - ), - ( - "op_webgpu_render_pass_draw_indirect", - op_sync(render_pass::op_webgpu_render_pass_draw_indirect), - ), - ( - "op_webgpu_render_pass_draw_indexed_indirect", - op_sync(render_pass::op_webgpu_render_pass_draw_indexed_indirect), - ), - // compute_pass - ( - "op_webgpu_compute_pass_set_pipeline", - op_sync(compute_pass::op_webgpu_compute_pass_set_pipeline), - ), - ( - "op_webgpu_compute_pass_dispatch", - op_sync(compute_pass::op_webgpu_compute_pass_dispatch), - ), - ( - "op_webgpu_compute_pass_dispatch_indirect", - op_sync(compute_pass::op_webgpu_compute_pass_dispatch_indirect), - ), - ( - "op_webgpu_compute_pass_end_pass", - op_sync(compute_pass::op_webgpu_compute_pass_end_pass), - ), - ( - "op_webgpu_compute_pass_set_bind_group", - op_sync(compute_pass::op_webgpu_compute_pass_set_bind_group), - ), - ( - "op_webgpu_compute_pass_push_debug_group", - op_sync(compute_pass::op_webgpu_compute_pass_push_debug_group), - ), - ( - "op_webgpu_compute_pass_pop_debug_group", - op_sync(compute_pass::op_webgpu_compute_pass_pop_debug_group), - ), - ( - "op_webgpu_compute_pass_insert_debug_marker", - op_sync(compute_pass::op_webgpu_compute_pass_insert_debug_marker), - ), - // bundle - ( - "op_webgpu_create_render_bundle_encoder", - op_sync(bundle::op_webgpu_create_render_bundle_encoder), - ), - ( - "op_webgpu_render_bundle_encoder_finish", - op_sync(bundle::op_webgpu_render_bundle_encoder_finish), - ), - ( - "op_webgpu_render_bundle_encoder_set_bind_group", - op_sync(bundle::op_webgpu_render_bundle_encoder_set_bind_group), - ), - ( - "op_webgpu_render_bundle_encoder_push_debug_group", - op_sync(bundle::op_webgpu_render_bundle_encoder_push_debug_group), - ), - ( - "op_webgpu_render_bundle_encoder_pop_debug_group", - op_sync(bundle::op_webgpu_render_bundle_encoder_pop_debug_group), - ), - ( - "op_webgpu_render_bundle_encoder_insert_debug_marker", - op_sync(bundle::op_webgpu_render_bundle_encoder_insert_debug_marker), - ), - ( - "op_webgpu_render_bundle_encoder_set_pipeline", - op_sync(bundle::op_webgpu_render_bundle_encoder_set_pipeline), - ), - ( - "op_webgpu_render_bundle_encoder_set_index_buffer", - op_sync(bundle::op_webgpu_render_bundle_encoder_set_index_buffer), - ), - ( - "op_webgpu_render_bundle_encoder_set_vertex_buffer", - op_sync(bundle::op_webgpu_render_bundle_encoder_set_vertex_buffer), - ), - ( - "op_webgpu_render_bundle_encoder_draw", - op_sync(bundle::op_webgpu_render_bundle_encoder_draw), - ), - ( - "op_webgpu_render_bundle_encoder_draw_indexed", - op_sync(bundle::op_webgpu_render_bundle_encoder_draw_indexed), - ), - ( - "op_webgpu_render_bundle_encoder_draw_indirect", - op_sync(bundle::op_webgpu_render_bundle_encoder_draw_indirect), - ), - // queue - ( - "op_webgpu_queue_submit", - op_sync(queue::op_webgpu_queue_submit), - ), - ( - "op_webgpu_write_buffer", - op_sync(queue::op_webgpu_write_buffer), - ), - ( - "op_webgpu_write_texture", - op_sync(queue::op_webgpu_write_texture), - ), - // shader - ( - "op_webgpu_create_shader_module", - op_sync(shader::op_webgpu_create_shader_module), - ), - ] -} diff --git a/ext/webgpu/pipeline.rs b/ext/webgpu/pipeline.rs deleted file mode 100644 index 1d22bdba0da19e..00000000000000 --- a/ext/webgpu/pipeline.rs +++ /dev/null @@ -1,791 +0,0 @@ -// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. - -use deno_core::error::AnyError; -use deno_core::ResourceId; -use deno_core::{OpState, Resource}; -use serde::Deserialize; -use serde::Serialize; -use std::borrow::Cow; - -use crate::sampler::GpuCompareFunction; -use crate::texture::GpuTextureFormat; - -use super::error::{WebGpuError, WebGpuResult}; - -const MAX_BIND_GROUPS: usize = 8; - -pub(crate) struct WebGpuPipelineLayout( - pub(crate) wgpu_core::id::PipelineLayoutId, -); -impl Resource for WebGpuPipelineLayout { - fn name(&self) -> Cow { - "webGPUPipelineLayout".into() - } -} - -pub(crate) struct WebGpuComputePipeline( - pub(crate) wgpu_core::id::ComputePipelineId, -); -impl Resource for WebGpuComputePipeline { - fn name(&self) -> Cow { - "webGPUComputePipeline".into() - } -} - -pub(crate) struct WebGpuRenderPipeline( - pub(crate) wgpu_core::id::RenderPipelineId, -); -impl Resource for WebGpuRenderPipeline { - fn name(&self) -> Cow { - "webGPURenderPipeline".into() - } -} - -#[derive(Deserialize)] -#[serde(rename_all = "kebab-case")] -pub enum GpuIndexFormat { - Uint16, - Uint32, -} - -impl From for wgpu_types::IndexFormat { - fn from(value: GpuIndexFormat) -> wgpu_types::IndexFormat { - match value { - GpuIndexFormat::Uint16 => wgpu_types::IndexFormat::Uint16, - GpuIndexFormat::Uint32 => wgpu_types::IndexFormat::Uint32, - } - } -} - -#[derive(Deserialize)] -#[serde(rename_all = "kebab-case")] -pub enum GPUStencilOperation { - Keep, - Zero, - Replace, - Invert, - IncrementClamp, - DecrementClamp, - IncrementWrap, - DecrementWrap, -} - -impl From for wgpu_types::StencilOperation { - fn from(value: GPUStencilOperation) -> wgpu_types::StencilOperation { - match value { - GPUStencilOperation::Keep => wgpu_types::StencilOperation::Keep, - GPUStencilOperation::Zero => wgpu_types::StencilOperation::Zero, - GPUStencilOperation::Replace => wgpu_types::StencilOperation::Replace, - GPUStencilOperation::Invert => wgpu_types::StencilOperation::Invert, - GPUStencilOperation::IncrementClamp => { - wgpu_types::StencilOperation::IncrementClamp - } - GPUStencilOperation::DecrementClamp => { - wgpu_types::StencilOperation::DecrementClamp - } - GPUStencilOperation::IncrementWrap => { - wgpu_types::StencilOperation::IncrementWrap - } - GPUStencilOperation::DecrementWrap => { - wgpu_types::StencilOperation::DecrementWrap - } - } - } -} - -#[derive(Deserialize)] -#[serde(rename_all = "kebab-case")] -pub enum GpuBlendFactor { - Zero, - One, - Src, - OneMinusSrc, - SrcAlpha, - OneMinusSrcAlpha, - Dst, - OneMinusDst, - DstAlpha, - OneMinusDstAlpha, - SrcAlphaSaturated, - Constant, - OneMinusConstant, -} - -impl From for wgpu_types::BlendFactor { - fn from(value: GpuBlendFactor) -> wgpu_types::BlendFactor { - match value { - GpuBlendFactor::Zero => wgpu_types::BlendFactor::Zero, - GpuBlendFactor::One => wgpu_types::BlendFactor::One, - GpuBlendFactor::Src => wgpu_types::BlendFactor::Src, - GpuBlendFactor::OneMinusSrc => wgpu_types::BlendFactor::OneMinusSrc, - GpuBlendFactor::SrcAlpha => wgpu_types::BlendFactor::SrcAlpha, - GpuBlendFactor::OneMinusSrcAlpha => { - wgpu_types::BlendFactor::OneMinusSrcAlpha - } - GpuBlendFactor::Dst => wgpu_types::BlendFactor::Dst, - GpuBlendFactor::OneMinusDst => wgpu_types::BlendFactor::OneMinusDst, - GpuBlendFactor::DstAlpha => wgpu_types::BlendFactor::DstAlpha, - GpuBlendFactor::OneMinusDstAlpha => { - wgpu_types::BlendFactor::OneMinusDstAlpha - } - GpuBlendFactor::SrcAlphaSaturated => { - wgpu_types::BlendFactor::SrcAlphaSaturated - } - GpuBlendFactor::Constant => wgpu_types::BlendFactor::Constant, - GpuBlendFactor::OneMinusConstant => { - wgpu_types::BlendFactor::OneMinusConstant - } - } - } -} - -#[derive(Deserialize)] -#[serde(rename_all = "kebab-case")] -pub enum GpuBlendOperation { - Add, - Subtract, - ReverseSubtract, - Min, - Max, -} - -impl From for wgpu_types::BlendOperation { - fn from(value: GpuBlendOperation) -> wgpu_types::BlendOperation { - match value { - GpuBlendOperation::Add => wgpu_types::BlendOperation::Add, - GpuBlendOperation::Subtract => wgpu_types::BlendOperation::Subtract, - GpuBlendOperation::ReverseSubtract => { - wgpu_types::BlendOperation::ReverseSubtract - } - GpuBlendOperation::Min => wgpu_types::BlendOperation::Min, - GpuBlendOperation::Max => wgpu_types::BlendOperation::Max, - } - } -} - -#[derive(Deserialize)] -#[serde(rename_all = "kebab-case")] -pub enum GpuPrimitiveTopology { - PointList, - LineList, - LineStrip, - TriangleList, - TriangleStrip, -} - -impl From for wgpu_types::PrimitiveTopology { - fn from(value: GpuPrimitiveTopology) -> wgpu_types::PrimitiveTopology { - match value { - GpuPrimitiveTopology::PointList => { - wgpu_types::PrimitiveTopology::PointList - } - GpuPrimitiveTopology::LineList => wgpu_types::PrimitiveTopology::LineList, - GpuPrimitiveTopology::LineStrip => { - wgpu_types::PrimitiveTopology::LineStrip - } - GpuPrimitiveTopology::TriangleList => { - wgpu_types::PrimitiveTopology::TriangleList - } - GpuPrimitiveTopology::TriangleStrip => { - wgpu_types::PrimitiveTopology::TriangleStrip - } - } - } -} - -#[derive(Deserialize)] -#[serde(rename_all = "kebab-case")] -pub enum GpuFrontFace { - Ccw, - Cw, -} - -impl From for wgpu_types::FrontFace { - fn from(value: GpuFrontFace) -> wgpu_types::FrontFace { - match value { - GpuFrontFace::Ccw => wgpu_types::FrontFace::Ccw, - GpuFrontFace::Cw => wgpu_types::FrontFace::Cw, - } - } -} - -#[derive(Deserialize)] -#[serde(rename_all = "kebab-case")] -pub enum GpuCullMode { - None, - Front, - Back, -} - -impl From for Option { - fn from(value: GpuCullMode) -> Option { - match value { - GpuCullMode::None => None, - GpuCullMode::Front => Some(wgpu_types::Face::Front), - GpuCullMode::Back => Some(wgpu_types::Face::Back), - } - } -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -struct GpuProgrammableStage { - module: ResourceId, - entry_point: String, - // constants: HashMap -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct CreateComputePipelineArgs { - device_rid: ResourceId, - label: Option, - layout: Option, - compute: GpuProgrammableStage, -} - -pub fn op_webgpu_create_compute_pipeline( - state: &mut OpState, - args: CreateComputePipelineArgs, - _: (), -) -> Result { - let instance = state.borrow::(); - let device_resource = state - .resource_table - .get::(args.device_rid)?; - let device = device_resource.0; - - let pipeline_layout = if let Some(rid) = args.layout { - let id = state.resource_table.get::(rid)?; - Some(id.0) - } else { - None - }; - - let compute_shader_module_resource = - state - .resource_table - .get::(args.compute.module)?; - - let descriptor = wgpu_core::pipeline::ComputePipelineDescriptor { - label: args.label.map(Cow::from), - layout: pipeline_layout, - stage: wgpu_core::pipeline::ProgrammableStageDescriptor { - module: compute_shader_module_resource.0, - entry_point: Cow::from(args.compute.entry_point), - // TODO(lucacasonato): support args.compute.constants - }, - }; - let implicit_pipelines = match args.layout { - Some(_) => None, - None => Some(wgpu_core::device::ImplicitPipelineIds { - root_id: std::marker::PhantomData, - group_ids: &[std::marker::PhantomData; MAX_BIND_GROUPS], - }), - }; - - let (compute_pipeline, maybe_err) = gfx_select!(device => instance.device_create_compute_pipeline( - device, - &descriptor, - std::marker::PhantomData, - implicit_pipelines - )); - - let rid = state - .resource_table - .add(WebGpuComputePipeline(compute_pipeline)); - - Ok(WebGpuResult::rid_err(rid, maybe_err)) -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct ComputePipelineGetBindGroupLayoutArgs { - compute_pipeline_rid: ResourceId, - index: u32, -} - -#[derive(Serialize)] -#[serde(rename_all = "camelCase")] -pub struct PipelineLayout { - rid: ResourceId, - label: String, - err: Option, -} - -pub fn op_webgpu_compute_pipeline_get_bind_group_layout( - state: &mut OpState, - args: ComputePipelineGetBindGroupLayoutArgs, - _: (), -) -> Result { - let instance = state.borrow::(); - let compute_pipeline_resource = state - .resource_table - .get::(args.compute_pipeline_rid)?; - let compute_pipeline = compute_pipeline_resource.0; - - let (bind_group_layout, maybe_err) = gfx_select!(compute_pipeline => instance.compute_pipeline_get_bind_group_layout(compute_pipeline, args.index, std::marker::PhantomData)); - - let label = gfx_select!(bind_group_layout => instance.bind_group_layout_label(bind_group_layout)); - - let rid = state - .resource_table - .add(super::binding::WebGpuBindGroupLayout(bind_group_layout)); - - Ok(PipelineLayout { - rid, - label, - err: maybe_err.map(WebGpuError::from), - }) -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -struct GpuPrimitiveState { - topology: GpuPrimitiveTopology, - strip_index_format: Option, - front_face: GpuFrontFace, - cull_mode: GpuCullMode, - clamp_depth: bool, -} - -impl From for wgpu_types::PrimitiveState { - fn from(value: GpuPrimitiveState) -> wgpu_types::PrimitiveState { - wgpu_types::PrimitiveState { - topology: value.topology.into(), - strip_index_format: value.strip_index_format.map(Into::into), - front_face: value.front_face.into(), - cull_mode: value.cull_mode.into(), - clamp_depth: value.clamp_depth, - polygon_mode: Default::default(), // native-only - conservative: false, // native-only - } - } -} -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -struct GpuBlendComponent { - src_factor: GpuBlendFactor, - dst_factor: GpuBlendFactor, - operation: GpuBlendOperation, -} - -impl From for wgpu_types::BlendComponent { - fn from(component: GpuBlendComponent) -> Self { - wgpu_types::BlendComponent { - src_factor: component.src_factor.into(), - dst_factor: component.dst_factor.into(), - operation: component.operation.into(), - } - } -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -struct GpuBlendState { - color: GpuBlendComponent, - alpha: GpuBlendComponent, -} - -impl From for wgpu_types::BlendState { - fn from(state: GpuBlendState) -> wgpu_types::BlendState { - wgpu_types::BlendState { - color: state.color.into(), - alpha: state.alpha.into(), - } - } -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -struct GpuColorTargetState { - format: GpuTextureFormat, - blend: Option, - write_mask: u32, -} - -impl TryFrom for wgpu_types::ColorTargetState { - type Error = AnyError; - fn try_from( - state: GpuColorTargetState, - ) -> Result { - Ok(wgpu_types::ColorTargetState { - format: state.format.try_into()?, - blend: state.blend.map(Into::into), - write_mask: wgpu_types::ColorWrites::from_bits_truncate(state.write_mask), - }) - } -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -struct GpuStencilFaceState { - compare: GpuCompareFunction, - fail_op: GPUStencilOperation, - depth_fail_op: GPUStencilOperation, - pass_op: GPUStencilOperation, -} - -impl From for wgpu_types::StencilFaceState { - fn from(state: GpuStencilFaceState) -> Self { - wgpu_types::StencilFaceState { - compare: state.compare.into(), - fail_op: state.fail_op.into(), - depth_fail_op: state.depth_fail_op.into(), - pass_op: state.pass_op.into(), - } - } -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -struct GpuDepthStencilState { - format: GpuTextureFormat, - depth_write_enabled: bool, - depth_compare: GpuCompareFunction, - stencil_front: GpuStencilFaceState, - stencil_back: GpuStencilFaceState, - stencil_read_mask: u32, - stencil_write_mask: u32, - depth_bias: i32, - depth_bias_slope_scale: f32, - depth_bias_clamp: f32, -} - -impl TryFrom for wgpu_types::DepthStencilState { - type Error = AnyError; - fn try_from( - state: GpuDepthStencilState, - ) -> Result { - Ok(wgpu_types::DepthStencilState { - format: state.format.try_into()?, - depth_write_enabled: state.depth_write_enabled, - depth_compare: state.depth_compare.into(), - stencil: wgpu_types::StencilState { - front: state.stencil_front.into(), - back: state.stencil_back.into(), - read_mask: state.stencil_read_mask, - write_mask: state.stencil_write_mask, - }, - bias: wgpu_types::DepthBiasState { - constant: state.depth_bias, - slope_scale: state.depth_bias_slope_scale, - clamp: state.depth_bias_clamp, - }, - }) - } -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -struct GpuVertexAttribute { - format: GpuVertexFormat, - offset: u64, - shader_location: u32, -} - -impl From for wgpu_types::VertexAttribute { - fn from(attribute: GpuVertexAttribute) -> Self { - wgpu_types::VertexAttribute { - format: attribute.format.into(), - offset: attribute.offset, - shader_location: attribute.shader_location, - } - } -} - -#[derive(Deserialize)] -#[serde(rename_all = "lowercase")] -enum GpuVertexFormat { - Uint8x2, - Uint8x4, - Sint8x2, - Sint8x4, - Unorm8x2, - Unorm8x4, - Snorm8x2, - Snorm8x4, - Uint16x2, - Uint16x4, - Sint16x2, - Sint16x4, - Unorm16x2, - Unorm16x4, - Snorm16x2, - Snorm16x4, - Float16x2, - Float16x4, - Float32, - Float32x2, - Float32x3, - Float32x4, - Uint32, - Uint32x2, - Uint32x3, - Uint32x4, - Sint32, - Sint32x2, - Sint32x3, - Sint32x4, - Float64, - Float64x2, - Float64x3, - Float64x4, -} - -impl From for wgpu_types::VertexFormat { - fn from(vf: GpuVertexFormat) -> wgpu_types::VertexFormat { - use wgpu_types::VertexFormat; - match vf { - GpuVertexFormat::Uint8x2 => VertexFormat::Uint8x2, - GpuVertexFormat::Uint8x4 => VertexFormat::Uint8x4, - GpuVertexFormat::Sint8x2 => VertexFormat::Sint8x2, - GpuVertexFormat::Sint8x4 => VertexFormat::Sint8x4, - GpuVertexFormat::Unorm8x2 => VertexFormat::Unorm8x2, - GpuVertexFormat::Unorm8x4 => VertexFormat::Unorm8x4, - GpuVertexFormat::Snorm8x2 => VertexFormat::Snorm8x2, - GpuVertexFormat::Snorm8x4 => VertexFormat::Snorm8x4, - GpuVertexFormat::Uint16x2 => VertexFormat::Uint16x2, - GpuVertexFormat::Uint16x4 => VertexFormat::Uint16x4, - GpuVertexFormat::Sint16x2 => VertexFormat::Sint16x2, - GpuVertexFormat::Sint16x4 => VertexFormat::Sint16x4, - GpuVertexFormat::Unorm16x2 => VertexFormat::Unorm16x2, - GpuVertexFormat::Unorm16x4 => VertexFormat::Unorm16x4, - GpuVertexFormat::Snorm16x2 => VertexFormat::Snorm16x2, - GpuVertexFormat::Snorm16x4 => VertexFormat::Snorm16x4, - GpuVertexFormat::Float16x2 => VertexFormat::Float16x2, - GpuVertexFormat::Float16x4 => VertexFormat::Float16x4, - GpuVertexFormat::Float32 => VertexFormat::Float32, - GpuVertexFormat::Float32x2 => VertexFormat::Float32x2, - GpuVertexFormat::Float32x3 => VertexFormat::Float32x3, - GpuVertexFormat::Float32x4 => VertexFormat::Float32x4, - GpuVertexFormat::Uint32 => VertexFormat::Uint32, - GpuVertexFormat::Uint32x2 => VertexFormat::Uint32x2, - GpuVertexFormat::Uint32x3 => VertexFormat::Uint32x3, - GpuVertexFormat::Uint32x4 => VertexFormat::Uint32x4, - GpuVertexFormat::Sint32 => VertexFormat::Sint32, - GpuVertexFormat::Sint32x2 => VertexFormat::Sint32x2, - GpuVertexFormat::Sint32x3 => VertexFormat::Sint32x3, - GpuVertexFormat::Sint32x4 => VertexFormat::Sint32x4, - GpuVertexFormat::Float64 => VertexFormat::Float64, - GpuVertexFormat::Float64x2 => VertexFormat::Float64x2, - GpuVertexFormat::Float64x3 => VertexFormat::Float64x3, - GpuVertexFormat::Float64x4 => VertexFormat::Float64x4, - } - } -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -enum GpuVertexStepMode { - Vertex, - Instance, -} - -impl From for wgpu_types::VertexStepMode { - fn from(vsm: GpuVertexStepMode) -> wgpu_types::VertexStepMode { - use wgpu_types::VertexStepMode; - match vsm { - GpuVertexStepMode::Vertex => VertexStepMode::Vertex, - GpuVertexStepMode::Instance => VertexStepMode::Instance, - } - } -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -struct GpuVertexBufferLayout { - array_stride: u64, - step_mode: GpuVertexStepMode, - attributes: Vec, -} - -impl<'a> From - for wgpu_core::pipeline::VertexBufferLayout<'a> -{ - fn from( - layout: GpuVertexBufferLayout, - ) -> wgpu_core::pipeline::VertexBufferLayout<'a> { - wgpu_core::pipeline::VertexBufferLayout { - array_stride: layout.array_stride, - step_mode: layout.step_mode.into(), - attributes: Cow::Owned( - layout.attributes.into_iter().map(Into::into).collect(), - ), - } - } -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -struct GpuVertexState { - module: ResourceId, - entry_point: String, - buffers: Vec>, -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -struct GpuMultisampleState { - count: u32, - mask: u64, - alpha_to_coverage_enabled: bool, -} - -impl From for wgpu_types::MultisampleState { - fn from(gms: GpuMultisampleState) -> wgpu_types::MultisampleState { - wgpu_types::MultisampleState { - count: gms.count, - mask: gms.mask, - alpha_to_coverage_enabled: gms.alpha_to_coverage_enabled, - } - } -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -struct GpuFragmentState { - targets: Vec, - module: u32, - entry_point: String, - // TODO(lucacasonato): constants -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct CreateRenderPipelineArgs { - device_rid: ResourceId, - label: Option, - layout: Option, - vertex: GpuVertexState, - primitive: GpuPrimitiveState, - depth_stencil: Option, - multisample: GpuMultisampleState, - fragment: Option, -} - -pub fn op_webgpu_create_render_pipeline( - state: &mut OpState, - args: CreateRenderPipelineArgs, - _: (), -) -> Result { - let instance = state.borrow::(); - let device_resource = state - .resource_table - .get::(args.device_rid)?; - let device = device_resource.0; - - let layout = if let Some(rid) = args.layout { - let pipeline_layout_resource = - state.resource_table.get::(rid)?; - Some(pipeline_layout_resource.0) - } else { - None - }; - - let vertex_shader_module_resource = - state - .resource_table - .get::(args.vertex.module)?; - - let fragment = if let Some(fragment) = args.fragment { - let fragment_shader_module_resource = - state - .resource_table - .get::(fragment.module)?; - - let mut targets = Vec::with_capacity(fragment.targets.len()); - - for target in fragment.targets { - targets.push(target.try_into()?); - } - - Some(wgpu_core::pipeline::FragmentState { - stage: wgpu_core::pipeline::ProgrammableStageDescriptor { - module: fragment_shader_module_resource.0, - entry_point: Cow::from(fragment.entry_point), - }, - targets: Cow::from(targets), - }) - } else { - None - }; - - let vertex_buffers = args - .vertex - .buffers - .into_iter() - .flatten() - .map(Into::into) - .collect(); - - let descriptor = wgpu_core::pipeline::RenderPipelineDescriptor { - label: args.label.map(Cow::Owned), - layout, - vertex: wgpu_core::pipeline::VertexState { - stage: wgpu_core::pipeline::ProgrammableStageDescriptor { - module: vertex_shader_module_resource.0, - entry_point: Cow::Owned(args.vertex.entry_point), - }, - buffers: Cow::Owned(vertex_buffers), - }, - primitive: args.primitive.into(), - depth_stencil: args.depth_stencil.map(TryInto::try_into).transpose()?, - multisample: args.multisample.into(), - fragment, - }; - - let implicit_pipelines = match args.layout { - Some(_) => None, - None => Some(wgpu_core::device::ImplicitPipelineIds { - root_id: std::marker::PhantomData, - group_ids: &[std::marker::PhantomData; MAX_BIND_GROUPS], - }), - }; - - let (render_pipeline, maybe_err) = gfx_select!(device => instance.device_create_render_pipeline( - device, - &descriptor, - std::marker::PhantomData, - implicit_pipelines - )); - - let rid = state - .resource_table - .add(WebGpuRenderPipeline(render_pipeline)); - - Ok(WebGpuResult::rid_err(rid, maybe_err)) -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct RenderPipelineGetBindGroupLayoutArgs { - render_pipeline_rid: ResourceId, - index: u32, -} - -pub fn op_webgpu_render_pipeline_get_bind_group_layout( - state: &mut OpState, - args: RenderPipelineGetBindGroupLayoutArgs, - _: (), -) -> Result { - let instance = state.borrow::(); - let render_pipeline_resource = state - .resource_table - .get::(args.render_pipeline_rid)?; - let render_pipeline = render_pipeline_resource.0; - - let (bind_group_layout, maybe_err) = gfx_select!(render_pipeline => instance.render_pipeline_get_bind_group_layout(render_pipeline, args.index, std::marker::PhantomData)); - - let label = gfx_select!(bind_group_layout => instance.bind_group_layout_label(bind_group_layout)); - - let rid = state - .resource_table - .add(super::binding::WebGpuBindGroupLayout(bind_group_layout)); - - Ok(PipelineLayout { - rid, - label, - err: maybe_err.map(WebGpuError::from), - }) -} diff --git a/ext/webgpu/queue.rs b/ext/webgpu/queue.rs deleted file mode 100644 index 39bd936037c4af..00000000000000 --- a/ext/webgpu/queue.rs +++ /dev/null @@ -1,142 +0,0 @@ -// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. - -use std::num::NonZeroU32; - -use deno_core::error::AnyError; -use deno_core::OpState; -use deno_core::ResourceId; -use deno_core::ZeroCopyBuf; -use serde::Deserialize; - -use super::error::WebGpuResult; - -type WebGpuQueue = super::WebGpuDevice; - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct QueueSubmitArgs { - queue_rid: ResourceId, - command_buffers: Vec, -} - -pub fn op_webgpu_queue_submit( - state: &mut OpState, - args: QueueSubmitArgs, - _: (), -) -> Result { - let instance = state.borrow::(); - let queue_resource = - state.resource_table.get::(args.queue_rid)?; - let queue = queue_resource.0; - - let mut ids = vec![]; - - for rid in args.command_buffers { - let buffer_resource = - state - .resource_table - .get::(rid)?; - ids.push(buffer_resource.0); - } - - let maybe_err = - gfx_select!(queue => instance.queue_submit(queue, &ids)).err(); - - Ok(WebGpuResult::maybe_err(maybe_err)) -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -struct GpuImageDataLayout { - offset: u64, - bytes_per_row: Option, - rows_per_image: Option, -} - -impl From for wgpu_types::ImageDataLayout { - fn from(layout: GpuImageDataLayout) -> Self { - wgpu_types::ImageDataLayout { - offset: layout.offset, - bytes_per_row: NonZeroU32::new(layout.bytes_per_row.unwrap_or(0)), - rows_per_image: NonZeroU32::new(layout.rows_per_image.unwrap_or(0)), - } - } -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct QueueWriteBufferArgs { - queue_rid: ResourceId, - buffer: ResourceId, - buffer_offset: u64, - data_offset: usize, - size: Option, -} - -pub fn op_webgpu_write_buffer( - state: &mut OpState, - args: QueueWriteBufferArgs, - zero_copy: ZeroCopyBuf, -) -> Result { - let instance = state.borrow::(); - let buffer_resource = state - .resource_table - .get::(args.buffer)?; - let buffer = buffer_resource.0; - let queue_resource = - state.resource_table.get::(args.queue_rid)?; - let queue = queue_resource.0; - - let data = match args.size { - Some(size) => &zero_copy[args.data_offset..(args.data_offset + size)], - None => &zero_copy[args.data_offset..], - }; - let maybe_err = gfx_select!(queue => instance.queue_write_buffer( - queue, - buffer, - args.buffer_offset, - data - )) - .err(); - - Ok(WebGpuResult::maybe_err(maybe_err)) -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct QueueWriteTextureArgs { - queue_rid: ResourceId, - destination: super::command_encoder::GpuImageCopyTexture, - data_layout: GpuImageDataLayout, - size: super::texture::GpuExtent3D, -} - -pub fn op_webgpu_write_texture( - state: &mut OpState, - args: QueueWriteTextureArgs, - zero_copy: ZeroCopyBuf, -) -> Result { - let instance = state.borrow::(); - let texture_resource = state - .resource_table - .get::(args.destination.texture)?; - let queue_resource = - state.resource_table.get::(args.queue_rid)?; - let queue = queue_resource.0; - - let destination = wgpu_core::command::ImageCopyTexture { - texture: texture_resource.0, - mip_level: args.destination.mip_level, - origin: args.destination.origin.into(), - aspect: args.destination.aspect.into(), - }; - let data_layout = args.data_layout.into(); - - gfx_ok!(queue => instance.queue_write_texture( - queue, - &destination, - &*zero_copy, - &data_layout, - &args.size.into() - )) -} diff --git a/ext/webgpu/render_pass.rs b/ext/webgpu/render_pass.rs deleted file mode 100644 index 780b6ea577e4ed..00000000000000 --- a/ext/webgpu/render_pass.rs +++ /dev/null @@ -1,665 +0,0 @@ -// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. - -use deno_core::error::type_error; -use deno_core::error::AnyError; -use deno_core::ResourceId; -use deno_core::ZeroCopyBuf; -use deno_core::{OpState, Resource}; -use serde::Deserialize; -use std::borrow::Cow; -use std::cell::RefCell; - -use crate::pipeline::GpuIndexFormat; - -use super::error::WebGpuResult; - -pub(crate) struct WebGpuRenderPass( - pub(crate) RefCell, -); -impl Resource for WebGpuRenderPass { - fn name(&self) -> Cow { - "webGPURenderPass".into() - } -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct RenderPassSetViewportArgs { - render_pass_rid: ResourceId, - x: f32, - y: f32, - width: f32, - height: f32, - min_depth: f32, - max_depth: f32, -} - -pub fn op_webgpu_render_pass_set_viewport( - state: &mut OpState, - args: RenderPassSetViewportArgs, - _: (), -) -> Result { - let render_pass_resource = state - .resource_table - .get::(args.render_pass_rid)?; - - wgpu_core::command::render_ffi::wgpu_render_pass_set_viewport( - &mut render_pass_resource.0.borrow_mut(), - args.x, - args.y, - args.width, - args.height, - args.min_depth, - args.max_depth, - ); - - Ok(WebGpuResult::empty()) -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct RenderPassSetScissorRectArgs { - render_pass_rid: ResourceId, - x: u32, - y: u32, - width: u32, - height: u32, -} - -pub fn op_webgpu_render_pass_set_scissor_rect( - state: &mut OpState, - args: RenderPassSetScissorRectArgs, - _: (), -) -> Result { - let render_pass_resource = state - .resource_table - .get::(args.render_pass_rid)?; - - wgpu_core::command::render_ffi::wgpu_render_pass_set_scissor_rect( - &mut render_pass_resource.0.borrow_mut(), - args.x, - args.y, - args.width, - args.height, - ); - - Ok(WebGpuResult::empty()) -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct GpuColor { - pub r: f64, - pub g: f64, - pub b: f64, - pub a: f64, -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct RenderPassSetBlendConstantArgs { - render_pass_rid: ResourceId, - color: GpuColor, -} - -pub fn op_webgpu_render_pass_set_blend_constant( - state: &mut OpState, - args: RenderPassSetBlendConstantArgs, - _: (), -) -> Result { - let render_pass_resource = state - .resource_table - .get::(args.render_pass_rid)?; - - wgpu_core::command::render_ffi::wgpu_render_pass_set_blend_constant( - &mut render_pass_resource.0.borrow_mut(), - &wgpu_types::Color { - r: args.color.r, - g: args.color.g, - b: args.color.b, - a: args.color.a, - }, - ); - - Ok(WebGpuResult::empty()) -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct RenderPassSetStencilReferenceArgs { - render_pass_rid: ResourceId, - reference: u32, -} - -pub fn op_webgpu_render_pass_set_stencil_reference( - state: &mut OpState, - args: RenderPassSetStencilReferenceArgs, - _: (), -) -> Result { - let render_pass_resource = state - .resource_table - .get::(args.render_pass_rid)?; - - wgpu_core::command::render_ffi::wgpu_render_pass_set_stencil_reference( - &mut render_pass_resource.0.borrow_mut(), - args.reference, - ); - - Ok(WebGpuResult::empty()) -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct RenderPassBeginPipelineStatisticsQueryArgs { - render_pass_rid: ResourceId, - query_set: u32, - query_index: u32, -} - -pub fn op_webgpu_render_pass_begin_pipeline_statistics_query( - state: &mut OpState, - args: RenderPassBeginPipelineStatisticsQueryArgs, - _: (), -) -> Result { - let render_pass_resource = state - .resource_table - .get::(args.render_pass_rid)?; - let query_set_resource = state - .resource_table - .get::(args.query_set)?; - - wgpu_core::command::render_ffi::wgpu_render_pass_begin_pipeline_statistics_query( - &mut render_pass_resource.0.borrow_mut(), - query_set_resource.0, - args.query_index, - ); - - Ok(WebGpuResult::empty()) -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct RenderPassEndPipelineStatisticsQueryArgs { - render_pass_rid: ResourceId, -} - -pub fn op_webgpu_render_pass_end_pipeline_statistics_query( - state: &mut OpState, - args: RenderPassEndPipelineStatisticsQueryArgs, - _: (), -) -> Result { - let render_pass_resource = state - .resource_table - .get::(args.render_pass_rid)?; - - wgpu_core::command::render_ffi::wgpu_render_pass_end_pipeline_statistics_query( - &mut render_pass_resource.0.borrow_mut(), - ); - - Ok(WebGpuResult::empty()) -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct RenderPassWriteTimestampArgs { - render_pass_rid: ResourceId, - query_set: u32, - query_index: u32, -} - -pub fn op_webgpu_render_pass_write_timestamp( - state: &mut OpState, - args: RenderPassWriteTimestampArgs, - _: (), -) -> Result { - let render_pass_resource = state - .resource_table - .get::(args.render_pass_rid)?; - let query_set_resource = state - .resource_table - .get::(args.query_set)?; - - wgpu_core::command::render_ffi::wgpu_render_pass_write_timestamp( - &mut render_pass_resource.0.borrow_mut(), - query_set_resource.0, - args.query_index, - ); - - Ok(WebGpuResult::empty()) -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct RenderPassExecuteBundlesArgs { - render_pass_rid: ResourceId, - bundles: Vec, -} - -pub fn op_webgpu_render_pass_execute_bundles( - state: &mut OpState, - args: RenderPassExecuteBundlesArgs, - _: (), -) -> Result { - let mut render_bundle_ids = vec![]; - - for rid in &args.bundles { - let render_bundle_resource = - state - .resource_table - .get::(*rid)?; - render_bundle_ids.push(render_bundle_resource.0); - } - - let render_pass_resource = state - .resource_table - .get::(args.render_pass_rid)?; - - // SAFETY: the raw pointer and length are of the same slice, and that slice - // lives longer than the below function invocation. - unsafe { - wgpu_core::command::render_ffi::wgpu_render_pass_execute_bundles( - &mut render_pass_resource.0.borrow_mut(), - render_bundle_ids.as_ptr(), - render_bundle_ids.len(), - ); - } - - Ok(WebGpuResult::empty()) -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct RenderPassEndPassArgs { - command_encoder_rid: ResourceId, - render_pass_rid: ResourceId, -} - -pub fn op_webgpu_render_pass_end_pass( - state: &mut OpState, - args: RenderPassEndPassArgs, - _: (), -) -> Result { - let command_encoder_resource = state - .resource_table - .get::( - args.command_encoder_rid, - )?; - let command_encoder = command_encoder_resource.0; - let render_pass_resource = state - .resource_table - .take::(args.render_pass_rid)?; - let render_pass = &render_pass_resource.0.borrow(); - let instance = state.borrow::(); - - gfx_ok!(command_encoder => instance.command_encoder_run_render_pass(command_encoder, render_pass)) -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct RenderPassSetBindGroupArgs { - render_pass_rid: ResourceId, - index: u32, - bind_group: u32, - dynamic_offsets_data: ZeroCopyBuf, - dynamic_offsets_data_start: usize, - dynamic_offsets_data_length: usize, -} - -pub fn op_webgpu_render_pass_set_bind_group( - state: &mut OpState, - args: RenderPassSetBindGroupArgs, - _: (), -) -> Result { - let bind_group_resource = - state - .resource_table - .get::(args.bind_group)?; - let render_pass_resource = state - .resource_table - .get::(args.render_pass_rid)?; - - // Align the data - assert!(args.dynamic_offsets_data_start % std::mem::size_of::() == 0); - // SAFETY: A u8 to u32 cast is safe because we asserted that the length is a - // multiple of 4. - let (prefix, dynamic_offsets_data, suffix) = - unsafe { args.dynamic_offsets_data.align_to::() }; - assert!(prefix.is_empty()); - assert!(suffix.is_empty()); - - let start = args.dynamic_offsets_data_start; - let len = args.dynamic_offsets_data_length; - - // Assert that length and start are both in bounds - assert!(start <= dynamic_offsets_data.len()); - assert!(len <= dynamic_offsets_data.len() - start); - - let dynamic_offsets_data: &[u32] = &dynamic_offsets_data[start..start + len]; - - // SAFETY: the raw pointer and length are of the same slice, and that slice - // lives longer than the below function invocation. - unsafe { - wgpu_core::command::render_ffi::wgpu_render_pass_set_bind_group( - &mut render_pass_resource.0.borrow_mut(), - args.index, - bind_group_resource.0, - dynamic_offsets_data.as_ptr(), - dynamic_offsets_data.len(), - ); - } - - Ok(WebGpuResult::empty()) -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct RenderPassPushDebugGroupArgs { - render_pass_rid: ResourceId, - group_label: String, -} - -pub fn op_webgpu_render_pass_push_debug_group( - state: &mut OpState, - args: RenderPassPushDebugGroupArgs, - _: (), -) -> Result { - let render_pass_resource = state - .resource_table - .get::(args.render_pass_rid)?; - - let label = std::ffi::CString::new(args.group_label).unwrap(); - // SAFETY: the string the raw pointer points to lives longer than the below - // function invocation. - unsafe { - wgpu_core::command::render_ffi::wgpu_render_pass_push_debug_group( - &mut render_pass_resource.0.borrow_mut(), - label.as_ptr(), - 0, // wgpu#975 - ); - } - - Ok(WebGpuResult::empty()) -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct RenderPassPopDebugGroupArgs { - render_pass_rid: ResourceId, -} - -pub fn op_webgpu_render_pass_pop_debug_group( - state: &mut OpState, - args: RenderPassPopDebugGroupArgs, - _: (), -) -> Result { - let render_pass_resource = state - .resource_table - .get::(args.render_pass_rid)?; - - wgpu_core::command::render_ffi::wgpu_render_pass_pop_debug_group( - &mut render_pass_resource.0.borrow_mut(), - ); - - Ok(WebGpuResult::empty()) -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct RenderPassInsertDebugMarkerArgs { - render_pass_rid: ResourceId, - marker_label: String, -} - -pub fn op_webgpu_render_pass_insert_debug_marker( - state: &mut OpState, - args: RenderPassInsertDebugMarkerArgs, - _: (), -) -> Result { - let render_pass_resource = state - .resource_table - .get::(args.render_pass_rid)?; - - let label = std::ffi::CString::new(args.marker_label).unwrap(); - // SAFETY: the string the raw pointer points to lives longer than the below - // function invocation. - unsafe { - wgpu_core::command::render_ffi::wgpu_render_pass_insert_debug_marker( - &mut render_pass_resource.0.borrow_mut(), - label.as_ptr(), - 0, // wgpu#975 - ); - } - - Ok(WebGpuResult::empty()) -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct RenderPassSetPipelineArgs { - render_pass_rid: ResourceId, - pipeline: u32, -} - -pub fn op_webgpu_render_pass_set_pipeline( - state: &mut OpState, - args: RenderPassSetPipelineArgs, - _: (), -) -> Result { - let render_pipeline_resource = - state - .resource_table - .get::(args.pipeline)?; - let render_pass_resource = state - .resource_table - .get::(args.render_pass_rid)?; - - wgpu_core::command::render_ffi::wgpu_render_pass_set_pipeline( - &mut render_pass_resource.0.borrow_mut(), - render_pipeline_resource.0, - ); - - Ok(WebGpuResult::empty()) -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct RenderPassSetIndexBufferArgs { - render_pass_rid: ResourceId, - buffer: u32, - index_format: GpuIndexFormat, - offset: u64, - size: Option, -} - -pub fn op_webgpu_render_pass_set_index_buffer( - state: &mut OpState, - args: RenderPassSetIndexBufferArgs, - _: (), -) -> Result { - let buffer_resource = state - .resource_table - .get::(args.buffer)?; - let render_pass_resource = state - .resource_table - .get::(args.render_pass_rid)?; - - let size = if let Some(size) = args.size { - Some( - std::num::NonZeroU64::new(size) - .ok_or_else(|| type_error("size must be larger than 0"))?, - ) - } else { - None - }; - - render_pass_resource.0.borrow_mut().set_index_buffer( - buffer_resource.0, - args.index_format.into(), - args.offset, - size, - ); - - Ok(WebGpuResult::empty()) -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct RenderPassSetVertexBufferArgs { - render_pass_rid: ResourceId, - slot: u32, - buffer: u32, - offset: u64, - size: Option, -} - -pub fn op_webgpu_render_pass_set_vertex_buffer( - state: &mut OpState, - args: RenderPassSetVertexBufferArgs, - _: (), -) -> Result { - let buffer_resource = state - .resource_table - .get::(args.buffer)?; - let render_pass_resource = state - .resource_table - .get::(args.render_pass_rid)?; - - let size = if let Some(size) = args.size { - Some( - std::num::NonZeroU64::new(size) - .ok_or_else(|| type_error("size must be larger than 0"))?, - ) - } else { - None - }; - - wgpu_core::command::render_ffi::wgpu_render_pass_set_vertex_buffer( - &mut render_pass_resource.0.borrow_mut(), - args.slot, - buffer_resource.0, - args.offset, - size, - ); - - Ok(WebGpuResult::empty()) -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct RenderPassDrawArgs { - render_pass_rid: ResourceId, - vertex_count: u32, - instance_count: u32, - first_vertex: u32, - first_instance: u32, -} - -pub fn op_webgpu_render_pass_draw( - state: &mut OpState, - args: RenderPassDrawArgs, - _: (), -) -> Result { - let render_pass_resource = state - .resource_table - .get::(args.render_pass_rid)?; - - wgpu_core::command::render_ffi::wgpu_render_pass_draw( - &mut render_pass_resource.0.borrow_mut(), - args.vertex_count, - args.instance_count, - args.first_vertex, - args.first_instance, - ); - - Ok(WebGpuResult::empty()) -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct RenderPassDrawIndexedArgs { - render_pass_rid: ResourceId, - index_count: u32, - instance_count: u32, - first_index: u32, - base_vertex: i32, - first_instance: u32, -} - -pub fn op_webgpu_render_pass_draw_indexed( - state: &mut OpState, - args: RenderPassDrawIndexedArgs, - _: (), -) -> Result { - let render_pass_resource = state - .resource_table - .get::(args.render_pass_rid)?; - - wgpu_core::command::render_ffi::wgpu_render_pass_draw_indexed( - &mut render_pass_resource.0.borrow_mut(), - args.index_count, - args.instance_count, - args.first_index, - args.base_vertex, - args.first_instance, - ); - - Ok(WebGpuResult::empty()) -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct RenderPassDrawIndirectArgs { - render_pass_rid: ResourceId, - indirect_buffer: u32, - indirect_offset: u64, -} - -pub fn op_webgpu_render_pass_draw_indirect( - state: &mut OpState, - args: RenderPassDrawIndirectArgs, - _: (), -) -> Result { - let buffer_resource = state - .resource_table - .get::(args.indirect_buffer)?; - let render_pass_resource = state - .resource_table - .get::(args.render_pass_rid)?; - - wgpu_core::command::render_ffi::wgpu_render_pass_draw_indirect( - &mut render_pass_resource.0.borrow_mut(), - buffer_resource.0, - args.indirect_offset, - ); - - Ok(WebGpuResult::empty()) -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct RenderPassDrawIndexedIndirectArgs { - render_pass_rid: ResourceId, - indirect_buffer: u32, - indirect_offset: u64, -} - -pub fn op_webgpu_render_pass_draw_indexed_indirect( - state: &mut OpState, - args: RenderPassDrawIndexedIndirectArgs, - _: (), -) -> Result { - let buffer_resource = state - .resource_table - .get::(args.indirect_buffer)?; - let render_pass_resource = state - .resource_table - .get::(args.render_pass_rid)?; - - wgpu_core::command::render_ffi::wgpu_render_pass_draw_indexed_indirect( - &mut render_pass_resource.0.borrow_mut(), - buffer_resource.0, - args.indirect_offset, - ); - - Ok(WebGpuResult::empty()) -} diff --git a/ext/webgpu/sampler.rs b/ext/webgpu/sampler.rs deleted file mode 100644 index 23652cc4702c17..00000000000000 --- a/ext/webgpu/sampler.rs +++ /dev/null @@ -1,132 +0,0 @@ -// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. - -use deno_core::error::AnyError; -use deno_core::ResourceId; -use deno_core::{OpState, Resource}; -use serde::Deserialize; -use std::borrow::Cow; - -use super::error::WebGpuResult; - -pub(crate) struct WebGpuSampler(pub(crate) wgpu_core::id::SamplerId); -impl Resource for WebGpuSampler { - fn name(&self) -> Cow { - "webGPUSampler".into() - } -} - -#[derive(Deserialize)] -#[serde(rename_all = "kebab-case")] -enum GpuAddressMode { - ClampToEdge, - Repeat, - MirrorRepeat, -} - -impl From for wgpu_types::AddressMode { - fn from(value: GpuAddressMode) -> wgpu_types::AddressMode { - match value { - GpuAddressMode::ClampToEdge => wgpu_types::AddressMode::ClampToEdge, - GpuAddressMode::Repeat => wgpu_types::AddressMode::Repeat, - GpuAddressMode::MirrorRepeat => wgpu_types::AddressMode::MirrorRepeat, - } - } -} - -#[derive(Deserialize)] -#[serde(rename_all = "kebab-case")] -enum GpuFilterMode { - Nearest, - Linear, -} - -impl From for wgpu_types::FilterMode { - fn from(value: GpuFilterMode) -> wgpu_types::FilterMode { - match value { - GpuFilterMode::Nearest => wgpu_types::FilterMode::Nearest, - GpuFilterMode::Linear => wgpu_types::FilterMode::Linear, - } - } -} - -#[derive(Deserialize)] -#[serde(rename_all = "kebab-case")] -pub enum GpuCompareFunction { - Never, - Less, - Equal, - LessEqual, - Greater, - NotEqual, - GreaterEqual, - Always, -} - -impl From for wgpu_types::CompareFunction { - fn from(value: GpuCompareFunction) -> wgpu_types::CompareFunction { - match value { - GpuCompareFunction::Never => wgpu_types::CompareFunction::Never, - GpuCompareFunction::Less => wgpu_types::CompareFunction::Less, - GpuCompareFunction::Equal => wgpu_types::CompareFunction::Equal, - GpuCompareFunction::LessEqual => wgpu_types::CompareFunction::LessEqual, - GpuCompareFunction::Greater => wgpu_types::CompareFunction::Greater, - GpuCompareFunction::NotEqual => wgpu_types::CompareFunction::NotEqual, - GpuCompareFunction::GreaterEqual => { - wgpu_types::CompareFunction::GreaterEqual - } - GpuCompareFunction::Always => wgpu_types::CompareFunction::Always, - } - } -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct CreateSamplerArgs { - device_rid: ResourceId, - label: Option, - address_mode_u: GpuAddressMode, - address_mode_v: GpuAddressMode, - address_mode_w: GpuAddressMode, - mag_filter: GpuFilterMode, - min_filter: GpuFilterMode, - mipmap_filter: GpuFilterMode, - lod_min_clamp: f32, - lod_max_clamp: f32, - compare: Option, - max_anisotropy: u8, -} - -pub fn op_webgpu_create_sampler( - state: &mut OpState, - args: CreateSamplerArgs, - _: (), -) -> Result { - let instance = state.borrow::(); - let device_resource = state - .resource_table - .get::(args.device_rid)?; - let device = device_resource.0; - - let descriptor = wgpu_core::resource::SamplerDescriptor { - label: args.label.map(Cow::from), - address_modes: [ - args.address_mode_u.into(), - args.address_mode_v.into(), - args.address_mode_w.into(), - ], - mag_filter: args.mag_filter.into(), - min_filter: args.min_filter.into(), - mipmap_filter: args.mipmap_filter.into(), - lod_min_clamp: args.lod_min_clamp, - lod_max_clamp: args.lod_max_clamp, - compare: args.compare.map(Into::into), - anisotropy_clamp: std::num::NonZeroU8::new(args.max_anisotropy), - border_color: None, // native-only - }; - - gfx_put!(device => instance.device_create_sampler( - device, - &descriptor, - std::marker::PhantomData - ) => state, WebGpuSampler) -} diff --git a/ext/webgpu/shader.rs b/ext/webgpu/shader.rs deleted file mode 100644 index 2477beceb965e5..00000000000000 --- a/ext/webgpu/shader.rs +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. - -use deno_core::error::AnyError; -use deno_core::ResourceId; -use deno_core::{OpState, Resource}; -use serde::Deserialize; -use std::borrow::Cow; - -use super::error::WebGpuResult; - -pub(crate) struct WebGpuShaderModule(pub(crate) wgpu_core::id::ShaderModuleId); -impl Resource for WebGpuShaderModule { - fn name(&self) -> Cow { - "webGPUShaderModule".into() - } -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct CreateShaderModuleArgs { - device_rid: ResourceId, - label: Option, - code: String, - _source_map: Option<()>, // not yet implemented -} - -pub fn op_webgpu_create_shader_module( - state: &mut OpState, - args: CreateShaderModuleArgs, - _: (), -) -> Result { - let instance = state.borrow::(); - let device_resource = state - .resource_table - .get::(args.device_rid)?; - let device = device_resource.0; - - let source = - wgpu_core::pipeline::ShaderModuleSource::Wgsl(Cow::from(args.code)); - - let descriptor = wgpu_core::pipeline::ShaderModuleDescriptor { - label: args.label.map(Cow::from), - }; - - gfx_put!(device => instance.device_create_shader_module( - device, - &descriptor, - source, - std::marker::PhantomData - ) => state, WebGpuShaderModule) -} diff --git a/ext/webgpu/src/binding.rs b/ext/webgpu/src/binding.rs new file mode 100644 index 00000000000000..68915c3531bdcc --- /dev/null +++ b/ext/webgpu/src/binding.rs @@ -0,0 +1,327 @@ +// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. + +use deno_core::error::AnyError; +use deno_core::ResourceId; +use deno_core::{OpState, Resource}; +use serde::Deserialize; +use std::borrow::Cow; +use std::convert::{TryFrom, TryInto}; + +use super::error::WebGpuResult; + +pub(crate) struct WebGpuBindGroupLayout(pub(crate) wgpu_core::id::BindGroupLayoutId); +impl Resource for WebGpuBindGroupLayout { + fn name(&self) -> Cow { + "webGPUBindGroupLayout".into() + } +} + +pub(crate) struct WebGpuBindGroup(pub(crate) wgpu_core::id::BindGroupId); +impl Resource for WebGpuBindGroup { + fn name(&self) -> Cow { + "webGPUBindGroup".into() + } +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +struct GpuBufferBindingLayout { + r#type: GpuBufferBindingType, + has_dynamic_offset: bool, + min_binding_size: u64, +} + +#[derive(Deserialize)] +#[serde(rename_all = "kebab-case")] +enum GpuBufferBindingType { + Uniform, + Storage, + ReadOnlyStorage, +} + +impl From for wgpu_types::BufferBindingType { + fn from(binding_type: GpuBufferBindingType) -> Self { + match binding_type { + GpuBufferBindingType::Uniform => wgpu_types::BufferBindingType::Uniform, + GpuBufferBindingType::Storage => { + wgpu_types::BufferBindingType::Storage { read_only: false } + } + GpuBufferBindingType::ReadOnlyStorage => { + wgpu_types::BufferBindingType::Storage { read_only: true } + } + } + } +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +struct GpuSamplerBindingLayout { + r#type: wgpu_types::SamplerBindingType, +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +struct GpuTextureBindingLayout { + sample_type: GpuTextureSampleType, + view_dimension: wgpu_types::TextureViewDimension, + multisampled: bool, +} + +#[derive(Deserialize)] +#[serde(rename_all = "kebab-case")] +enum GpuTextureSampleType { + Float, + UnfilterableFloat, + Depth, + Sint, + Uint, +} + +impl From for wgpu_types::TextureSampleType { + fn from(sample_type: GpuTextureSampleType) -> Self { + match sample_type { + GpuTextureSampleType::Float => { + wgpu_types::TextureSampleType::Float { filterable: true } + } + GpuTextureSampleType::UnfilterableFloat => { + wgpu_types::TextureSampleType::Float { filterable: false } + } + GpuTextureSampleType::Depth => wgpu_types::TextureSampleType::Depth, + GpuTextureSampleType::Sint => wgpu_types::TextureSampleType::Sint, + GpuTextureSampleType::Uint => wgpu_types::TextureSampleType::Uint, + } + } +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +struct GpuStorageTextureBindingLayout { + access: GpuStorageTextureAccess, + format: wgpu_types::TextureFormat, + view_dimension: wgpu_types::TextureViewDimension, +} + +#[derive(Deserialize)] +#[serde(rename_all = "kebab-case")] +enum GpuStorageTextureAccess { + WriteOnly, +} + +impl From for wgpu_types::StorageTextureAccess { + fn from(access: GpuStorageTextureAccess) -> Self { + match access { + GpuStorageTextureAccess::WriteOnly => wgpu_types::StorageTextureAccess::WriteOnly, + } + } +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +struct GpuBindGroupLayoutEntry { + binding: u32, + visibility: u32, + #[serde(flatten)] + binding_type: GpuBindingType, +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +enum GpuBindingType { + Buffer(GpuBufferBindingLayout), + Sampler(GpuSamplerBindingLayout), + Texture(GpuTextureBindingLayout), + StorageTexture(GpuStorageTextureBindingLayout), +} + +impl TryFrom for wgpu_types::BindingType { + type Error = AnyError; + + fn try_from(binding_type: GpuBindingType) -> Result { + let binding_type = match binding_type { + GpuBindingType::Buffer(buffer) => wgpu_types::BindingType::Buffer { + ty: buffer.r#type.into(), + has_dynamic_offset: buffer.has_dynamic_offset, + min_binding_size: std::num::NonZeroU64::new(buffer.min_binding_size), + }, + GpuBindingType::Sampler(sampler) => wgpu_types::BindingType::Sampler(sampler.r#type), + GpuBindingType::Texture(texture) => wgpu_types::BindingType::Texture { + sample_type: texture.sample_type.into(), + view_dimension: texture.view_dimension, + multisampled: texture.multisampled, + }, + GpuBindingType::StorageTexture(storage_texture) => { + wgpu_types::BindingType::StorageTexture { + access: storage_texture.access.into(), + format: storage_texture.format, + view_dimension: storage_texture.view_dimension, + } + } + }; + Ok(binding_type) + } +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct CreateBindGroupLayoutArgs { + device_rid: ResourceId, + label: Option, + entries: Vec, +} + +pub fn op_webgpu_create_bind_group_layout( + state: &mut OpState, + args: CreateBindGroupLayoutArgs, + _: (), +) -> Result { + let instance = state.borrow::(); + let device_resource = state + .resource_table + .get::(args.device_rid)?; + let device = device_resource.0; + + let mut entries = vec![]; + + for entry in args.entries { + entries.push(wgpu_types::BindGroupLayoutEntry { + binding: entry.binding, + visibility: wgpu_types::ShaderStages::from_bits(entry.visibility).unwrap(), + ty: entry.binding_type.try_into()?, + count: None, // native-only + }); + } + + let descriptor = wgpu_core::binding_model::BindGroupLayoutDescriptor { + label: args.label.map(Cow::from), + entries: Cow::from(entries), + }; + + gfx_put!(device => instance.device_create_bind_group_layout( + device, + &descriptor, + std::marker::PhantomData + ) => state, WebGpuBindGroupLayout) +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct CreatePipelineLayoutArgs { + device_rid: ResourceId, + label: Option, + bind_group_layouts: Vec, +} + +pub fn op_webgpu_create_pipeline_layout( + state: &mut OpState, + args: CreatePipelineLayoutArgs, + _: (), +) -> Result { + let instance = state.borrow::(); + let device_resource = state + .resource_table + .get::(args.device_rid)?; + let device = device_resource.0; + + let mut bind_group_layouts = vec![]; + + for rid in &args.bind_group_layouts { + let bind_group_layout = state.resource_table.get::(*rid)?; + bind_group_layouts.push(bind_group_layout.0); + } + + let descriptor = wgpu_core::binding_model::PipelineLayoutDescriptor { + label: args.label.map(Cow::from), + bind_group_layouts: Cow::from(bind_group_layouts), + push_constant_ranges: Default::default(), + }; + + gfx_put!(device => instance.device_create_pipeline_layout( + device, + &descriptor, + std::marker::PhantomData + ) => state, super::pipeline::WebGpuPipelineLayout) +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +struct GpuBindGroupEntry { + binding: u32, + kind: String, + resource: ResourceId, + offset: Option, + size: Option, +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct CreateBindGroupArgs { + device_rid: ResourceId, + label: Option, + layout: ResourceId, + entries: Vec, +} + +pub fn op_webgpu_create_bind_group( + state: &mut OpState, + args: CreateBindGroupArgs, + _: (), +) -> Result { + let instance = state.borrow::(); + let device_resource = state + .resource_table + .get::(args.device_rid)?; + let device = device_resource.0; + + let mut entries = vec![]; + + for entry in &args.entries { + let e = wgpu_core::binding_model::BindGroupEntry { + binding: entry.binding, + resource: match entry.kind.as_str() { + "GPUSampler" => { + let sampler_resource = state + .resource_table + .get::(entry.resource)?; + wgpu_core::binding_model::BindingResource::Sampler(sampler_resource.0) + } + "GPUTextureView" => { + let texture_view_resource = + state + .resource_table + .get::(entry.resource)?; + wgpu_core::binding_model::BindingResource::TextureView(texture_view_resource.0) + } + "GPUBufferBinding" => { + let buffer_resource = state + .resource_table + .get::(entry.resource)?; + wgpu_core::binding_model::BindingResource::Buffer( + wgpu_core::binding_model::BufferBinding { + buffer_id: buffer_resource.0, + offset: entry.offset.unwrap_or(0), + size: std::num::NonZeroU64::new(entry.size.unwrap_or(0)), + }, + ) + } + _ => unreachable!(), + }, + }; + entries.push(e); + } + + let bind_group_layout = state + .resource_table + .get::(args.layout)?; + + let descriptor = wgpu_core::binding_model::BindGroupDescriptor { + label: args.label.map(Cow::from), + layout: bind_group_layout.0, + entries: Cow::from(entries), + }; + + gfx_put!(device => instance.device_create_bind_group( + device, + &descriptor, + std::marker::PhantomData + ) => state, WebGpuBindGroup) +} diff --git a/ext/webgpu/src/buffer.rs b/ext/webgpu/src/buffer.rs new file mode 100644 index 00000000000000..e93318b2d83df7 --- /dev/null +++ b/ext/webgpu/src/buffer.rs @@ -0,0 +1,223 @@ +// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. + +use deno_core::error::type_error; +use deno_core::error::AnyError; +use deno_core::futures::channel::oneshot; +use deno_core::OpState; +use deno_core::Resource; +use deno_core::ResourceId; +use deno_core::ZeroCopyBuf; +use serde::Deserialize; +use std::borrow::Cow; +use std::cell::RefCell; +use std::rc::Rc; +use std::time::Duration; + +use super::error::DomExceptionOperationError; +use super::error::WebGpuResult; + +pub(crate) struct WebGpuBuffer(pub(crate) wgpu_core::id::BufferId); +impl Resource for WebGpuBuffer { + fn name(&self) -> Cow { + "webGPUBuffer".into() + } +} + +struct WebGpuBufferMapped(*mut u8, usize); +impl Resource for WebGpuBufferMapped { + fn name(&self) -> Cow { + "webGPUBufferMapped".into() + } +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct CreateBufferArgs { + device_rid: ResourceId, + label: Option, + size: u64, + usage: u32, + mapped_at_creation: bool, +} + +pub fn op_webgpu_create_buffer( + state: &mut OpState, + args: CreateBufferArgs, + _: (), +) -> Result { + let instance = state.borrow::(); + let device_resource = state + .resource_table + .get::(args.device_rid)?; + let device = device_resource.0; + + let descriptor = wgpu_core::resource::BufferDescriptor { + label: args.label.map(Cow::from), + size: args.size, + usage: wgpu_types::BufferUsages::from_bits(args.usage) + .ok_or_else(|| type_error("usage is not valid"))?, + mapped_at_creation: args.mapped_at_creation, + }; + + gfx_put!(device => instance.device_create_buffer( + device, + &descriptor, + std::marker::PhantomData + ) => state, WebGpuBuffer) +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct BufferGetMapAsyncArgs { + buffer_rid: ResourceId, + device_rid: ResourceId, + mode: u32, + offset: u64, + size: u64, +} + +pub async fn op_webgpu_buffer_get_map_async( + state: Rc>, + args: BufferGetMapAsyncArgs, + _: (), +) -> Result { + let (sender, receiver) = oneshot::channel::>(); + + let device; + { + let state_ = state.borrow(); + let instance = state_.borrow::(); + let buffer_resource = state_.resource_table.get::(args.buffer_rid)?; + let buffer = buffer_resource.0; + let device_resource = state_ + .resource_table + .get::(args.device_rid)?; + device = device_resource.0; + + let boxed_sender = Box::new(sender); + let sender_ptr = Box::into_raw(boxed_sender) as *mut u8; + + extern "C" fn buffer_map_future_wrapper( + status: wgpu_core::resource::BufferMapAsyncStatus, + user_data: *mut u8, + ) { + let sender_ptr = user_data as *mut oneshot::Sender>; + let boxed_sender = unsafe { Box::from_raw(sender_ptr) }; + boxed_sender + .send(match status { + wgpu_core::resource::BufferMapAsyncStatus::Success => Ok(()), + _ => unreachable!(), // TODO + }) + .unwrap(); + } + + // TODO(lucacasonato): error handling + let maybe_err = gfx_select!(buffer => instance.buffer_map_async( + buffer, + args.offset..(args.offset + args.size), + wgpu_core::resource::BufferMapOperation { + host: match args.mode { + 1 => wgpu_core::device::HostMap::Read, + 2 => wgpu_core::device::HostMap::Write, + _ => unreachable!(), + }, + callback: buffer_map_future_wrapper, + user_data: sender_ptr, + } + )) + .err(); + + if maybe_err.is_some() { + return Ok(WebGpuResult::maybe_err(maybe_err)); + } + } + + let done = Rc::new(RefCell::new(false)); + let done_ = done.clone(); + let device_poll_fut = async move { + while !*done.borrow() { + { + let state = state.borrow(); + let instance = state.borrow::(); + gfx_select!(device => instance.device_poll(device, false)).unwrap() + } + tokio::time::sleep(Duration::from_millis(10)).await; + } + Ok::<(), AnyError>(()) + }; + + let receiver_fut = async move { + receiver.await??; + let mut done = done_.borrow_mut(); + *done = true; + Ok::<(), AnyError>(()) + }; + + tokio::try_join!(device_poll_fut, receiver_fut)?; + + Ok(WebGpuResult::empty()) +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct BufferGetMappedRangeArgs { + buffer_rid: ResourceId, + offset: u64, + size: Option, +} + +pub fn op_webgpu_buffer_get_mapped_range( + state: &mut OpState, + args: BufferGetMappedRangeArgs, + mut zero_copy: ZeroCopyBuf, +) -> Result { + let instance = state.borrow::(); + let buffer_resource = state.resource_table.get::(args.buffer_rid)?; + let buffer = buffer_resource.0; + + let (slice_pointer, range_size) = gfx_select!(buffer => instance.buffer_get_mapped_range( + buffer, + args.offset, + args.size + )) + .map_err(|e| DomExceptionOperationError::new(&e.to_string()))?; + + let slice = unsafe { std::slice::from_raw_parts_mut(slice_pointer, range_size as usize) }; + zero_copy.copy_from_slice(slice); + + let rid = state + .resource_table + .add(WebGpuBufferMapped(slice_pointer, range_size as usize)); + + Ok(WebGpuResult::rid(rid)) +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct BufferUnmapArgs { + buffer_rid: ResourceId, + mapped_rid: ResourceId, +} + +pub fn op_webgpu_buffer_unmap( + state: &mut OpState, + args: BufferUnmapArgs, + zero_copy: Option, +) -> Result { + let mapped_resource = state + .resource_table + .take::(args.mapped_rid)?; + let instance = state.borrow::(); + let buffer_resource = state.resource_table.get::(args.buffer_rid)?; + let buffer = buffer_resource.0; + + let slice_pointer = mapped_resource.0; + let size = mapped_resource.1; + + if let Some(buffer) = zero_copy { + let slice = unsafe { std::slice::from_raw_parts_mut(slice_pointer, size) }; + slice.copy_from_slice(&buffer); + } + + gfx_ok!(buffer => instance.buffer_unmap(buffer)) +} diff --git a/ext/webgpu/src/bundle.rs b/ext/webgpu/src/bundle.rs new file mode 100644 index 00000000000000..541e328f6c2d3d --- /dev/null +++ b/ext/webgpu/src/bundle.rs @@ -0,0 +1,443 @@ +// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. + +use deno_core::error::AnyError; +use deno_core::ResourceId; +use deno_core::ZeroCopyBuf; +use deno_core::{OpState, Resource}; +use serde::Deserialize; +use std::borrow::Cow; +use std::cell::RefCell; +use std::rc::Rc; + +use super::error::WebGpuResult; + +struct WebGpuRenderBundleEncoder(RefCell); +impl Resource for WebGpuRenderBundleEncoder { + fn name(&self) -> Cow { + "webGPURenderBundleEncoder".into() + } +} + +pub(crate) struct WebGpuRenderBundle(pub(crate) wgpu_core::id::RenderBundleId); +impl Resource for WebGpuRenderBundle { + fn name(&self) -> Cow { + "webGPURenderBundle".into() + } +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct CreateRenderBundleEncoderArgs { + device_rid: ResourceId, + label: Option, + color_formats: Vec, + depth_stencil_format: Option, + sample_count: u32, + depth_read_only: bool, + stencil_read_only: bool, +} + +pub fn op_webgpu_create_render_bundle_encoder( + state: &mut OpState, + args: CreateRenderBundleEncoderArgs, + _: (), +) -> Result { + let device_resource = state + .resource_table + .get::(args.device_rid)?; + let device = device_resource.0; + + let mut color_formats = vec![]; + + for format in args.color_formats { + color_formats.push(format); + } + + let depth_stencil = if let Some(format) = args.depth_stencil_format { + Some(wgpu_types::RenderBundleDepthStencil { + format, + depth_read_only: args.depth_read_only, + stencil_read_only: args.stencil_read_only, + }) + } else { + None + }; + + let descriptor = wgpu_core::command::RenderBundleEncoderDescriptor { + label: args.label.map(Cow::from), + color_formats: Cow::from(color_formats), + sample_count: args.sample_count, + depth_stencil, + multiview: None, + }; + + let res = wgpu_core::command::RenderBundleEncoder::new(&descriptor, device, None); + let (render_bundle_encoder, maybe_err) = match res { + Ok(encoder) => (encoder, None), + Err(e) => ( + wgpu_core::command::RenderBundleEncoder::dummy(device), + Some(e), + ), + }; + + let rid = state + .resource_table + .add(WebGpuRenderBundleEncoder(RefCell::new( + render_bundle_encoder, + ))); + + Ok(WebGpuResult::rid_err(rid, maybe_err)) +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct RenderBundleEncoderFinishArgs { + render_bundle_encoder_rid: ResourceId, + label: Option, +} + +pub fn op_webgpu_render_bundle_encoder_finish( + state: &mut OpState, + args: RenderBundleEncoderFinishArgs, + _: (), +) -> Result { + let render_bundle_encoder_resource = state + .resource_table + .take::(args.render_bundle_encoder_rid)?; + let render_bundle_encoder = Rc::try_unwrap(render_bundle_encoder_resource) + .ok() + .expect("unwrapping render_bundle_encoder_resource should succeed") + .0 + .into_inner(); + let instance = state.borrow::(); + + gfx_put!(render_bundle_encoder.parent() => instance.render_bundle_encoder_finish( + render_bundle_encoder, + &wgpu_core::command::RenderBundleDescriptor { + label: args.label.map(Cow::from), + }, + std::marker::PhantomData + ) => state, WebGpuRenderBundle) +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct RenderBundleEncoderSetBindGroupArgs { + render_bundle_encoder_rid: ResourceId, + index: u32, + bind_group: ResourceId, + dynamic_offsets_data: ZeroCopyBuf, + dynamic_offsets_data_start: usize, + dynamic_offsets_data_length: usize, +} + +pub fn op_webgpu_render_bundle_encoder_set_bind_group( + state: &mut OpState, + args: RenderBundleEncoderSetBindGroupArgs, + _: (), +) -> Result { + let bind_group_resource = state + .resource_table + .get::(args.bind_group)?; + let render_bundle_encoder_resource = state + .resource_table + .get::(args.render_bundle_encoder_rid)?; + + // Align the data + assert!(args.dynamic_offsets_data.len() % std::mem::size_of::() == 0); + // SAFETY: A u8 to u32 cast is safe because we asserted that the length is a + // multiple of 4. + let (prefix, dynamic_offsets_data, suffix) = + unsafe { args.dynamic_offsets_data.align_to::() }; + assert!(prefix.is_empty()); + assert!(suffix.is_empty()); + + let start = args.dynamic_offsets_data_start; + let len = args.dynamic_offsets_data_length; + + // Assert that length and start are both in bounds + assert!(start <= dynamic_offsets_data.len()); + assert!(len <= dynamic_offsets_data.len() - start); + + let dynamic_offsets_data: &[u32] = &dynamic_offsets_data[start..start + len]; + + // SAFETY: the raw pointer and length are of the same slice, and that slice + // lives longer than the below function invocation. + unsafe { + wgpu_core::command::bundle_ffi::wgpu_render_bundle_set_bind_group( + &mut render_bundle_encoder_resource.0.borrow_mut(), + args.index, + bind_group_resource.0, + dynamic_offsets_data.as_ptr(), + dynamic_offsets_data.len(), + ); + } + + Ok(WebGpuResult::empty()) +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct RenderBundleEncoderPushDebugGroupArgs { + render_bundle_encoder_rid: ResourceId, + group_label: String, +} + +pub fn op_webgpu_render_bundle_encoder_push_debug_group( + state: &mut OpState, + args: RenderBundleEncoderPushDebugGroupArgs, + _: (), +) -> Result { + let render_bundle_encoder_resource = state + .resource_table + .get::(args.render_bundle_encoder_rid)?; + + let label = std::ffi::CString::new(args.group_label).unwrap(); + // SAFETY: the string the raw pointer points to lives longer than the below + // function invocation. + unsafe { + wgpu_core::command::bundle_ffi::wgpu_render_bundle_push_debug_group( + &mut render_bundle_encoder_resource.0.borrow_mut(), + label.as_ptr(), + ); + } + + Ok(WebGpuResult::empty()) +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct RenderBundleEncoderPopDebugGroupArgs { + render_bundle_encoder_rid: ResourceId, +} + +pub fn op_webgpu_render_bundle_encoder_pop_debug_group( + state: &mut OpState, + args: RenderBundleEncoderPopDebugGroupArgs, + _: (), +) -> Result { + let render_bundle_encoder_resource = state + .resource_table + .get::(args.render_bundle_encoder_rid)?; + + wgpu_core::command::bundle_ffi::wgpu_render_bundle_pop_debug_group( + &mut render_bundle_encoder_resource.0.borrow_mut(), + ); + + Ok(WebGpuResult::empty()) +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct RenderBundleEncoderInsertDebugMarkerArgs { + render_bundle_encoder_rid: ResourceId, + marker_label: String, +} + +pub fn op_webgpu_render_bundle_encoder_insert_debug_marker( + state: &mut OpState, + args: RenderBundleEncoderInsertDebugMarkerArgs, + _: (), +) -> Result { + let render_bundle_encoder_resource = state + .resource_table + .get::(args.render_bundle_encoder_rid)?; + + let label = std::ffi::CString::new(args.marker_label).unwrap(); + // SAFETY: the string the raw pointer points to lives longer than the below + // function invocation. + unsafe { + wgpu_core::command::bundle_ffi::wgpu_render_bundle_insert_debug_marker( + &mut render_bundle_encoder_resource.0.borrow_mut(), + label.as_ptr(), + ); + } + + Ok(WebGpuResult::empty()) +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct RenderBundleEncoderSetPipelineArgs { + render_bundle_encoder_rid: ResourceId, + pipeline: ResourceId, +} + +pub fn op_webgpu_render_bundle_encoder_set_pipeline( + state: &mut OpState, + args: RenderBundleEncoderSetPipelineArgs, + _: (), +) -> Result { + let render_pipeline_resource = state + .resource_table + .get::(args.pipeline)?; + let render_bundle_encoder_resource = state + .resource_table + .get::(args.render_bundle_encoder_rid)?; + + wgpu_core::command::bundle_ffi::wgpu_render_bundle_set_pipeline( + &mut render_bundle_encoder_resource.0.borrow_mut(), + render_pipeline_resource.0, + ); + + Ok(WebGpuResult::empty()) +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct RenderBundleEncoderSetIndexBufferArgs { + render_bundle_encoder_rid: ResourceId, + buffer: ResourceId, + index_format: wgpu_types::IndexFormat, + offset: u64, + size: u64, +} + +pub fn op_webgpu_render_bundle_encoder_set_index_buffer( + state: &mut OpState, + args: RenderBundleEncoderSetIndexBufferArgs, + _: (), +) -> Result { + let buffer_resource = state + .resource_table + .get::(args.buffer)?; + let render_bundle_encoder_resource = state + .resource_table + .get::(args.render_bundle_encoder_rid)?; + + render_bundle_encoder_resource + .0 + .borrow_mut() + .set_index_buffer( + buffer_resource.0, + args.index_format, + args.offset, + std::num::NonZeroU64::new(args.size), + ); + + Ok(WebGpuResult::empty()) +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct RenderBundleEncoderSetVertexBufferArgs { + render_bundle_encoder_rid: ResourceId, + slot: u32, + buffer: ResourceId, + offset: u64, + size: u64, +} + +pub fn op_webgpu_render_bundle_encoder_set_vertex_buffer( + state: &mut OpState, + args: RenderBundleEncoderSetVertexBufferArgs, + _: (), +) -> Result { + let buffer_resource = state + .resource_table + .get::(args.buffer)?; + let render_bundle_encoder_resource = state + .resource_table + .get::(args.render_bundle_encoder_rid)?; + + wgpu_core::command::bundle_ffi::wgpu_render_bundle_set_vertex_buffer( + &mut render_bundle_encoder_resource.0.borrow_mut(), + args.slot, + buffer_resource.0, + args.offset, + std::num::NonZeroU64::new(args.size), + ); + + Ok(WebGpuResult::empty()) +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct RenderBundleEncoderDrawArgs { + render_bundle_encoder_rid: ResourceId, + vertex_count: u32, + instance_count: u32, + first_vertex: u32, + first_instance: u32, +} + +pub fn op_webgpu_render_bundle_encoder_draw( + state: &mut OpState, + args: RenderBundleEncoderDrawArgs, + _: (), +) -> Result { + let render_bundle_encoder_resource = state + .resource_table + .get::(args.render_bundle_encoder_rid)?; + + wgpu_core::command::bundle_ffi::wgpu_render_bundle_draw( + &mut render_bundle_encoder_resource.0.borrow_mut(), + args.vertex_count, + args.instance_count, + args.first_vertex, + args.first_instance, + ); + + Ok(WebGpuResult::empty()) +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct RenderBundleEncoderDrawIndexedArgs { + render_bundle_encoder_rid: ResourceId, + index_count: u32, + instance_count: u32, + first_index: u32, + base_vertex: i32, + first_instance: u32, +} + +pub fn op_webgpu_render_bundle_encoder_draw_indexed( + state: &mut OpState, + args: RenderBundleEncoderDrawIndexedArgs, + _: (), +) -> Result { + let render_bundle_encoder_resource = state + .resource_table + .get::(args.render_bundle_encoder_rid)?; + + wgpu_core::command::bundle_ffi::wgpu_render_bundle_draw_indexed( + &mut render_bundle_encoder_resource.0.borrow_mut(), + args.index_count, + args.instance_count, + args.first_index, + args.base_vertex, + args.first_instance, + ); + + Ok(WebGpuResult::empty()) +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct RenderBundleEncoderDrawIndirectArgs { + render_bundle_encoder_rid: ResourceId, + indirect_buffer: ResourceId, + indirect_offset: u64, +} + +pub fn op_webgpu_render_bundle_encoder_draw_indirect( + state: &mut OpState, + args: RenderBundleEncoderDrawIndirectArgs, + _: (), +) -> Result { + let buffer_resource = state + .resource_table + .get::(args.indirect_buffer)?; + let render_bundle_encoder_resource = state + .resource_table + .get::(args.render_bundle_encoder_rid)?; + + wgpu_core::command::bundle_ffi::wgpu_render_bundle_draw_indirect( + &mut render_bundle_encoder_resource.0.borrow_mut(), + buffer_resource.0, + args.indirect_offset, + ); + + Ok(WebGpuResult::empty()) +} diff --git a/ext/webgpu/src/command_encoder.rs b/ext/webgpu/src/command_encoder.rs new file mode 100644 index 00000000000000..f6e969381d4db1 --- /dev/null +++ b/ext/webgpu/src/command_encoder.rs @@ -0,0 +1,622 @@ +// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. + +use deno_core::error::AnyError; +use deno_core::ResourceId; +use deno_core::{OpState, Resource}; +use serde::Deserialize; +use std::borrow::Cow; +use std::cell::RefCell; +use std::num::NonZeroU32; + +use super::error::WebGpuResult; + +pub(crate) struct WebGpuCommandEncoder(pub(crate) wgpu_core::id::CommandEncoderId); +impl Resource for WebGpuCommandEncoder { + fn name(&self) -> Cow { + "webGPUCommandEncoder".into() + } +} + +pub(crate) struct WebGpuCommandBuffer(pub(crate) wgpu_core::id::CommandBufferId); +impl Resource for WebGpuCommandBuffer { + fn name(&self) -> Cow { + "webGPUCommandBuffer".into() + } +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct CreateCommandEncoderArgs { + device_rid: ResourceId, + label: Option, + _measure_execution_time: Option, // not yet implemented +} + +pub fn op_webgpu_create_command_encoder( + state: &mut OpState, + args: CreateCommandEncoderArgs, + _: (), +) -> Result { + let instance = state.borrow::(); + let device_resource = state + .resource_table + .get::(args.device_rid)?; + let device = device_resource.0; + + let descriptor = wgpu_types::CommandEncoderDescriptor { + label: args.label.map(Cow::from), + }; + + gfx_put!(device => instance.device_create_command_encoder( + device, + &descriptor, + std::marker::PhantomData + ) => state, WebGpuCommandEncoder) +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct GpuRenderPassColorAttachment { + view: ResourceId, + resolve_target: Option, + load_op: GpuLoadOp, + store_op: wgpu_core::command::StoreOp, +} + +#[derive(Deserialize)] +#[serde(rename_all = "kebab-case")] +enum GpuLoadOp { + Load, + Clear(T), +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +struct GpuRenderPassDepthStencilAttachment { + view: ResourceId, + depth_load_op: GpuLoadOp, + depth_store_op: wgpu_core::command::StoreOp, + depth_read_only: bool, + stencil_load_op: GpuLoadOp, + stencil_store_op: wgpu_core::command::StoreOp, + stencil_read_only: bool, +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct CommandEncoderBeginRenderPassArgs { + command_encoder_rid: ResourceId, + label: Option, + color_attachments: Vec, + depth_stencil_attachment: Option, + _occlusion_query_set: Option, // not yet implemented +} + +pub fn op_webgpu_command_encoder_begin_render_pass( + state: &mut OpState, + args: CommandEncoderBeginRenderPassArgs, + _: (), +) -> Result { + let command_encoder_resource = state + .resource_table + .get::(args.command_encoder_rid)?; + + let mut color_attachments = vec![]; + + for color_attachment in args.color_attachments { + let texture_view_resource = state + .resource_table + .get::(color_attachment.view)?; + + let resolve_target = color_attachment + .resolve_target + .map(|rid| { + state + .resource_table + .get::(rid) + }) + .transpose()? + .map(|texture| texture.0); + + let attachment = wgpu_core::command::RenderPassColorAttachment { + view: texture_view_resource.0, + resolve_target, + channel: match color_attachment.load_op { + GpuLoadOp::Load => wgpu_core::command::PassChannel { + load_op: wgpu_core::command::LoadOp::Load, + store_op: color_attachment.store_op, + clear_value: Default::default(), + read_only: false, + }, + GpuLoadOp::Clear(color) => wgpu_core::command::PassChannel { + load_op: wgpu_core::command::LoadOp::Clear, + store_op: color_attachment.store_op, + clear_value: color, + read_only: false, + }, + }, + }; + + color_attachments.push(attachment) + } + + let mut depth_stencil_attachment = None; + + if let Some(attachment) = args.depth_stencil_attachment { + let texture_view_resource = state + .resource_table + .get::(attachment.view)?; + + depth_stencil_attachment = Some(wgpu_core::command::RenderPassDepthStencilAttachment { + view: texture_view_resource.0, + depth: match attachment.depth_load_op { + GpuLoadOp::Load => wgpu_core::command::PassChannel { + load_op: wgpu_core::command::LoadOp::Load, + store_op: attachment.depth_store_op, + clear_value: 0.0, + read_only: attachment.depth_read_only, + }, + GpuLoadOp::Clear(value) => wgpu_core::command::PassChannel { + load_op: wgpu_core::command::LoadOp::Clear, + store_op: attachment.depth_store_op, + clear_value: value, + read_only: attachment.depth_read_only, + }, + }, + stencil: match attachment.stencil_load_op { + GpuLoadOp::Load => wgpu_core::command::PassChannel { + load_op: wgpu_core::command::LoadOp::Load, + store_op: attachment.stencil_store_op, + clear_value: 0, + read_only: attachment.stencil_read_only, + }, + GpuLoadOp::Clear(value) => wgpu_core::command::PassChannel { + load_op: wgpu_core::command::LoadOp::Clear, + store_op: attachment.stencil_store_op, + clear_value: value, + read_only: attachment.stencil_read_only, + }, + }, + }); + } + + let descriptor = wgpu_core::command::RenderPassDescriptor { + label: args.label.map(Cow::from), + color_attachments: Cow::from(color_attachments), + depth_stencil_attachment: depth_stencil_attachment.as_ref(), + }; + + let render_pass = wgpu_core::command::RenderPass::new(command_encoder_resource.0, &descriptor); + + let rid = state + .resource_table + .add(super::render_pass::WebGpuRenderPass(RefCell::new( + render_pass, + ))); + + Ok(WebGpuResult::rid(rid)) +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct CommandEncoderBeginComputePassArgs { + command_encoder_rid: ResourceId, + label: Option, +} + +pub fn op_webgpu_command_encoder_begin_compute_pass( + state: &mut OpState, + args: CommandEncoderBeginComputePassArgs, + _: (), +) -> Result { + let command_encoder_resource = state + .resource_table + .get::(args.command_encoder_rid)?; + + let descriptor = wgpu_core::command::ComputePassDescriptor { + label: args.label.map(Cow::from), + }; + + let compute_pass = + wgpu_core::command::ComputePass::new(command_encoder_resource.0, &descriptor); + + let rid = state + .resource_table + .add(super::compute_pass::WebGpuComputePass(RefCell::new( + compute_pass, + ))); + + Ok(WebGpuResult::rid(rid)) +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct CommandEncoderCopyBufferToBufferArgs { + command_encoder_rid: ResourceId, + source: ResourceId, + source_offset: u64, + destination: ResourceId, + destination_offset: u64, + size: u64, +} + +pub fn op_webgpu_command_encoder_copy_buffer_to_buffer( + state: &mut OpState, + args: CommandEncoderCopyBufferToBufferArgs, + _: (), +) -> Result { + let instance = state.borrow::(); + let command_encoder_resource = state + .resource_table + .get::(args.command_encoder_rid)?; + let command_encoder = command_encoder_resource.0; + let source_buffer_resource = state + .resource_table + .get::(args.source)?; + let source_buffer = source_buffer_resource.0; + let destination_buffer_resource = state + .resource_table + .get::(args.destination)?; + let destination_buffer = destination_buffer_resource.0; + + gfx_ok!(command_encoder => instance.command_encoder_copy_buffer_to_buffer( + command_encoder, + source_buffer, + args.source_offset, + destination_buffer, + args.destination_offset, + args.size + )) +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct GpuImageCopyBuffer { + buffer: ResourceId, + offset: u64, + bytes_per_row: Option, + rows_per_image: Option, +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct GpuImageCopyTexture { + pub texture: ResourceId, + pub mip_level: u32, + pub origin: wgpu_types::Origin3d, + pub aspect: wgpu_types::TextureAspect, +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct CommandEncoderCopyBufferToTextureArgs { + command_encoder_rid: ResourceId, + source: GpuImageCopyBuffer, + destination: GpuImageCopyTexture, + copy_size: wgpu_types::Extent3d, +} + +pub fn op_webgpu_command_encoder_copy_buffer_to_texture( + state: &mut OpState, + args: CommandEncoderCopyBufferToTextureArgs, + _: (), +) -> Result { + let instance = state.borrow::(); + let command_encoder_resource = state + .resource_table + .get::(args.command_encoder_rid)?; + let command_encoder = command_encoder_resource.0; + let source_buffer_resource = state + .resource_table + .get::(args.source.buffer)?; + let destination_texture_resource = state + .resource_table + .get::(args.destination.texture)?; + + let source = wgpu_core::command::ImageCopyBuffer { + buffer: source_buffer_resource.0, + layout: wgpu_types::ImageDataLayout { + offset: args.source.offset, + bytes_per_row: NonZeroU32::new(args.source.bytes_per_row.unwrap_or(0)), + rows_per_image: NonZeroU32::new(args.source.rows_per_image.unwrap_or(0)), + }, + }; + let destination = wgpu_core::command::ImageCopyTexture { + texture: destination_texture_resource.0, + mip_level: args.destination.mip_level, + origin: args.destination.origin, + aspect: args.destination.aspect, + }; + gfx_ok!(command_encoder => instance.command_encoder_copy_buffer_to_texture( + command_encoder, + &source, + &destination, + &args.copy_size + )) +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct CommandEncoderCopyTextureToBufferArgs { + command_encoder_rid: ResourceId, + source: GpuImageCopyTexture, + destination: GpuImageCopyBuffer, + copy_size: wgpu_types::Extent3d, +} + +pub fn op_webgpu_command_encoder_copy_texture_to_buffer( + state: &mut OpState, + args: CommandEncoderCopyTextureToBufferArgs, + _: (), +) -> Result { + let instance = state.borrow::(); + let command_encoder_resource = state + .resource_table + .get::(args.command_encoder_rid)?; + let command_encoder = command_encoder_resource.0; + let source_texture_resource = state + .resource_table + .get::(args.source.texture)?; + let destination_buffer_resource = state + .resource_table + .get::(args.destination.buffer)?; + + let source = wgpu_core::command::ImageCopyTexture { + texture: source_texture_resource.0, + mip_level: args.source.mip_level, + origin: args.source.origin, + aspect: args.source.aspect, + }; + let destination = wgpu_core::command::ImageCopyBuffer { + buffer: destination_buffer_resource.0, + layout: wgpu_types::ImageDataLayout { + offset: args.destination.offset, + bytes_per_row: NonZeroU32::new(args.destination.bytes_per_row.unwrap_or(0)), + rows_per_image: NonZeroU32::new(args.destination.rows_per_image.unwrap_or(0)), + }, + }; + gfx_ok!(command_encoder => instance.command_encoder_copy_texture_to_buffer( + command_encoder, + &source, + &destination, + &args.copy_size + )) +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct CommandEncoderCopyTextureToTextureArgs { + command_encoder_rid: ResourceId, + source: GpuImageCopyTexture, + destination: GpuImageCopyTexture, + copy_size: wgpu_types::Extent3d, +} + +pub fn op_webgpu_command_encoder_copy_texture_to_texture( + state: &mut OpState, + args: CommandEncoderCopyTextureToTextureArgs, + _: (), +) -> Result { + let instance = state.borrow::(); + let command_encoder_resource = state + .resource_table + .get::(args.command_encoder_rid)?; + let command_encoder = command_encoder_resource.0; + let source_texture_resource = state + .resource_table + .get::(args.source.texture)?; + let destination_texture_resource = state + .resource_table + .get::(args.destination.texture)?; + + let source = wgpu_core::command::ImageCopyTexture { + texture: source_texture_resource.0, + mip_level: args.source.mip_level, + origin: args.source.origin, + aspect: args.source.aspect, + }; + let destination = wgpu_core::command::ImageCopyTexture { + texture: destination_texture_resource.0, + mip_level: args.destination.mip_level, + origin: args.destination.origin, + aspect: args.destination.aspect, + }; + gfx_ok!(command_encoder => instance.command_encoder_copy_texture_to_texture( + command_encoder, + &source, + &destination, + &args.copy_size + )) +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct CommandEncoderClearBufferArgs { + command_encoder_rid: u32, + destination_rid: u32, + destination_offset: u64, + size: u64, +} + +pub fn op_webgpu_command_encoder_clear_buffer( + state: &mut OpState, + args: CommandEncoderClearBufferArgs, + _: (), +) -> Result { + let instance = state.borrow::(); + let command_encoder_resource = state + .resource_table + .get::(args.command_encoder_rid)?; + let command_encoder = command_encoder_resource.0; + let destination_resource = state + .resource_table + .get::(args.destination_rid)?; + + gfx_ok!(command_encoder => instance.command_encoder_clear_buffer( + command_encoder, + destination_resource.0, + args.destination_offset, + std::num::NonZeroU64::new(args.size) + )) +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct CommandEncoderPushDebugGroupArgs { + command_encoder_rid: ResourceId, + group_label: String, +} + +pub fn op_webgpu_command_encoder_push_debug_group( + state: &mut OpState, + args: CommandEncoderPushDebugGroupArgs, + _: (), +) -> Result { + let instance = state.borrow::(); + let command_encoder_resource = state + .resource_table + .get::(args.command_encoder_rid)?; + let command_encoder = command_encoder_resource.0; + + gfx_ok!(command_encoder => instance + .command_encoder_push_debug_group(command_encoder, &args.group_label)) +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct CommandEncoderPopDebugGroupArgs { + command_encoder_rid: ResourceId, +} + +pub fn op_webgpu_command_encoder_pop_debug_group( + state: &mut OpState, + args: CommandEncoderPopDebugGroupArgs, + _: (), +) -> Result { + let instance = state.borrow::(); + let command_encoder_resource = state + .resource_table + .get::(args.command_encoder_rid)?; + let command_encoder = command_encoder_resource.0; + + gfx_ok!(command_encoder => instance.command_encoder_pop_debug_group(command_encoder)) +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct CommandEncoderInsertDebugMarkerArgs { + command_encoder_rid: ResourceId, + marker_label: String, +} + +pub fn op_webgpu_command_encoder_insert_debug_marker( + state: &mut OpState, + args: CommandEncoderInsertDebugMarkerArgs, + _: (), +) -> Result { + let instance = state.borrow::(); + let command_encoder_resource = state + .resource_table + .get::(args.command_encoder_rid)?; + let command_encoder = command_encoder_resource.0; + + gfx_ok!(command_encoder => instance.command_encoder_insert_debug_marker( + command_encoder, + &args.marker_label + )) +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct CommandEncoderWriteTimestampArgs { + command_encoder_rid: ResourceId, + query_set: ResourceId, + query_index: u32, +} + +pub fn op_webgpu_command_encoder_write_timestamp( + state: &mut OpState, + args: CommandEncoderWriteTimestampArgs, + _: (), +) -> Result { + let instance = state.borrow::(); + let command_encoder_resource = state + .resource_table + .get::(args.command_encoder_rid)?; + let command_encoder = command_encoder_resource.0; + let query_set_resource = state + .resource_table + .get::(args.query_set)?; + + gfx_ok!(command_encoder => instance.command_encoder_write_timestamp( + command_encoder, + query_set_resource.0, + args.query_index + )) +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct CommandEncoderResolveQuerySetArgs { + command_encoder_rid: ResourceId, + query_set: ResourceId, + first_query: u32, + query_count: u32, + destination: ResourceId, + destination_offset: u64, +} + +pub fn op_webgpu_command_encoder_resolve_query_set( + state: &mut OpState, + args: CommandEncoderResolveQuerySetArgs, + _: (), +) -> Result { + let instance = state.borrow::(); + let command_encoder_resource = state + .resource_table + .get::(args.command_encoder_rid)?; + let command_encoder = command_encoder_resource.0; + let query_set_resource = state + .resource_table + .get::(args.query_set)?; + let destination_resource = state + .resource_table + .get::(args.destination)?; + + gfx_ok!(command_encoder => instance.command_encoder_resolve_query_set( + command_encoder, + query_set_resource.0, + args.first_query, + args.query_count, + destination_resource.0, + args.destination_offset + )) +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct CommandEncoderFinishArgs { + command_encoder_rid: ResourceId, + label: Option, +} + +pub fn op_webgpu_command_encoder_finish( + state: &mut OpState, + args: CommandEncoderFinishArgs, + _: (), +) -> Result { + let command_encoder_resource = state + .resource_table + .take::(args.command_encoder_rid)?; + let command_encoder = command_encoder_resource.0; + let instance = state.borrow::(); + + let descriptor = wgpu_types::CommandBufferDescriptor { + label: args.label.map(Cow::from), + }; + + gfx_put!(command_encoder => instance.command_encoder_finish( + command_encoder, + &descriptor + ) => state, WebGpuCommandBuffer) +} diff --git a/ext/webgpu/src/compute_pass.rs b/ext/webgpu/src/compute_pass.rs new file mode 100644 index 00000000000000..cd3b088949ed07 --- /dev/null +++ b/ext/webgpu/src/compute_pass.rs @@ -0,0 +1,349 @@ +// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. + +use deno_core::error::AnyError; +use deno_core::ResourceId; +use deno_core::ZeroCopyBuf; +use deno_core::{OpState, Resource}; +use serde::Deserialize; +use std::borrow::Cow; +use std::cell::RefCell; + +use super::error::WebGpuResult; + +pub(crate) struct WebGpuComputePass(pub(crate) RefCell); +impl Resource for WebGpuComputePass { + fn name(&self) -> Cow { + "webGPUComputePass".into() + } +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ComputePassSetPipelineArgs { + compute_pass_rid: ResourceId, + pipeline: ResourceId, +} + +pub fn op_webgpu_compute_pass_set_pipeline( + state: &mut OpState, + args: ComputePassSetPipelineArgs, + _: (), +) -> Result { + let compute_pipeline_resource = state + .resource_table + .get::(args.pipeline)?; + let compute_pass_resource = state + .resource_table + .get::(args.compute_pass_rid)?; + + wgpu_core::command::compute_ffi::wgpu_compute_pass_set_pipeline( + &mut compute_pass_resource.0.borrow_mut(), + compute_pipeline_resource.0, + ); + + Ok(WebGpuResult::empty()) +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ComputePassDispatchArgs { + compute_pass_rid: ResourceId, + x: u32, + y: u32, + z: u32, +} + +pub fn op_webgpu_compute_pass_dispatch( + state: &mut OpState, + args: ComputePassDispatchArgs, + _: (), +) -> Result { + let compute_pass_resource = state + .resource_table + .get::(args.compute_pass_rid)?; + + wgpu_core::command::compute_ffi::wgpu_compute_pass_dispatch( + &mut compute_pass_resource.0.borrow_mut(), + args.x, + args.y, + args.z, + ); + + Ok(WebGpuResult::empty()) +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ComputePassDispatchIndirectArgs { + compute_pass_rid: ResourceId, + indirect_buffer: ResourceId, + indirect_offset: u64, +} + +pub fn op_webgpu_compute_pass_dispatch_indirect( + state: &mut OpState, + args: ComputePassDispatchIndirectArgs, + _: (), +) -> Result { + let buffer_resource = state + .resource_table + .get::(args.indirect_buffer)?; + let compute_pass_resource = state + .resource_table + .get::(args.compute_pass_rid)?; + + wgpu_core::command::compute_ffi::wgpu_compute_pass_dispatch_indirect( + &mut compute_pass_resource.0.borrow_mut(), + buffer_resource.0, + args.indirect_offset, + ); + + Ok(WebGpuResult::empty()) +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ComputePassBeginPipelineStatisticsQueryArgs { + compute_pass_rid: ResourceId, + query_set: ResourceId, + query_index: u32, +} + +pub fn op_webgpu_compute_pass_begin_pipeline_statistics_query( + state: &mut OpState, + args: ComputePassBeginPipelineStatisticsQueryArgs, + _: (), +) -> Result { + let compute_pass_resource = state + .resource_table + .get::(args.compute_pass_rid)?; + let query_set_resource = state + .resource_table + .get::(args.query_set)?; + + wgpu_core::command::compute_ffi::wgpu_compute_pass_begin_pipeline_statistics_query( + &mut compute_pass_resource.0.borrow_mut(), + query_set_resource.0, + args.query_index, + ); + + Ok(WebGpuResult::empty()) +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ComputePassEndPipelineStatisticsQueryArgs { + compute_pass_rid: ResourceId, +} + +pub fn op_webgpu_compute_pass_end_pipeline_statistics_query( + state: &mut OpState, + args: ComputePassEndPipelineStatisticsQueryArgs, + _: (), +) -> Result { + let compute_pass_resource = state + .resource_table + .get::(args.compute_pass_rid)?; + + wgpu_core::command::compute_ffi::wgpu_compute_pass_end_pipeline_statistics_query( + &mut compute_pass_resource.0.borrow_mut(), + ); + + Ok(WebGpuResult::empty()) +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ComputePassWriteTimestampArgs { + compute_pass_rid: ResourceId, + query_set: ResourceId, + query_index: u32, +} + +pub fn op_webgpu_compute_pass_write_timestamp( + state: &mut OpState, + args: ComputePassWriteTimestampArgs, + _: (), +) -> Result { + let compute_pass_resource = state + .resource_table + .get::(args.compute_pass_rid)?; + let query_set_resource = state + .resource_table + .get::(args.query_set)?; + + wgpu_core::command::compute_ffi::wgpu_compute_pass_write_timestamp( + &mut compute_pass_resource.0.borrow_mut(), + query_set_resource.0, + args.query_index, + ); + + Ok(WebGpuResult::empty()) +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ComputePassEndPassArgs { + command_encoder_rid: ResourceId, + compute_pass_rid: ResourceId, +} + +pub fn op_webgpu_compute_pass_end_pass( + state: &mut OpState, + args: ComputePassEndPassArgs, + _: (), +) -> Result { + let command_encoder_resource = + state + .resource_table + .get::(args.command_encoder_rid)?; + let command_encoder = command_encoder_resource.0; + let compute_pass_resource = state + .resource_table + .take::(args.compute_pass_rid)?; + let compute_pass = &compute_pass_resource.0.borrow(); + let instance = state.borrow::(); + + gfx_ok!(command_encoder => instance.command_encoder_run_compute_pass( + command_encoder, + compute_pass + )) +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ComputePassSetBindGroupArgs { + compute_pass_rid: ResourceId, + index: u32, + bind_group: ResourceId, + dynamic_offsets_data: ZeroCopyBuf, + dynamic_offsets_data_start: usize, + dynamic_offsets_data_length: usize, +} + +pub fn op_webgpu_compute_pass_set_bind_group( + state: &mut OpState, + args: ComputePassSetBindGroupArgs, + _: (), +) -> Result { + let bind_group_resource = state + .resource_table + .get::(args.bind_group)?; + let compute_pass_resource = state + .resource_table + .get::(args.compute_pass_rid)?; + + // Align the data + assert!(args.dynamic_offsets_data_start % std::mem::size_of::() == 0); + // SAFETY: A u8 to u32 cast is safe because we asserted that the length is a + // multiple of 4. + let (prefix, dynamic_offsets_data, suffix) = + unsafe { args.dynamic_offsets_data.align_to::() }; + assert!(prefix.is_empty()); + assert!(suffix.is_empty()); + + let start = args.dynamic_offsets_data_start; + let len = args.dynamic_offsets_data_length; + + // Assert that length and start are both in bounds + assert!(start <= dynamic_offsets_data.len()); + assert!(len <= dynamic_offsets_data.len() - start); + + let dynamic_offsets_data: &[u32] = &dynamic_offsets_data[start..start + len]; + + // SAFETY: the raw pointer and length are of the same slice, and that slice + // lives longer than the below function invocation. + unsafe { + wgpu_core::command::compute_ffi::wgpu_compute_pass_set_bind_group( + &mut compute_pass_resource.0.borrow_mut(), + args.index, + bind_group_resource.0, + dynamic_offsets_data.as_ptr(), + dynamic_offsets_data.len(), + ); + } + + Ok(WebGpuResult::empty()) +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ComputePassPushDebugGroupArgs { + compute_pass_rid: ResourceId, + group_label: String, +} + +pub fn op_webgpu_compute_pass_push_debug_group( + state: &mut OpState, + args: ComputePassPushDebugGroupArgs, + _: (), +) -> Result { + let compute_pass_resource = state + .resource_table + .get::(args.compute_pass_rid)?; + + let label = std::ffi::CString::new(args.group_label).unwrap(); + // SAFETY: the string the raw pointer points to lives longer than the below + // function invocation. + unsafe { + wgpu_core::command::compute_ffi::wgpu_compute_pass_push_debug_group( + &mut compute_pass_resource.0.borrow_mut(), + label.as_ptr(), + 0, // wgpu#975 + ); + } + + Ok(WebGpuResult::empty()) +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ComputePassPopDebugGroupArgs { + compute_pass_rid: ResourceId, +} + +pub fn op_webgpu_compute_pass_pop_debug_group( + state: &mut OpState, + args: ComputePassPopDebugGroupArgs, + _: (), +) -> Result { + let compute_pass_resource = state + .resource_table + .get::(args.compute_pass_rid)?; + + wgpu_core::command::compute_ffi::wgpu_compute_pass_pop_debug_group( + &mut compute_pass_resource.0.borrow_mut(), + ); + + Ok(WebGpuResult::empty()) +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ComputePassInsertDebugMarkerArgs { + compute_pass_rid: ResourceId, + marker_label: String, +} + +pub fn op_webgpu_compute_pass_insert_debug_marker( + state: &mut OpState, + args: ComputePassInsertDebugMarkerArgs, + _: (), +) -> Result { + let compute_pass_resource = state + .resource_table + .get::(args.compute_pass_rid)?; + + let label = std::ffi::CString::new(args.marker_label).unwrap(); + // SAFETY: the string the raw pointer points to lives longer than the below + // function invocation. + unsafe { + wgpu_core::command::compute_ffi::wgpu_compute_pass_insert_debug_marker( + &mut compute_pass_resource.0.borrow_mut(), + label.as_ptr(), + 0, // wgpu#975 + ); + } + + Ok(WebGpuResult::empty()) +} diff --git a/ext/webgpu/src/error.rs b/ext/webgpu/src/error.rs new file mode 100644 index 00000000000000..26d7f7b24617a5 --- /dev/null +++ b/ext/webgpu/src/error.rs @@ -0,0 +1,289 @@ +// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. +use deno_core::error::AnyError; +use deno_core::ResourceId; +use serde::Serialize; +use std::convert::From; +use std::fmt; +use wgpu_core::binding_model::CreateBindGroupError; +use wgpu_core::binding_model::CreateBindGroupLayoutError; +use wgpu_core::binding_model::CreatePipelineLayoutError; +use wgpu_core::binding_model::GetBindGroupLayoutError; +use wgpu_core::command::ClearError; +use wgpu_core::command::CommandEncoderError; +use wgpu_core::command::ComputePassError; +use wgpu_core::command::CopyError; +use wgpu_core::command::CreateRenderBundleError; +use wgpu_core::command::QueryError; +use wgpu_core::command::RenderBundleError; +use wgpu_core::command::RenderPassError; +use wgpu_core::device::queue::QueueSubmitError; +use wgpu_core::device::queue::QueueWriteError; +use wgpu_core::device::DeviceError; +use wgpu_core::pipeline::CreateComputePipelineError; +use wgpu_core::pipeline::CreateRenderPipelineError; +use wgpu_core::pipeline::CreateShaderModuleError; +use wgpu_core::resource::BufferAccessError; +use wgpu_core::resource::CreateBufferError; +use wgpu_core::resource::CreateQuerySetError; +use wgpu_core::resource::CreateSamplerError; +use wgpu_core::resource::CreateTextureError; +use wgpu_core::resource::CreateTextureViewError; + +#[derive(Serialize)] +pub struct WebGpuResult { + pub rid: Option, + pub err: Option, +} + +impl WebGpuResult { + pub fn rid(rid: ResourceId) -> Self { + Self { + rid: Some(rid), + err: None, + } + } + + pub fn rid_err>(rid: ResourceId, err: Option) -> Self { + Self { + rid: Some(rid), + err: err.map(|e| e.into()), + } + } + + pub fn maybe_err>(err: Option) -> Self { + Self { + rid: None, + err: err.map(|e| e.into()), + } + } + + pub fn empty() -> Self { + Self { + rid: None, + err: None, + } + } +} + +#[derive(Serialize)] +#[serde(tag = "type", content = "value")] +#[serde(rename_all = "kebab-case")] +pub enum WebGpuError { + Lost, + OutOfMemory, + Validation(String), +} + +impl From for WebGpuError { + fn from(err: CreateBufferError) -> Self { + match err { + CreateBufferError::Device(err) => err.into(), + CreateBufferError::AccessError(err) => err.into(), + err => WebGpuError::Validation(err.to_string()), + } + } +} + +impl From for WebGpuError { + fn from(err: DeviceError) -> Self { + match err { + DeviceError::Lost => WebGpuError::Lost, + DeviceError::OutOfMemory => WebGpuError::OutOfMemory, + DeviceError::Invalid => WebGpuError::Validation(err.to_string()), + } + } +} + +impl From for WebGpuError { + fn from(err: BufferAccessError) -> Self { + match err { + BufferAccessError::Device(err) => err.into(), + err => WebGpuError::Validation(err.to_string()), + } + } +} + +impl From for WebGpuError { + fn from(err: CreateBindGroupLayoutError) -> Self { + match err { + CreateBindGroupLayoutError::Device(err) => err.into(), + err => WebGpuError::Validation(err.to_string()), + } + } +} + +impl From for WebGpuError { + fn from(err: CreatePipelineLayoutError) -> Self { + match err { + CreatePipelineLayoutError::Device(err) => err.into(), + err => WebGpuError::Validation(err.to_string()), + } + } +} + +impl From for WebGpuError { + fn from(err: CreateBindGroupError) -> Self { + match err { + CreateBindGroupError::Device(err) => err.into(), + err => WebGpuError::Validation(err.to_string()), + } + } +} + +impl From for WebGpuError { + fn from(err: RenderBundleError) -> Self { + WebGpuError::Validation(err.to_string()) + } +} + +impl From for WebGpuError { + fn from(err: CreateRenderBundleError) -> Self { + WebGpuError::Validation(err.to_string()) + } +} + +impl From for WebGpuError { + fn from(err: CopyError) -> Self { + WebGpuError::Validation(err.to_string()) + } +} + +impl From for WebGpuError { + fn from(err: CommandEncoderError) -> Self { + WebGpuError::Validation(err.to_string()) + } +} + +impl From for WebGpuError { + fn from(err: QueryError) -> Self { + WebGpuError::Validation(err.to_string()) + } +} + +impl From for WebGpuError { + fn from(err: ComputePassError) -> Self { + WebGpuError::Validation(err.to_string()) + } +} + +impl From for WebGpuError { + fn from(err: CreateComputePipelineError) -> Self { + match err { + CreateComputePipelineError::Device(err) => err.into(), + err => WebGpuError::Validation(err.to_string()), + } + } +} + +impl From for WebGpuError { + fn from(err: GetBindGroupLayoutError) -> Self { + WebGpuError::Validation(err.to_string()) + } +} + +impl From for WebGpuError { + fn from(err: CreateRenderPipelineError) -> Self { + match err { + CreateRenderPipelineError::Device(err) => err.into(), + err => WebGpuError::Validation(err.to_string()), + } + } +} + +impl From for WebGpuError { + fn from(err: RenderPassError) -> Self { + WebGpuError::Validation(err.to_string()) + } +} + +impl From for WebGpuError { + fn from(err: CreateSamplerError) -> Self { + match err { + CreateSamplerError::Device(err) => err.into(), + err => WebGpuError::Validation(err.to_string()), + } + } +} + +impl From for WebGpuError { + fn from(err: CreateShaderModuleError) -> Self { + match err { + CreateShaderModuleError::Device(err) => err.into(), + err => WebGpuError::Validation(err.to_string()), + } + } +} + +impl From for WebGpuError { + fn from(err: CreateTextureError) -> Self { + match err { + CreateTextureError::Device(err) => err.into(), + err => WebGpuError::Validation(err.to_string()), + } + } +} + +impl From for WebGpuError { + fn from(err: CreateTextureViewError) -> Self { + WebGpuError::Validation(err.to_string()) + } +} + +impl From for WebGpuError { + fn from(err: CreateQuerySetError) -> Self { + match err { + CreateQuerySetError::Device(err) => err.into(), + err => WebGpuError::Validation(err.to_string()), + } + } +} + +impl From for WebGpuError { + fn from(err: QueueSubmitError) -> Self { + match err { + QueueSubmitError::Queue(err) => err.into(), + err => WebGpuError::Validation(err.to_string()), + } + } +} + +impl From for WebGpuError { + fn from(err: QueueWriteError) -> Self { + match err { + QueueWriteError::Queue(err) => err.into(), + err => WebGpuError::Validation(err.to_string()), + } + } +} + +impl From for WebGpuError { + fn from(err: ClearError) -> Self { + WebGpuError::Validation(err.to_string()) + } +} + +#[derive(Debug)] +pub struct DomExceptionOperationError { + pub msg: String, +} + +impl DomExceptionOperationError { + pub fn new(msg: &str) -> Self { + DomExceptionOperationError { + msg: msg.to_string(), + } + } +} + +impl fmt::Display for DomExceptionOperationError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad(&self.msg) + } +} + +impl std::error::Error for DomExceptionOperationError {} + +pub fn get_error_class_name(e: &AnyError) -> Option<&'static str> { + e.downcast_ref::() + .map(|_| "DOMExceptionOperationError") +} diff --git a/ext/webgpu/src/lib.rs b/ext/webgpu/src/lib.rs new file mode 100644 index 00000000000000..db5ac1a8cf9204 --- /dev/null +++ b/ext/webgpu/src/lib.rs @@ -0,0 +1,888 @@ +// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. + +use deno_core::error::AnyError; +use deno_core::include_js_files; +use deno_core::op_async; +use deno_core::op_sync; +use deno_core::Extension; +use deno_core::OpFn; +use deno_core::OpState; +use deno_core::Resource; +use deno_core::ResourceId; +use serde::Deserialize; +use serde::Serialize; +use std::borrow::Cow; +use std::cell::RefCell; +use std::collections::HashSet; +use std::rc::Rc; +pub use wgpu_core; +pub use wgpu_types; +use wgpu_types::PowerPreference; + +use error::DomExceptionOperationError; +use error::WebGpuResult; + +#[macro_use] +mod macros { + macro_rules! gfx_select { + ($id:expr => $global:ident.$method:ident( $($param:expr),* )) => { + match $id.backend() { + #[cfg(not(target_os = "macos"))] + wgpu_types::Backend::Vulkan => $global.$method::( $($param),* ), + #[cfg(target_os = "macos")] + wgpu_types::Backend::Metal => $global.$method::( $($param),* ), + #[cfg(windows)] + wgpu_types::Backend::Dx12 => $global.$method::( $($param),* ), + #[cfg(all(unix, not(target_os = "macos")))] + wgpu_types::Backend::Gl => $global.$method::( $($param),+ ), + other => panic!("Unexpected backend {:?}", other), + } + }; + } + + macro_rules! gfx_put { + ($id:expr => $global:ident.$method:ident( $($param:expr),* ) => $state:expr, $rc:expr) => {{ + let (val, maybe_err) = gfx_select!($id => $global.$method($($param),*)); + let rid = $state.resource_table.add($rc(val)); + Ok(WebGpuResult::rid_err(rid, maybe_err)) + }}; + } + + macro_rules! gfx_ok { + ($id:expr => $global:ident.$method:ident( $($param:expr),* )) => {{ + let maybe_err = gfx_select!($id => $global.$method($($param),*)).err(); + Ok(WebGpuResult::maybe_err(maybe_err)) + }}; + } +} + +pub mod binding; +pub mod buffer; +pub mod bundle; +pub mod command_encoder; +pub mod compute_pass; +pub mod error; +pub mod pipeline; +pub mod queue; +pub mod render_pass; +pub mod sampler; +pub mod shader; +pub mod texture; + +pub struct Unstable(pub bool); + +fn check_unstable(state: &OpState, api_name: &str) { + let unstable = state.borrow::(); + if !unstable.0 { + eprintln!( + "Unstable API '{}'. The --unstable flag must be provided.", + api_name + ); + std::process::exit(70); + } +} + +type Instance = wgpu_core::hub::Global; + +struct WebGpuAdapter(wgpu_core::id::AdapterId); +impl Resource for WebGpuAdapter { + fn name(&self) -> Cow { + "webGPUAdapter".into() + } +} + +struct WebGpuDevice(wgpu_core::id::DeviceId); +impl Resource for WebGpuDevice { + fn name(&self) -> Cow { + "webGPUDevice".into() + } +} + +struct WebGpuQuerySet(wgpu_core::id::QuerySetId); +impl Resource for WebGpuQuerySet { + fn name(&self) -> Cow { + "webGPUQuerySet".into() + } +} + +pub fn init(unstable: bool) -> Extension { + Extension::builder() + .js(include_js_files!( + prefix "deno:deno_webgpu", + "01_webgpu.js", + "02_idl_types.js", + )) + .ops(declare_webgpu_ops()) + .state(move |state| { + // TODO: check & possibly streamline this + // Unstable might be able to be OpMiddleware + // let unstable_checker = state.borrow::(); + // let unstable = unstable_checker.unstable; + state.put(Unstable(unstable)); + Ok(()) + }) + .build() +} + +fn deserialize_features(features: &wgpu_types::Features) -> Vec<&'static str> { + let mut return_features: Vec<&'static str> = vec![]; + + if features.contains(wgpu_types::Features::DEPTH_CLIP_CONTROL) { + return_features.push("depth-clip-control"); + } + if features.contains(wgpu_types::Features::PIPELINE_STATISTICS_QUERY) { + return_features.push("pipeline-statistics-query"); + } + if features.contains(wgpu_types::Features::TEXTURE_COMPRESSION_BC) { + return_features.push("texture-compression-bc"); + } + if features.contains(wgpu_types::Features::TEXTURE_COMPRESSION_ETC2) { + return_features.push("texture-compression-etc2"); + } + if features.contains(wgpu_types::Features::TEXTURE_COMPRESSION_ASTC_LDR) { + return_features.push("texture-compression-astc"); + } + if features.contains(wgpu_types::Features::TIMESTAMP_QUERY) { + return_features.push("timestamp-query"); + } + if features.contains(wgpu_types::Features::INDIRECT_FIRST_INSTANCE) { + return_features.push("indirect-first-instance"); + } + + // extended from spec + if features.contains(wgpu_types::Features::MAPPABLE_PRIMARY_BUFFERS) { + return_features.push("mappable-primary-buffers"); + } + if features.contains(wgpu_types::Features::TEXTURE_BINDING_ARRAY) { + return_features.push("texture-binding-array"); + } + if features.contains(wgpu_types::Features::BUFFER_BINDING_ARRAY) { + return_features.push("buffer-binding-array"); + } + if features.contains(wgpu_types::Features::STORAGE_RESOURCE_BINDING_ARRAY) { + return_features.push("storage-resource-binding-array"); + } + if features.contains( + wgpu_types::Features::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING, + ) { + return_features.push("sampled-texture-and-storage-buffer-array-non-uniform-indexing"); + } + if features.contains( + wgpu_types::Features::UNIFORM_BUFFER_AND_STORAGE_TEXTURE_ARRAY_NON_UNIFORM_INDEXING, + ) { + return_features.push("uniform-buffer-and-storage-buffer-texture-non-uniform-indexing"); + } + if features.contains(wgpu_types::Features::UNSIZED_BINDING_ARRAY) { + return_features.push("unsized-binding-array"); + } + if features.contains(wgpu_types::Features::MULTI_DRAW_INDIRECT) { + return_features.push("multi-draw-indirect"); + } + if features.contains(wgpu_types::Features::MULTI_DRAW_INDIRECT_COUNT) { + return_features.push("multi-draw-indirect-count"); + } + if features.contains(wgpu_types::Features::PUSH_CONSTANTS) { + return_features.push("push-constants"); + } + if features.contains(wgpu_types::Features::ADDRESS_MODE_CLAMP_TO_BORDER) { + return_features.push("address-mode-clamp-to-border"); + } + if features.contains(wgpu_types::Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES) { + return_features.push("texture-adapter-specific-format-features"); + } + if features.contains(wgpu_types::Features::SHADER_FLOAT64) { + return_features.push("shader-float64"); + } + if features.contains(wgpu_types::Features::VERTEX_ATTRIBUTE_64BIT) { + return_features.push("vertex-attribute-64bit"); + } + if features.contains(wgpu_types::Features::CONSERVATIVE_RASTERIZATION) { + return_features.push("conservative-rasterization"); + } + if features.contains(wgpu_types::Features::VERTEX_WRITABLE_STORAGE) { + return_features.push("vertex-writable-storage"); + } + if features.contains(wgpu_types::Features::CLEAR_COMMANDS) { + return_features.push("clear-commands"); + } + if features.contains(wgpu_types::Features::SPIRV_SHADER_PASSTHROUGH) { + return_features.push("spirv-shader-passthrough"); + } + if features.contains(wgpu_types::Features::SHADER_PRIMITIVE_INDEX) { + return_features.push("shader-primitive-index"); + } + + return_features +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct RequestAdapterArgs { + power_preference: Option, + force_fallback_adapter: bool, +} + +#[derive(Serialize)] +#[serde(untagged)] +pub enum GpuAdapterDeviceOrErr { + Error { err: String }, + Features(GpuAdapterDevice), +} + +#[derive(Serialize)] +#[serde(rename_all = "camelCase")] +pub struct GpuAdapterDevice { + rid: ResourceId, + name: Option, + limits: wgpu_types::Limits, + features: Vec<&'static str>, + is_software: bool, +} + +pub async fn op_webgpu_request_adapter( + state: Rc>, + args: RequestAdapterArgs, + _: (), +) -> Result { + let mut state = state.borrow_mut(); + check_unstable(&state, "navigator.gpu.requestAdapter"); + let backends = std::env::var("DENO_WEBGPU_BACKEND") + .ok() + .map_or_else(wgpu_types::Backends::all, |s| { + wgpu_core::instance::parse_backends_from_comma_list(&s) + }); + let instance = if let Some(instance) = state.try_borrow::() { + instance + } else { + state.put(wgpu_core::hub::Global::new( + "webgpu", + wgpu_core::hub::IdentityManagerFactory, + backends, + )); + state.borrow::() + }; + + let descriptor = wgpu_core::instance::RequestAdapterOptions { + power_preference: match args.power_preference { + Some(power_preference) => power_preference.into(), + None => PowerPreference::default(), + }, + force_fallback_adapter: args.force_fallback_adapter, + compatible_surface: None, // windowless + }; + let res = instance.request_adapter( + &descriptor, + wgpu_core::instance::AdapterInputs::Mask(backends, |_| std::marker::PhantomData), + ); + + let adapter = match res { + Ok(adapter) => adapter, + Err(err) => { + return Ok(GpuAdapterDeviceOrErr::Error { + err: err.to_string(), + }) + } + }; + let name = gfx_select!(adapter => instance.adapter_get_info(adapter))?.name; + let adapter_features = gfx_select!(adapter => instance.adapter_features(adapter))?; + let features = deserialize_features(&adapter_features); + let adapter_limits = gfx_select!(adapter => instance.adapter_limits(adapter))?; + + let rid = state.resource_table.add(WebGpuAdapter(adapter)); + + Ok(GpuAdapterDeviceOrErr::Features(GpuAdapterDevice { + rid, + name: Some(name), + features, + limits: adapter_limits, + is_software: false, + })) +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct RequestDeviceArgs { + adapter_rid: ResourceId, + label: Option, + required_features: Option, + required_limits: Option, +} + +#[derive(Deserialize)] +pub struct GpuRequiredFeatures(HashSet); + +impl From for wgpu_types::Features { + fn from(required_features: GpuRequiredFeatures) -> wgpu_types::Features { + let mut features: wgpu_types::Features = wgpu_types::Features::empty(); + features.set( + wgpu_types::Features::DEPTH_CLIP_CONTROL, + required_features.0.contains("depth-clip-control"), + ); + features.set( + wgpu_types::Features::PIPELINE_STATISTICS_QUERY, + required_features.0.contains("pipeline-statistics-query"), + ); + features.set( + wgpu_types::Features::TEXTURE_COMPRESSION_BC, + required_features.0.contains("texture-compression-bc"), + ); + features.set( + wgpu_types::Features::TEXTURE_COMPRESSION_ETC2, + required_features.0.contains("texture-compression-etc2"), + ); + features.set( + wgpu_types::Features::TEXTURE_COMPRESSION_ASTC_LDR, + required_features.0.contains("texture-compression-astc"), + ); + features.set( + wgpu_types::Features::TIMESTAMP_QUERY, + required_features.0.contains("timestamp-query"), + ); + features.set( + wgpu_types::Features::INDIRECT_FIRST_INSTANCE, + required_features.0.contains("indirect-first-instance"), + ); + + // extended from spec + features.set( + wgpu_types::Features::MAPPABLE_PRIMARY_BUFFERS, + required_features.0.contains("mappable-primary-buffers"), + ); + features.set( + wgpu_types::Features::TEXTURE_BINDING_ARRAY, + required_features.0.contains("texture-binding-array"), + ); + features.set( + wgpu_types::Features::BUFFER_BINDING_ARRAY, + required_features.0.contains("buffer-binding-array"), + ); + features.set( + wgpu_types::Features::STORAGE_RESOURCE_BINDING_ARRAY, + required_features + .0 + .contains("storage-resource-binding-array"), + ); + features.set( + wgpu_types::Features::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING, + required_features + .0 + .contains("sampled-texture-and-storage-buffer-array-non-uniform-indexing"), + ); + features.set( + wgpu_types::Features::UNIFORM_BUFFER_AND_STORAGE_TEXTURE_ARRAY_NON_UNIFORM_INDEXING, + required_features + .0 + .contains("uniform-buffer-and-storage-buffer-texture-non-uniform-indexing"), + ); + features.set( + wgpu_types::Features::UNSIZED_BINDING_ARRAY, + required_features.0.contains("unsized-binding-array"), + ); + features.set( + wgpu_types::Features::MULTI_DRAW_INDIRECT, + required_features.0.contains("multi-draw-indirect"), + ); + features.set( + wgpu_types::Features::MULTI_DRAW_INDIRECT_COUNT, + required_features.0.contains("multi-draw-indirect-count"), + ); + features.set( + wgpu_types::Features::PUSH_CONSTANTS, + required_features.0.contains("push-constants"), + ); + features.set( + wgpu_types::Features::ADDRESS_MODE_CLAMP_TO_BORDER, + required_features.0.contains("address-mode-clamp-to-border"), + ); + features.set( + wgpu_types::Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES, + required_features + .0 + .contains("texture-adapter-specific-format-features"), + ); + features.set( + wgpu_types::Features::SHADER_FLOAT64, + required_features.0.contains("shader-float64"), + ); + features.set( + wgpu_types::Features::VERTEX_ATTRIBUTE_64BIT, + required_features.0.contains("vertex-attribute-64bit"), + ); + features.set( + wgpu_types::Features::CONSERVATIVE_RASTERIZATION, + required_features.0.contains("conservative-rasterization"), + ); + features.set( + wgpu_types::Features::VERTEX_WRITABLE_STORAGE, + required_features.0.contains("vertex-writable-storage"), + ); + features.set( + wgpu_types::Features::CLEAR_COMMANDS, + required_features.0.contains("clear-commands"), + ); + features.set( + wgpu_types::Features::SPIRV_SHADER_PASSTHROUGH, + required_features.0.contains("spirv-shader-passthrough"), + ); + features.set( + wgpu_types::Features::SHADER_PRIMITIVE_INDEX, + required_features.0.contains("shader-primitive-index"), + ); + + features + } +} + +pub async fn op_webgpu_request_device( + state: Rc>, + args: RequestDeviceArgs, + _: (), +) -> Result { + let mut state = state.borrow_mut(); + let adapter_resource = state + .resource_table + .get::(args.adapter_rid)?; + let adapter = adapter_resource.0; + let instance = state.borrow::(); + + let descriptor = wgpu_types::DeviceDescriptor { + label: args.label.map(Cow::from), + features: args.required_features.map(Into::into).unwrap_or_default(), + limits: args.required_limits.map(Into::into).unwrap_or_default(), + }; + + let (device, maybe_err) = gfx_select!(adapter => instance.adapter_request_device( + adapter, + &descriptor, + std::env::var("DENO_WEBGPU_TRACE").ok().as_ref().map(std::path::Path::new), + std::marker::PhantomData + )); + if let Some(err) = maybe_err { + return Err(DomExceptionOperationError::new(&err.to_string()).into()); + } + + let device_features = gfx_select!(device => instance.device_features(device))?; + let features = deserialize_features(&device_features); + let limits = gfx_select!(device => instance.device_limits(device))?; + + let rid = state.resource_table.add(WebGpuDevice(device)); + + Ok(GpuAdapterDevice { + rid, + name: None, + features, + limits, + // TODO(lucacasonato): report correctly from wgpu + is_software: false, + }) +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct CreateQuerySetArgs { + device_rid: ResourceId, + label: Option, + #[serde(flatten)] + r#type: GpuQueryType, + count: u32, +} + +#[derive(Deserialize)] +#[serde(rename_all = "kebab-case", tag = "type")] +enum GpuQueryType { + Occlusion, + #[serde(rename_all = "camelCase")] + PipelineStatistics { + pipeline_statistics: HashSet, + }, + Timestamp, +} + +impl From for wgpu_types::QueryType { + fn from(query_type: GpuQueryType) -> Self { + match query_type { + GpuQueryType::Occlusion => wgpu_types::QueryType::Occlusion, + GpuQueryType::PipelineStatistics { + pipeline_statistics, + } => { + use wgpu_types::PipelineStatisticsTypes; + + let mut types = PipelineStatisticsTypes::empty(); + + if pipeline_statistics.contains("vertex-shader-invocations") { + types.set(PipelineStatisticsTypes::VERTEX_SHADER_INVOCATIONS, true); + } + if pipeline_statistics.contains("clipper-invocations") { + types.set(PipelineStatisticsTypes::CLIPPER_INVOCATIONS, true); + } + if pipeline_statistics.contains("clipper-primitives-out") { + types.set(PipelineStatisticsTypes::CLIPPER_PRIMITIVES_OUT, true); + } + if pipeline_statistics.contains("fragment-shader-invocations") { + types.set(PipelineStatisticsTypes::FRAGMENT_SHADER_INVOCATIONS, true); + } + if pipeline_statistics.contains("compute-shader-invocations") { + types.set(PipelineStatisticsTypes::COMPUTE_SHADER_INVOCATIONS, true); + } + + wgpu_types::QueryType::PipelineStatistics(types) + } + GpuQueryType::Timestamp => wgpu_types::QueryType::Timestamp, + } + } +} + +pub fn op_webgpu_create_query_set( + state: &mut OpState, + args: CreateQuerySetArgs, + _: (), +) -> Result { + let device_resource = state.resource_table.get::(args.device_rid)?; + let device = device_resource.0; + let instance = &state.borrow::(); + + let descriptor = wgpu_types::QuerySetDescriptor { + label: args.label.map(Cow::from), + ty: args.r#type.into(), + count: args.count, + }; + + gfx_put!(device => instance.device_create_query_set( + device, + &descriptor, + std::marker::PhantomData + ) => state, WebGpuQuerySet) +} + +fn declare_webgpu_ops() -> Vec<(&'static str, Box)> { + vec![ + // Request device/adapter + ( + "op_webgpu_request_adapter", + op_async(op_webgpu_request_adapter), + ), + ( + "op_webgpu_request_device", + op_async(op_webgpu_request_device), + ), + // Query Set + ( + "op_webgpu_create_query_set", + op_sync(op_webgpu_create_query_set), + ), + // buffer + ( + "op_webgpu_create_buffer", + op_sync(buffer::op_webgpu_create_buffer), + ), + ( + "op_webgpu_buffer_get_mapped_range", + op_sync(buffer::op_webgpu_buffer_get_mapped_range), + ), + ( + "op_webgpu_buffer_unmap", + op_sync(buffer::op_webgpu_buffer_unmap), + ), + // buffer async + ( + "op_webgpu_buffer_get_map_async", + op_async(buffer::op_webgpu_buffer_get_map_async), + ), + // remaining sync ops + + // texture + ( + "op_webgpu_create_texture", + op_sync(texture::op_webgpu_create_texture), + ), + ( + "op_webgpu_create_texture_view", + op_sync(texture::op_webgpu_create_texture_view), + ), + // sampler + ( + "op_webgpu_create_sampler", + op_sync(sampler::op_webgpu_create_sampler), + ), + // binding + ( + "op_webgpu_create_bind_group_layout", + op_sync(binding::op_webgpu_create_bind_group_layout), + ), + ( + "op_webgpu_create_pipeline_layout", + op_sync(binding::op_webgpu_create_pipeline_layout), + ), + ( + "op_webgpu_create_bind_group", + op_sync(binding::op_webgpu_create_bind_group), + ), + // pipeline + ( + "op_webgpu_create_compute_pipeline", + op_sync(pipeline::op_webgpu_create_compute_pipeline), + ), + ( + "op_webgpu_compute_pipeline_get_bind_group_layout", + op_sync(pipeline::op_webgpu_compute_pipeline_get_bind_group_layout), + ), + ( + "op_webgpu_create_render_pipeline", + op_sync(pipeline::op_webgpu_create_render_pipeline), + ), + ( + "op_webgpu_render_pipeline_get_bind_group_layout", + op_sync(pipeline::op_webgpu_render_pipeline_get_bind_group_layout), + ), + // command_encoder + ( + "op_webgpu_create_command_encoder", + op_sync(command_encoder::op_webgpu_create_command_encoder), + ), + ( + "op_webgpu_command_encoder_begin_render_pass", + op_sync(command_encoder::op_webgpu_command_encoder_begin_render_pass), + ), + ( + "op_webgpu_command_encoder_begin_compute_pass", + op_sync(command_encoder::op_webgpu_command_encoder_begin_compute_pass), + ), + ( + "op_webgpu_command_encoder_copy_buffer_to_buffer", + op_sync(command_encoder::op_webgpu_command_encoder_copy_buffer_to_buffer), + ), + ( + "op_webgpu_command_encoder_copy_buffer_to_texture", + op_sync(command_encoder::op_webgpu_command_encoder_copy_buffer_to_texture), + ), + ( + "op_webgpu_command_encoder_copy_texture_to_buffer", + op_sync(command_encoder::op_webgpu_command_encoder_copy_texture_to_buffer), + ), + ( + "op_webgpu_command_encoder_copy_texture_to_texture", + op_sync(command_encoder::op_webgpu_command_encoder_copy_texture_to_texture), + ), + ( + "op_webgpu_command_encoder_clear_buffer", + op_sync(command_encoder::op_webgpu_command_encoder_clear_buffer), + ), + ( + "op_webgpu_command_encoder_push_debug_group", + op_sync(command_encoder::op_webgpu_command_encoder_push_debug_group), + ), + ( + "op_webgpu_command_encoder_pop_debug_group", + op_sync(command_encoder::op_webgpu_command_encoder_pop_debug_group), + ), + ( + "op_webgpu_command_encoder_insert_debug_marker", + op_sync(command_encoder::op_webgpu_command_encoder_insert_debug_marker), + ), + ( + "op_webgpu_command_encoder_write_timestamp", + op_sync(command_encoder::op_webgpu_command_encoder_write_timestamp), + ), + ( + "op_webgpu_command_encoder_resolve_query_set", + op_sync(command_encoder::op_webgpu_command_encoder_resolve_query_set), + ), + ( + "op_webgpu_command_encoder_finish", + op_sync(command_encoder::op_webgpu_command_encoder_finish), + ), + // render_pass + ( + "op_webgpu_render_pass_set_viewport", + op_sync(render_pass::op_webgpu_render_pass_set_viewport), + ), + ( + "op_webgpu_render_pass_set_scissor_rect", + op_sync(render_pass::op_webgpu_render_pass_set_scissor_rect), + ), + ( + "op_webgpu_render_pass_set_blend_constant", + op_sync(render_pass::op_webgpu_render_pass_set_blend_constant), + ), + ( + "op_webgpu_render_pass_set_stencil_reference", + op_sync(render_pass::op_webgpu_render_pass_set_stencil_reference), + ), + ( + "op_webgpu_render_pass_begin_pipeline_statistics_query", + op_sync(render_pass::op_webgpu_render_pass_begin_pipeline_statistics_query), + ), + ( + "op_webgpu_render_pass_end_pipeline_statistics_query", + op_sync(render_pass::op_webgpu_render_pass_end_pipeline_statistics_query), + ), + ( + "op_webgpu_render_pass_write_timestamp", + op_sync(render_pass::op_webgpu_render_pass_write_timestamp), + ), + ( + "op_webgpu_render_pass_execute_bundles", + op_sync(render_pass::op_webgpu_render_pass_execute_bundles), + ), + ( + "op_webgpu_render_pass_end_pass", + op_sync(render_pass::op_webgpu_render_pass_end_pass), + ), + ( + "op_webgpu_render_pass_set_bind_group", + op_sync(render_pass::op_webgpu_render_pass_set_bind_group), + ), + ( + "op_webgpu_render_pass_push_debug_group", + op_sync(render_pass::op_webgpu_render_pass_push_debug_group), + ), + ( + "op_webgpu_render_pass_pop_debug_group", + op_sync(render_pass::op_webgpu_render_pass_pop_debug_group), + ), + ( + "op_webgpu_render_pass_insert_debug_marker", + op_sync(render_pass::op_webgpu_render_pass_insert_debug_marker), + ), + ( + "op_webgpu_render_pass_set_pipeline", + op_sync(render_pass::op_webgpu_render_pass_set_pipeline), + ), + ( + "op_webgpu_render_pass_set_index_buffer", + op_sync(render_pass::op_webgpu_render_pass_set_index_buffer), + ), + ( + "op_webgpu_render_pass_set_vertex_buffer", + op_sync(render_pass::op_webgpu_render_pass_set_vertex_buffer), + ), + ( + "op_webgpu_render_pass_draw", + op_sync(render_pass::op_webgpu_render_pass_draw), + ), + ( + "op_webgpu_render_pass_draw_indexed", + op_sync(render_pass::op_webgpu_render_pass_draw_indexed), + ), + ( + "op_webgpu_render_pass_draw_indirect", + op_sync(render_pass::op_webgpu_render_pass_draw_indirect), + ), + ( + "op_webgpu_render_pass_draw_indexed_indirect", + op_sync(render_pass::op_webgpu_render_pass_draw_indexed_indirect), + ), + // compute_pass + ( + "op_webgpu_compute_pass_set_pipeline", + op_sync(compute_pass::op_webgpu_compute_pass_set_pipeline), + ), + ( + "op_webgpu_compute_pass_dispatch", + op_sync(compute_pass::op_webgpu_compute_pass_dispatch), + ), + ( + "op_webgpu_compute_pass_dispatch_indirect", + op_sync(compute_pass::op_webgpu_compute_pass_dispatch_indirect), + ), + ( + "op_webgpu_compute_pass_begin_pipeline_statistics_query", + op_sync(compute_pass::op_webgpu_compute_pass_begin_pipeline_statistics_query), + ), + ( + "op_webgpu_compute_pass_end_pipeline_statistics_query", + op_sync(compute_pass::op_webgpu_compute_pass_end_pipeline_statistics_query), + ), + ( + "op_webgpu_compute_pass_write_timestamp", + op_sync(compute_pass::op_webgpu_compute_pass_write_timestamp), + ), + ( + "op_webgpu_compute_pass_end_pass", + op_sync(compute_pass::op_webgpu_compute_pass_end_pass), + ), + ( + "op_webgpu_compute_pass_set_bind_group", + op_sync(compute_pass::op_webgpu_compute_pass_set_bind_group), + ), + ( + "op_webgpu_compute_pass_push_debug_group", + op_sync(compute_pass::op_webgpu_compute_pass_push_debug_group), + ), + ( + "op_webgpu_compute_pass_pop_debug_group", + op_sync(compute_pass::op_webgpu_compute_pass_pop_debug_group), + ), + ( + "op_webgpu_compute_pass_insert_debug_marker", + op_sync(compute_pass::op_webgpu_compute_pass_insert_debug_marker), + ), + // bundle + ( + "op_webgpu_create_render_bundle_encoder", + op_sync(bundle::op_webgpu_create_render_bundle_encoder), + ), + ( + "op_webgpu_render_bundle_encoder_finish", + op_sync(bundle::op_webgpu_render_bundle_encoder_finish), + ), + ( + "op_webgpu_render_bundle_encoder_set_bind_group", + op_sync(bundle::op_webgpu_render_bundle_encoder_set_bind_group), + ), + ( + "op_webgpu_render_bundle_encoder_push_debug_group", + op_sync(bundle::op_webgpu_render_bundle_encoder_push_debug_group), + ), + ( + "op_webgpu_render_bundle_encoder_pop_debug_group", + op_sync(bundle::op_webgpu_render_bundle_encoder_pop_debug_group), + ), + ( + "op_webgpu_render_bundle_encoder_insert_debug_marker", + op_sync(bundle::op_webgpu_render_bundle_encoder_insert_debug_marker), + ), + ( + "op_webgpu_render_bundle_encoder_set_pipeline", + op_sync(bundle::op_webgpu_render_bundle_encoder_set_pipeline), + ), + ( + "op_webgpu_render_bundle_encoder_set_index_buffer", + op_sync(bundle::op_webgpu_render_bundle_encoder_set_index_buffer), + ), + ( + "op_webgpu_render_bundle_encoder_set_vertex_buffer", + op_sync(bundle::op_webgpu_render_bundle_encoder_set_vertex_buffer), + ), + ( + "op_webgpu_render_bundle_encoder_draw", + op_sync(bundle::op_webgpu_render_bundle_encoder_draw), + ), + ( + "op_webgpu_render_bundle_encoder_draw_indexed", + op_sync(bundle::op_webgpu_render_bundle_encoder_draw_indexed), + ), + ( + "op_webgpu_render_bundle_encoder_draw_indirect", + op_sync(bundle::op_webgpu_render_bundle_encoder_draw_indirect), + ), + // queue + ( + "op_webgpu_queue_submit", + op_sync(queue::op_webgpu_queue_submit), + ), + ( + "op_webgpu_write_buffer", + op_sync(queue::op_webgpu_write_buffer), + ), + ( + "op_webgpu_write_texture", + op_sync(queue::op_webgpu_write_texture), + ), + // shader + ( + "op_webgpu_create_shader_module", + op_sync(shader::op_webgpu_create_shader_module), + ), + ] +} diff --git a/ext/webgpu/src/pipeline.rs b/ext/webgpu/src/pipeline.rs new file mode 100644 index 00000000000000..106f8d0bce9d09 --- /dev/null +++ b/ext/webgpu/src/pipeline.rs @@ -0,0 +1,418 @@ +// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. + +use deno_core::error::AnyError; +use deno_core::ResourceId; +use deno_core::{OpState, Resource}; +use serde::Deserialize; +use serde::Serialize; +use std::borrow::Cow; +use std::convert::{TryFrom, TryInto}; + +use super::error::WebGpuError; +use super::error::WebGpuResult; + +const MAX_BIND_GROUPS: usize = 8; + +pub(crate) struct WebGpuPipelineLayout(pub(crate) wgpu_core::id::PipelineLayoutId); +impl Resource for WebGpuPipelineLayout { + fn name(&self) -> Cow { + "webGPUPipelineLayout".into() + } +} + +pub(crate) struct WebGpuComputePipeline(pub(crate) wgpu_core::id::ComputePipelineId); +impl Resource for WebGpuComputePipeline { + fn name(&self) -> Cow { + "webGPUComputePipeline".into() + } +} + +pub(crate) struct WebGpuRenderPipeline(pub(crate) wgpu_core::id::RenderPipelineId); +impl Resource for WebGpuRenderPipeline { + fn name(&self) -> Cow { + "webGPURenderPipeline".into() + } +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +struct GpuProgrammableStage { + module: ResourceId, + entry_point: String, + // constants: HashMap +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct CreateComputePipelineArgs { + device_rid: ResourceId, + label: Option, + layout: Option, + compute: GpuProgrammableStage, +} + +pub fn op_webgpu_create_compute_pipeline( + state: &mut OpState, + args: CreateComputePipelineArgs, + _: (), +) -> Result { + let instance = state.borrow::(); + let device_resource = state + .resource_table + .get::(args.device_rid)?; + let device = device_resource.0; + + let pipeline_layout = if let Some(rid) = args.layout { + let id = state.resource_table.get::(rid)?; + Some(id.0) + } else { + None + }; + + let compute_shader_module_resource = state + .resource_table + .get::(args.compute.module)?; + + let descriptor = wgpu_core::pipeline::ComputePipelineDescriptor { + label: args.label.map(Cow::from), + layout: pipeline_layout, + stage: wgpu_core::pipeline::ProgrammableStageDescriptor { + module: compute_shader_module_resource.0, + entry_point: Cow::from(args.compute.entry_point), + // TODO(lucacasonato): support args.compute.constants + }, + }; + let implicit_pipelines = match args.layout { + Some(_) => None, + None => Some(wgpu_core::device::ImplicitPipelineIds { + root_id: std::marker::PhantomData, + group_ids: &[std::marker::PhantomData; MAX_BIND_GROUPS], + }), + }; + + let (compute_pipeline, maybe_err) = gfx_select!(device => instance.device_create_compute_pipeline( + device, + &descriptor, + std::marker::PhantomData, + implicit_pipelines + )); + + let rid = state + .resource_table + .add(WebGpuComputePipeline(compute_pipeline)); + + Ok(WebGpuResult::rid_err(rid, maybe_err)) +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ComputePipelineGetBindGroupLayoutArgs { + compute_pipeline_rid: ResourceId, + index: u32, +} + +#[derive(Serialize)] +#[serde(rename_all = "camelCase")] +pub struct PipelineLayout { + rid: ResourceId, + label: String, + err: Option, +} + +pub fn op_webgpu_compute_pipeline_get_bind_group_layout( + state: &mut OpState, + args: ComputePipelineGetBindGroupLayoutArgs, + _: (), +) -> Result { + let instance = state.borrow::(); + let compute_pipeline_resource = state + .resource_table + .get::(args.compute_pipeline_rid)?; + let compute_pipeline = compute_pipeline_resource.0; + + let (bind_group_layout, maybe_err) = gfx_select!(compute_pipeline => instance.compute_pipeline_get_bind_group_layout(compute_pipeline, args.index, std::marker::PhantomData)); + + let label = + gfx_select!(bind_group_layout => instance.bind_group_layout_label(bind_group_layout)); + + let rid = state + .resource_table + .add(super::binding::WebGpuBindGroupLayout(bind_group_layout)); + + Ok(PipelineLayout { + rid, + label, + err: maybe_err.map(WebGpuError::from), + }) +} + +#[derive(Deserialize)] +#[serde(rename_all = "kebab-case")] +pub enum GpuCullMode { + None, + Front, + Back, +} + +impl From for Option { + fn from(value: GpuCullMode) -> Option { + match value { + GpuCullMode::None => None, + GpuCullMode::Front => Some(wgpu_types::Face::Front), + GpuCullMode::Back => Some(wgpu_types::Face::Back), + } + } +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +struct GpuPrimitiveState { + topology: wgpu_types::PrimitiveTopology, + strip_index_format: Option, + front_face: wgpu_types::FrontFace, + cull_mode: GpuCullMode, + unclipped_depth: bool, +} + +impl From for wgpu_types::PrimitiveState { + fn from(value: GpuPrimitiveState) -> wgpu_types::PrimitiveState { + wgpu_types::PrimitiveState { + topology: value.topology, + strip_index_format: value.strip_index_format, + front_face: value.front_face, + cull_mode: value.cull_mode.into(), + unclipped_depth: value.unclipped_depth, + polygon_mode: Default::default(), // native-only + conservative: false, // native-only + } + } +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +struct GpuDepthStencilState { + format: wgpu_types::TextureFormat, + depth_write_enabled: bool, + depth_compare: wgpu_types::CompareFunction, + stencil_front: wgpu_types::StencilFaceState, + stencil_back: wgpu_types::StencilFaceState, + stencil_read_mask: u32, + stencil_write_mask: u32, + depth_bias: i32, + depth_bias_slope_scale: f32, + depth_bias_clamp: f32, +} + +impl TryFrom for wgpu_types::DepthStencilState { + type Error = AnyError; + fn try_from(state: GpuDepthStencilState) -> Result { + Ok(wgpu_types::DepthStencilState { + format: state.format, + depth_write_enabled: state.depth_write_enabled, + depth_compare: state.depth_compare.into(), + stencil: wgpu_types::StencilState { + front: state.stencil_front.into(), + back: state.stencil_back.into(), + read_mask: state.stencil_read_mask, + write_mask: state.stencil_write_mask, + }, + bias: wgpu_types::DepthBiasState { + constant: state.depth_bias, + slope_scale: state.depth_bias_slope_scale, + clamp: state.depth_bias_clamp, + }, + }) + } +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +struct GpuVertexBufferLayout { + array_stride: u64, + step_mode: wgpu_types::VertexStepMode, + attributes: Vec, +} + +impl<'a> From for wgpu_core::pipeline::VertexBufferLayout<'a> { + fn from(layout: GpuVertexBufferLayout) -> wgpu_core::pipeline::VertexBufferLayout<'a> { + wgpu_core::pipeline::VertexBufferLayout { + array_stride: layout.array_stride, + step_mode: layout.step_mode, + attributes: Cow::Owned(layout.attributes), + } + } +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +struct GpuVertexState { + module: ResourceId, + entry_point: String, + buffers: Vec>, +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +struct GpuMultisampleState { + count: u32, + mask: u64, + alpha_to_coverage_enabled: bool, +} + +impl From for wgpu_types::MultisampleState { + fn from(gms: GpuMultisampleState) -> wgpu_types::MultisampleState { + wgpu_types::MultisampleState { + count: gms.count, + mask: gms.mask, + alpha_to_coverage_enabled: gms.alpha_to_coverage_enabled, + } + } +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +struct GpuFragmentState { + targets: Vec, + module: u32, + entry_point: String, + // TODO(lucacasonato): constants +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct CreateRenderPipelineArgs { + device_rid: ResourceId, + label: Option, + layout: Option, + vertex: GpuVertexState, + primitive: GpuPrimitiveState, + depth_stencil: Option, + multisample: wgpu_types::MultisampleState, + fragment: Option, +} + +pub fn op_webgpu_create_render_pipeline( + state: &mut OpState, + args: CreateRenderPipelineArgs, + _: (), +) -> Result { + let instance = state.borrow::(); + let device_resource = state + .resource_table + .get::(args.device_rid)?; + let device = device_resource.0; + + let layout = if let Some(rid) = args.layout { + let pipeline_layout_resource = state.resource_table.get::(rid)?; + Some(pipeline_layout_resource.0) + } else { + None + }; + + let vertex_shader_module_resource = state + .resource_table + .get::(args.vertex.module)?; + + let fragment = if let Some(fragment) = args.fragment { + let fragment_shader_module_resource = + state + .resource_table + .get::(fragment.module)?; + + let mut targets = Vec::with_capacity(fragment.targets.len()); + + for target in fragment.targets { + targets.push(target.try_into()?); + } + + Some(wgpu_core::pipeline::FragmentState { + stage: wgpu_core::pipeline::ProgrammableStageDescriptor { + module: fragment_shader_module_resource.0, + entry_point: Cow::from(fragment.entry_point), + }, + targets: Cow::from(targets), + }) + } else { + None + }; + + let vertex_buffers = args + .vertex + .buffers + .into_iter() + .flatten() + .map(Into::into) + .collect(); + + let descriptor = wgpu_core::pipeline::RenderPipelineDescriptor { + label: args.label.map(Cow::Owned), + layout, + vertex: wgpu_core::pipeline::VertexState { + stage: wgpu_core::pipeline::ProgrammableStageDescriptor { + module: vertex_shader_module_resource.0, + entry_point: Cow::Owned(args.vertex.entry_point), + }, + buffers: Cow::Owned(vertex_buffers), + }, + primitive: args.primitive.into(), + depth_stencil: args.depth_stencil.map(TryInto::try_into).transpose()?, + multisample: args.multisample.into(), + fragment, + multiview: None, + }; + + let implicit_pipelines = match args.layout { + Some(_) => None, + None => Some(wgpu_core::device::ImplicitPipelineIds { + root_id: std::marker::PhantomData, + group_ids: &[std::marker::PhantomData; MAX_BIND_GROUPS], + }), + }; + + let (render_pipeline, maybe_err) = gfx_select!(device => instance.device_create_render_pipeline( + device, + &descriptor, + std::marker::PhantomData, + implicit_pipelines + )); + + let rid = state + .resource_table + .add(WebGpuRenderPipeline(render_pipeline)); + + Ok(WebGpuResult::rid_err(rid, maybe_err)) +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct RenderPipelineGetBindGroupLayoutArgs { + render_pipeline_rid: ResourceId, + index: u32, +} + +pub fn op_webgpu_render_pipeline_get_bind_group_layout( + state: &mut OpState, + args: RenderPipelineGetBindGroupLayoutArgs, + _: (), +) -> Result { + let instance = state.borrow::(); + let render_pipeline_resource = state + .resource_table + .get::(args.render_pipeline_rid)?; + let render_pipeline = render_pipeline_resource.0; + + let (bind_group_layout, maybe_err) = gfx_select!(render_pipeline => instance.render_pipeline_get_bind_group_layout(render_pipeline, args.index, std::marker::PhantomData)); + + let label = + gfx_select!(bind_group_layout => instance.bind_group_layout_label(bind_group_layout)); + + let rid = state + .resource_table + .add(super::binding::WebGpuBindGroupLayout(bind_group_layout)); + + Ok(PipelineLayout { + rid, + label, + err: maybe_err.map(WebGpuError::from), + }) +} diff --git a/ext/webgpu/src/queue.rs b/ext/webgpu/src/queue.rs new file mode 100644 index 00000000000000..c46f511b2d83a3 --- /dev/null +++ b/ext/webgpu/src/queue.rs @@ -0,0 +1,137 @@ +// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. + +use std::num::NonZeroU32; + +use deno_core::error::AnyError; +use deno_core::OpState; +use deno_core::ResourceId; +use deno_core::ZeroCopyBuf; +use serde::Deserialize; + +use super::error::WebGpuResult; + +type WebGpuQueue = super::WebGpuDevice; + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct QueueSubmitArgs { + queue_rid: ResourceId, + command_buffers: Vec, +} + +pub fn op_webgpu_queue_submit( + state: &mut OpState, + args: QueueSubmitArgs, + _: (), +) -> Result { + let instance = state.borrow::(); + let queue_resource = state.resource_table.get::(args.queue_rid)?; + let queue = queue_resource.0; + + let mut ids = vec![]; + + for rid in args.command_buffers { + let buffer_resource = state + .resource_table + .get::(rid)?; + ids.push(buffer_resource.0); + } + + let maybe_err = gfx_select!(queue => instance.queue_submit(queue, &ids)).err(); + + Ok(WebGpuResult::maybe_err(maybe_err)) +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +struct GpuImageDataLayout { + offset: u64, + bytes_per_row: Option, + rows_per_image: Option, +} + +impl From for wgpu_types::ImageDataLayout { + fn from(layout: GpuImageDataLayout) -> Self { + wgpu_types::ImageDataLayout { + offset: layout.offset, + bytes_per_row: NonZeroU32::new(layout.bytes_per_row.unwrap_or(0)), + rows_per_image: NonZeroU32::new(layout.rows_per_image.unwrap_or(0)), + } + } +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct QueueWriteBufferArgs { + queue_rid: ResourceId, + buffer: ResourceId, + buffer_offset: u64, + data_offset: usize, + size: Option, +} + +pub fn op_webgpu_write_buffer( + state: &mut OpState, + args: QueueWriteBufferArgs, + zero_copy: ZeroCopyBuf, +) -> Result { + let instance = state.borrow::(); + let buffer_resource = state + .resource_table + .get::(args.buffer)?; + let buffer = buffer_resource.0; + let queue_resource = state.resource_table.get::(args.queue_rid)?; + let queue = queue_resource.0; + + let data = match args.size { + Some(size) => &zero_copy[args.data_offset..(args.data_offset + size)], + None => &zero_copy[args.data_offset..], + }; + let maybe_err = gfx_select!(queue => instance.queue_write_buffer( + queue, + buffer, + args.buffer_offset, + data + )) + .err(); + + Ok(WebGpuResult::maybe_err(maybe_err)) +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct QueueWriteTextureArgs { + queue_rid: ResourceId, + destination: super::command_encoder::GpuImageCopyTexture, + data_layout: GpuImageDataLayout, + size: wgpu_types::Extent3d, +} + +pub fn op_webgpu_write_texture( + state: &mut OpState, + args: QueueWriteTextureArgs, + zero_copy: ZeroCopyBuf, +) -> Result { + let instance = state.borrow::(); + let texture_resource = state + .resource_table + .get::(args.destination.texture)?; + let queue_resource = state.resource_table.get::(args.queue_rid)?; + let queue = queue_resource.0; + + let destination = wgpu_core::command::ImageCopyTexture { + texture: texture_resource.0, + mip_level: args.destination.mip_level, + origin: args.destination.origin, + aspect: args.destination.aspect, + }; + let data_layout = args.data_layout.into(); + + gfx_ok!(queue => instance.queue_write_texture( + queue, + &destination, + &*zero_copy, + &data_layout, + &args.size + )) +} diff --git a/ext/webgpu/src/render_pass.rs b/ext/webgpu/src/render_pass.rs new file mode 100644 index 00000000000000..83a5ff0d0e515d --- /dev/null +++ b/ext/webgpu/src/render_pass.rs @@ -0,0 +1,643 @@ +// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. + +use deno_core::error::type_error; +use deno_core::error::AnyError; +use deno_core::ResourceId; +use deno_core::ZeroCopyBuf; +use deno_core::{OpState, Resource}; +use serde::Deserialize; +use std::borrow::Cow; +use std::cell::RefCell; + +use super::error::WebGpuResult; + +pub(crate) struct WebGpuRenderPass(pub(crate) RefCell); +impl Resource for WebGpuRenderPass { + fn name(&self) -> Cow { + "webGPURenderPass".into() + } +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct RenderPassSetViewportArgs { + render_pass_rid: ResourceId, + x: f32, + y: f32, + width: f32, + height: f32, + min_depth: f32, + max_depth: f32, +} + +pub fn op_webgpu_render_pass_set_viewport( + state: &mut OpState, + args: RenderPassSetViewportArgs, + _: (), +) -> Result { + let render_pass_resource = state + .resource_table + .get::(args.render_pass_rid)?; + + wgpu_core::command::render_ffi::wgpu_render_pass_set_viewport( + &mut render_pass_resource.0.borrow_mut(), + args.x, + args.y, + args.width, + args.height, + args.min_depth, + args.max_depth, + ); + + Ok(WebGpuResult::empty()) +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct RenderPassSetScissorRectArgs { + render_pass_rid: ResourceId, + x: u32, + y: u32, + width: u32, + height: u32, +} + +pub fn op_webgpu_render_pass_set_scissor_rect( + state: &mut OpState, + args: RenderPassSetScissorRectArgs, + _: (), +) -> Result { + let render_pass_resource = state + .resource_table + .get::(args.render_pass_rid)?; + + wgpu_core::command::render_ffi::wgpu_render_pass_set_scissor_rect( + &mut render_pass_resource.0.borrow_mut(), + args.x, + args.y, + args.width, + args.height, + ); + + Ok(WebGpuResult::empty()) +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct RenderPassSetBlendConstantArgs { + render_pass_rid: ResourceId, + color: wgpu_types::Color, +} + +pub fn op_webgpu_render_pass_set_blend_constant( + state: &mut OpState, + args: RenderPassSetBlendConstantArgs, + _: (), +) -> Result { + let render_pass_resource = state + .resource_table + .get::(args.render_pass_rid)?; + + wgpu_core::command::render_ffi::wgpu_render_pass_set_blend_constant( + &mut render_pass_resource.0.borrow_mut(), + &args.color, + ); + + Ok(WebGpuResult::empty()) +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct RenderPassSetStencilReferenceArgs { + render_pass_rid: ResourceId, + reference: u32, +} + +pub fn op_webgpu_render_pass_set_stencil_reference( + state: &mut OpState, + args: RenderPassSetStencilReferenceArgs, + _: (), +) -> Result { + let render_pass_resource = state + .resource_table + .get::(args.render_pass_rid)?; + + wgpu_core::command::render_ffi::wgpu_render_pass_set_stencil_reference( + &mut render_pass_resource.0.borrow_mut(), + args.reference, + ); + + Ok(WebGpuResult::empty()) +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct RenderPassBeginPipelineStatisticsQueryArgs { + render_pass_rid: ResourceId, + query_set: u32, + query_index: u32, +} + +pub fn op_webgpu_render_pass_begin_pipeline_statistics_query( + state: &mut OpState, + args: RenderPassBeginPipelineStatisticsQueryArgs, + _: (), +) -> Result { + let render_pass_resource = state + .resource_table + .get::(args.render_pass_rid)?; + let query_set_resource = state + .resource_table + .get::(args.query_set)?; + + wgpu_core::command::render_ffi::wgpu_render_pass_begin_pipeline_statistics_query( + &mut render_pass_resource.0.borrow_mut(), + query_set_resource.0, + args.query_index, + ); + + Ok(WebGpuResult::empty()) +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct RenderPassEndPipelineStatisticsQueryArgs { + render_pass_rid: ResourceId, +} + +pub fn op_webgpu_render_pass_end_pipeline_statistics_query( + state: &mut OpState, + args: RenderPassEndPipelineStatisticsQueryArgs, + _: (), +) -> Result { + let render_pass_resource = state + .resource_table + .get::(args.render_pass_rid)?; + + wgpu_core::command::render_ffi::wgpu_render_pass_end_pipeline_statistics_query( + &mut render_pass_resource.0.borrow_mut(), + ); + + Ok(WebGpuResult::empty()) +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct RenderPassWriteTimestampArgs { + render_pass_rid: ResourceId, + query_set: u32, + query_index: u32, +} + +pub fn op_webgpu_render_pass_write_timestamp( + state: &mut OpState, + args: RenderPassWriteTimestampArgs, + _: (), +) -> Result { + let render_pass_resource = state + .resource_table + .get::(args.render_pass_rid)?; + let query_set_resource = state + .resource_table + .get::(args.query_set)?; + + wgpu_core::command::render_ffi::wgpu_render_pass_write_timestamp( + &mut render_pass_resource.0.borrow_mut(), + query_set_resource.0, + args.query_index, + ); + + Ok(WebGpuResult::empty()) +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct RenderPassExecuteBundlesArgs { + render_pass_rid: ResourceId, + bundles: Vec, +} + +pub fn op_webgpu_render_pass_execute_bundles( + state: &mut OpState, + args: RenderPassExecuteBundlesArgs, + _: (), +) -> Result { + let mut render_bundle_ids = vec![]; + + for rid in &args.bundles { + let render_bundle_resource = state + .resource_table + .get::(*rid)?; + render_bundle_ids.push(render_bundle_resource.0); + } + + let render_pass_resource = state + .resource_table + .get::(args.render_pass_rid)?; + + // SAFETY: the raw pointer and length are of the same slice, and that slice + // lives longer than the below function invocation. + unsafe { + wgpu_core::command::render_ffi::wgpu_render_pass_execute_bundles( + &mut render_pass_resource.0.borrow_mut(), + render_bundle_ids.as_ptr(), + render_bundle_ids.len(), + ); + } + + Ok(WebGpuResult::empty()) +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct RenderPassEndPassArgs { + command_encoder_rid: ResourceId, + render_pass_rid: ResourceId, +} + +pub fn op_webgpu_render_pass_end_pass( + state: &mut OpState, + args: RenderPassEndPassArgs, + _: (), +) -> Result { + let command_encoder_resource = + state + .resource_table + .get::(args.command_encoder_rid)?; + let command_encoder = command_encoder_resource.0; + let render_pass_resource = state + .resource_table + .take::(args.render_pass_rid)?; + let render_pass = &render_pass_resource.0.borrow(); + let instance = state.borrow::(); + + gfx_ok!(command_encoder => instance.command_encoder_run_render_pass(command_encoder, render_pass)) +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct RenderPassSetBindGroupArgs { + render_pass_rid: ResourceId, + index: u32, + bind_group: u32, + dynamic_offsets_data: ZeroCopyBuf, + dynamic_offsets_data_start: usize, + dynamic_offsets_data_length: usize, +} + +pub fn op_webgpu_render_pass_set_bind_group( + state: &mut OpState, + args: RenderPassSetBindGroupArgs, + _: (), +) -> Result { + let bind_group_resource = state + .resource_table + .get::(args.bind_group)?; + let render_pass_resource = state + .resource_table + .get::(args.render_pass_rid)?; + + // Align the data + assert!(args.dynamic_offsets_data_start % std::mem::size_of::() == 0); + // SAFETY: A u8 to u32 cast is safe because we asserted that the length is a + // multiple of 4. + let (prefix, dynamic_offsets_data, suffix) = + unsafe { args.dynamic_offsets_data.align_to::() }; + assert!(prefix.is_empty()); + assert!(suffix.is_empty()); + + let start = args.dynamic_offsets_data_start; + let len = args.dynamic_offsets_data_length; + + // Assert that length and start are both in bounds + assert!(start <= dynamic_offsets_data.len()); + assert!(len <= dynamic_offsets_data.len() - start); + + let dynamic_offsets_data: &[u32] = &dynamic_offsets_data[start..start + len]; + + // SAFETY: the raw pointer and length are of the same slice, and that slice + // lives longer than the below function invocation. + unsafe { + wgpu_core::command::render_ffi::wgpu_render_pass_set_bind_group( + &mut render_pass_resource.0.borrow_mut(), + args.index, + bind_group_resource.0, + dynamic_offsets_data.as_ptr(), + dynamic_offsets_data.len(), + ); + } + + Ok(WebGpuResult::empty()) +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct RenderPassPushDebugGroupArgs { + render_pass_rid: ResourceId, + group_label: String, +} + +pub fn op_webgpu_render_pass_push_debug_group( + state: &mut OpState, + args: RenderPassPushDebugGroupArgs, + _: (), +) -> Result { + let render_pass_resource = state + .resource_table + .get::(args.render_pass_rid)?; + + let label = std::ffi::CString::new(args.group_label).unwrap(); + // SAFETY: the string the raw pointer points to lives longer than the below + // function invocation. + unsafe { + wgpu_core::command::render_ffi::wgpu_render_pass_push_debug_group( + &mut render_pass_resource.0.borrow_mut(), + label.as_ptr(), + 0, // wgpu#975 + ); + } + + Ok(WebGpuResult::empty()) +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct RenderPassPopDebugGroupArgs { + render_pass_rid: ResourceId, +} + +pub fn op_webgpu_render_pass_pop_debug_group( + state: &mut OpState, + args: RenderPassPopDebugGroupArgs, + _: (), +) -> Result { + let render_pass_resource = state + .resource_table + .get::(args.render_pass_rid)?; + + wgpu_core::command::render_ffi::wgpu_render_pass_pop_debug_group( + &mut render_pass_resource.0.borrow_mut(), + ); + + Ok(WebGpuResult::empty()) +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct RenderPassInsertDebugMarkerArgs { + render_pass_rid: ResourceId, + marker_label: String, +} + +pub fn op_webgpu_render_pass_insert_debug_marker( + state: &mut OpState, + args: RenderPassInsertDebugMarkerArgs, + _: (), +) -> Result { + let render_pass_resource = state + .resource_table + .get::(args.render_pass_rid)?; + + let label = std::ffi::CString::new(args.marker_label).unwrap(); + // SAFETY: the string the raw pointer points to lives longer than the below + // function invocation. + unsafe { + wgpu_core::command::render_ffi::wgpu_render_pass_insert_debug_marker( + &mut render_pass_resource.0.borrow_mut(), + label.as_ptr(), + 0, // wgpu#975 + ); + } + + Ok(WebGpuResult::empty()) +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct RenderPassSetPipelineArgs { + render_pass_rid: ResourceId, + pipeline: u32, +} + +pub fn op_webgpu_render_pass_set_pipeline( + state: &mut OpState, + args: RenderPassSetPipelineArgs, + _: (), +) -> Result { + let render_pipeline_resource = state + .resource_table + .get::(args.pipeline)?; + let render_pass_resource = state + .resource_table + .get::(args.render_pass_rid)?; + + wgpu_core::command::render_ffi::wgpu_render_pass_set_pipeline( + &mut render_pass_resource.0.borrow_mut(), + render_pipeline_resource.0, + ); + + Ok(WebGpuResult::empty()) +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct RenderPassSetIndexBufferArgs { + render_pass_rid: ResourceId, + buffer: u32, + index_format: wgpu_types::IndexFormat, + offset: u64, + size: Option, +} + +pub fn op_webgpu_render_pass_set_index_buffer( + state: &mut OpState, + args: RenderPassSetIndexBufferArgs, + _: (), +) -> Result { + let buffer_resource = state + .resource_table + .get::(args.buffer)?; + let render_pass_resource = state + .resource_table + .get::(args.render_pass_rid)?; + + let size = if let Some(size) = args.size { + Some( + std::num::NonZeroU64::new(size) + .ok_or_else(|| type_error("size must be larger than 0"))?, + ) + } else { + None + }; + + render_pass_resource.0.borrow_mut().set_index_buffer( + buffer_resource.0, + args.index_format, + args.offset, + size, + ); + + Ok(WebGpuResult::empty()) +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct RenderPassSetVertexBufferArgs { + render_pass_rid: ResourceId, + slot: u32, + buffer: u32, + offset: u64, + size: Option, +} + +pub fn op_webgpu_render_pass_set_vertex_buffer( + state: &mut OpState, + args: RenderPassSetVertexBufferArgs, + _: (), +) -> Result { + let buffer_resource = state + .resource_table + .get::(args.buffer)?; + let render_pass_resource = state + .resource_table + .get::(args.render_pass_rid)?; + + let size = if let Some(size) = args.size { + Some( + std::num::NonZeroU64::new(size) + .ok_or_else(|| type_error("size must be larger than 0"))?, + ) + } else { + None + }; + + wgpu_core::command::render_ffi::wgpu_render_pass_set_vertex_buffer( + &mut render_pass_resource.0.borrow_mut(), + args.slot, + buffer_resource.0, + args.offset, + size, + ); + + Ok(WebGpuResult::empty()) +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct RenderPassDrawArgs { + render_pass_rid: ResourceId, + vertex_count: u32, + instance_count: u32, + first_vertex: u32, + first_instance: u32, +} + +pub fn op_webgpu_render_pass_draw( + state: &mut OpState, + args: RenderPassDrawArgs, + _: (), +) -> Result { + let render_pass_resource = state + .resource_table + .get::(args.render_pass_rid)?; + + wgpu_core::command::render_ffi::wgpu_render_pass_draw( + &mut render_pass_resource.0.borrow_mut(), + args.vertex_count, + args.instance_count, + args.first_vertex, + args.first_instance, + ); + + Ok(WebGpuResult::empty()) +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct RenderPassDrawIndexedArgs { + render_pass_rid: ResourceId, + index_count: u32, + instance_count: u32, + first_index: u32, + base_vertex: i32, + first_instance: u32, +} + +pub fn op_webgpu_render_pass_draw_indexed( + state: &mut OpState, + args: RenderPassDrawIndexedArgs, + _: (), +) -> Result { + let render_pass_resource = state + .resource_table + .get::(args.render_pass_rid)?; + + wgpu_core::command::render_ffi::wgpu_render_pass_draw_indexed( + &mut render_pass_resource.0.borrow_mut(), + args.index_count, + args.instance_count, + args.first_index, + args.base_vertex, + args.first_instance, + ); + + Ok(WebGpuResult::empty()) +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct RenderPassDrawIndirectArgs { + render_pass_rid: ResourceId, + indirect_buffer: u32, + indirect_offset: u64, +} + +pub fn op_webgpu_render_pass_draw_indirect( + state: &mut OpState, + args: RenderPassDrawIndirectArgs, + _: (), +) -> Result { + let buffer_resource = state + .resource_table + .get::(args.indirect_buffer)?; + let render_pass_resource = state + .resource_table + .get::(args.render_pass_rid)?; + + wgpu_core::command::render_ffi::wgpu_render_pass_draw_indirect( + &mut render_pass_resource.0.borrow_mut(), + buffer_resource.0, + args.indirect_offset, + ); + + Ok(WebGpuResult::empty()) +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct RenderPassDrawIndexedIndirectArgs { + render_pass_rid: ResourceId, + indirect_buffer: u32, + indirect_offset: u64, +} + +pub fn op_webgpu_render_pass_draw_indexed_indirect( + state: &mut OpState, + args: RenderPassDrawIndexedIndirectArgs, + _: (), +) -> Result { + let buffer_resource = state + .resource_table + .get::(args.indirect_buffer)?; + let render_pass_resource = state + .resource_table + .get::(args.render_pass_rid)?; + + wgpu_core::command::render_ffi::wgpu_render_pass_draw_indexed_indirect( + &mut render_pass_resource.0.borrow_mut(), + buffer_resource.0, + args.indirect_offset, + ); + + Ok(WebGpuResult::empty()) +} diff --git a/ext/webgpu/src/sampler.rs b/ext/webgpu/src/sampler.rs new file mode 100644 index 00000000000000..5e49d14c9bb0a0 --- /dev/null +++ b/ext/webgpu/src/sampler.rs @@ -0,0 +1,68 @@ +// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. + +use deno_core::error::AnyError; +use deno_core::ResourceId; +use deno_core::{OpState, Resource}; +use serde::Deserialize; +use std::borrow::Cow; + +use super::error::WebGpuResult; + +pub(crate) struct WebGpuSampler(pub(crate) wgpu_core::id::SamplerId); +impl Resource for WebGpuSampler { + fn name(&self) -> Cow { + "webGPUSampler".into() + } +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct CreateSamplerArgs { + device_rid: ResourceId, + label: Option, + address_mode_u: wgpu_types::AddressMode, + address_mode_v: wgpu_types::AddressMode, + address_mode_w: wgpu_types::AddressMode, + mag_filter: wgpu_types::FilterMode, + min_filter: wgpu_types::FilterMode, + mipmap_filter: wgpu_types::FilterMode, + lod_min_clamp: f32, + lod_max_clamp: f32, + compare: Option, + max_anisotropy: u8, +} + +pub fn op_webgpu_create_sampler( + state: &mut OpState, + args: CreateSamplerArgs, + _: (), +) -> Result { + let instance = state.borrow::(); + let device_resource = state + .resource_table + .get::(args.device_rid)?; + let device = device_resource.0; + + let descriptor = wgpu_core::resource::SamplerDescriptor { + label: args.label.map(Cow::from), + address_modes: [ + args.address_mode_u, + args.address_mode_v, + args.address_mode_w, + ], + mag_filter: args.mag_filter, + min_filter: args.min_filter, + mipmap_filter: args.mipmap_filter, + lod_min_clamp: args.lod_min_clamp, + lod_max_clamp: args.lod_max_clamp, + compare: args.compare, + anisotropy_clamp: std::num::NonZeroU8::new(args.max_anisotropy), + border_color: None, // native-only + }; + + gfx_put!(device => instance.device_create_sampler( + device, + &descriptor, + std::marker::PhantomData + ) => state, WebGpuSampler) +} diff --git a/ext/webgpu/src/shader.rs b/ext/webgpu/src/shader.rs new file mode 100644 index 00000000000000..55fdf7021e78c0 --- /dev/null +++ b/ext/webgpu/src/shader.rs @@ -0,0 +1,51 @@ +// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. + +use deno_core::error::AnyError; +use deno_core::ResourceId; +use deno_core::{OpState, Resource}; +use serde::Deserialize; +use std::borrow::Cow; + +use super::error::WebGpuResult; + +pub(crate) struct WebGpuShaderModule(pub(crate) wgpu_core::id::ShaderModuleId); +impl Resource for WebGpuShaderModule { + fn name(&self) -> Cow { + "webGPUShaderModule".into() + } +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct CreateShaderModuleArgs { + device_rid: ResourceId, + label: Option, + code: String, + _source_map: Option<()>, // not yet implemented +} + +pub fn op_webgpu_create_shader_module( + state: &mut OpState, + args: CreateShaderModuleArgs, + _: (), +) -> Result { + let instance = state.borrow::(); + let device_resource = state + .resource_table + .get::(args.device_rid)?; + let device = device_resource.0; + + let source = wgpu_core::pipeline::ShaderModuleSource::Wgsl(Cow::from(args.code)); + + let descriptor = wgpu_core::pipeline::ShaderModuleDescriptor { + label: args.label.map(Cow::from), + shader_bound_checks: wgpu_types::ShaderBoundChecks::default(), + }; + + gfx_put!(device => instance.device_create_shader_module( + device, + &descriptor, + source, + std::marker::PhantomData + ) => state, WebGpuShaderModule) +} diff --git a/ext/webgpu/src/texture.rs b/ext/webgpu/src/texture.rs new file mode 100644 index 00000000000000..a3b2b79c7f66db --- /dev/null +++ b/ext/webgpu/src/texture.rs @@ -0,0 +1,108 @@ +// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. + +use deno_core::error::AnyError; +use deno_core::ResourceId; +use deno_core::{OpState, Resource}; +use serde::Deserialize; +use std::borrow::Cow; + +use super::error::WebGpuResult; +pub(crate) struct WebGpuTexture(pub(crate) wgpu_core::id::TextureId); +impl Resource for WebGpuTexture { + fn name(&self) -> Cow { + "webGPUTexture".into() + } +} + +pub(crate) struct WebGpuTextureView(pub(crate) wgpu_core::id::TextureViewId); +impl Resource for WebGpuTextureView { + fn name(&self) -> Cow { + "webGPUTextureView".into() + } +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct CreateTextureArgs { + device_rid: ResourceId, + label: Option, + size: wgpu_types::Extent3d, + mip_level_count: u32, + sample_count: u32, + dimension: wgpu_types::TextureDimension, + format: wgpu_types::TextureFormat, + usage: u32, +} + +pub fn op_webgpu_create_texture( + state: &mut OpState, + args: CreateTextureArgs, + _: (), +) -> Result { + let instance = state.borrow::(); + let device_resource = state + .resource_table + .get::(args.device_rid)?; + let device = device_resource.0; + + let descriptor = wgpu_core::resource::TextureDescriptor { + label: args.label.map(Cow::from), + size: args.size, + mip_level_count: args.mip_level_count, + sample_count: args.sample_count, + dimension: args.dimension, + format: args.format, + usage: wgpu_types::TextureUsages::from_bits_truncate(args.usage), + }; + + gfx_put!(device => instance.device_create_texture( + device, + &descriptor, + std::marker::PhantomData + ) => state, WebGpuTexture) +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct CreateTextureViewArgs { + texture_rid: ResourceId, + label: Option, + format: Option, + dimension: Option, + aspect: wgpu_types::TextureAspect, + base_mip_level: u32, + mip_level_count: Option, + base_array_layer: u32, + array_layer_count: Option, +} + +pub fn op_webgpu_create_texture_view( + state: &mut OpState, + args: CreateTextureViewArgs, + _: (), +) -> Result { + let instance = state.borrow::(); + let texture_resource = state + .resource_table + .get::(args.texture_rid)?; + let texture = texture_resource.0; + + let descriptor = wgpu_core::resource::TextureViewDescriptor { + label: args.label.map(Cow::from), + format: args.format, + dimension: args.dimension, + range: wgpu_types::ImageSubresourceRange { + aspect: args.aspect, + base_mip_level: args.base_mip_level, + mip_level_count: std::num::NonZeroU32::new(args.mip_level_count.unwrap_or(0)), + base_array_layer: args.base_array_layer, + array_layer_count: std::num::NonZeroU32::new(args.array_layer_count.unwrap_or(0)), + }, + }; + + gfx_put!(texture => instance.texture_create_view( + texture, + &descriptor, + std::marker::PhantomData + ) => state, WebGpuTextureView) +} diff --git a/ext/webgpu/texture.rs b/ext/webgpu/texture.rs deleted file mode 100644 index 9b007b34d463e4..00000000000000 --- a/ext/webgpu/texture.rs +++ /dev/null @@ -1,419 +0,0 @@ -// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. - -use deno_core::error::not_supported; -use deno_core::error::AnyError; -use deno_core::ResourceId; -use deno_core::{OpState, Resource}; -use serde::Deserialize; -use std::borrow::Cow; - -use super::error::WebGpuResult; -pub(crate) struct WebGpuTexture(pub(crate) wgpu_core::id::TextureId); -impl Resource for WebGpuTexture { - fn name(&self) -> Cow { - "webGPUTexture".into() - } -} - -pub(crate) struct WebGpuTextureView(pub(crate) wgpu_core::id::TextureViewId); -impl Resource for WebGpuTextureView { - fn name(&self) -> Cow { - "webGPUTextureView".into() - } -} - -#[derive(Deserialize)] -#[serde(rename_all = "kebab-case")] -pub enum GpuTextureFormat { - // 8-bit formats - #[serde(rename = "r8unorm")] - R8Unorm, - #[serde(rename = "r8snorm")] - R8Snorm, - #[serde(rename = "r8uint")] - R8Uint, - #[serde(rename = "r8sint")] - R8Sint, - - // 16-bit formats - #[serde(rename = "r16uint")] - R16Uint, - #[serde(rename = "r16sint")] - R16Sint, - #[serde(rename = "r16float")] - R16Float, - #[serde(rename = "rg8unorm")] - Rg8Unorm, - #[serde(rename = "rg8snorm")] - Rg8Snorm, - #[serde(rename = "rg8uint")] - Rg8Uint, - #[serde(rename = "rg8sint")] - Rg8Sint, - - // 32-bit formats - #[serde(rename = "r32uint")] - R32Uint, - #[serde(rename = "r32sint")] - R32Sint, - #[serde(rename = "r32float")] - R32Float, - #[serde(rename = "rg16uint")] - Rg16Uint, - #[serde(rename = "rg16sint")] - Rg16Sint, - #[serde(rename = "rg16float")] - Rg16Float, - #[serde(rename = "rgba8unorm")] - Rgba8Unorm, - #[serde(rename = "rgba8unorm-srgb")] - Rgba8UnormSrgb, - #[serde(rename = "rgba8snorm")] - Rgba8Snorm, - #[serde(rename = "rgba8uint")] - Rgba8Uint, - #[serde(rename = "rgba8sint")] - Rgba8Sint, - #[serde(rename = "bgra8unorm")] - Bgra8Unorm, - #[serde(rename = "bgra8unorm-srgb")] - Bgra8UnormSrgb, - // Packed 32-bit formats - #[serde(rename = "rgb9e5ufloat")] - RgB9E5UFloat, - #[serde(rename = "rgb10a2unorm")] - Rgb10a2Unorm, - #[serde(rename = "rg11b10ufloat")] - Rg11b10Float, - - // 64-bit formats - #[serde(rename = "rg32uint")] - Rg32Uint, - #[serde(rename = "rg32sint")] - Rg32Sint, - #[serde(rename = "rg32float")] - Rg32Float, - #[serde(rename = "rgba16uint")] - Rgba16Uint, - #[serde(rename = "rgba16sint")] - Rgba16Sint, - #[serde(rename = "rgba16float")] - Rgba16Float, - - // 128-bit formats - #[serde(rename = "rgba32uint")] - Rgba32Uint, - #[serde(rename = "rgba32sint")] - Rgba32Sint, - #[serde(rename = "rgba32float")] - Rgba32Float, - - // Depth and stencil formats - #[serde(rename = "stencil8")] - Stencil8, - #[serde(rename = "depth16unorm")] - Depth16Unorm, - #[serde(rename = "depth24plus")] - Depth24Plus, - #[serde(rename = "depth24plus-stencil8")] - Depth24PlusStencil8, - #[serde(rename = "depth32float")] - Depth32Float, - - // BC compressed formats usable if "texture-compression-bc" is both - // supported by the device/user agent and enabled in requestDevice. - #[serde(rename = "bc1-rgba-unorm")] - Bc1RgbaUnorm, - #[serde(rename = "bc1-rgba-unorm-srgb")] - Bc1RgbaUnormSrgb, - #[serde(rename = "bc2-rgba-unorm")] - Bc2RgbaUnorm, - #[serde(rename = "bc2-rgba-unorm-srgb")] - Bc2RgbaUnormSrgb, - #[serde(rename = "bc3-rgba-unorm")] - Bc3RgbaUnorm, - #[serde(rename = "bc3-rgba-unorm-srgb")] - Bc3RgbaUnormSrgb, - #[serde(rename = "bc4-r-unorm")] - Bc4RUnorm, - #[serde(rename = "bc4-r-snorm")] - Bc4RSnorm, - #[serde(rename = "bc5-rg-unorm")] - Bc5RgUnorm, - #[serde(rename = "bc5-rg-snorm")] - Bc5RgSnorm, - #[serde(rename = "bc6h-rgb-ufloat")] - Bc6hRgbUfloat, - #[serde(rename = "bc6h-rgb-float")] - Bc6HRgbFloat, - #[serde(rename = "bc7-rgba-unorm")] - Bc7RgbaUnorm, - #[serde(rename = "bc7-rgba-unorm-srgb")] - Bc7RgbaUnormSrgb, - - // "depth24unorm-stencil8" feature - #[serde(rename = "depth24unorm-stencil8")] - Depth24UnormStencil8, - - // "depth32float-stencil8" feature - #[serde(rename = "depth32float-stencil8")] - Depth32FloatStencil8, -} - -impl TryFrom for wgpu_types::TextureFormat { - type Error = AnyError; - - fn try_from(value: GpuTextureFormat) -> Result { - use wgpu_types::TextureFormat; - match value { - GpuTextureFormat::R8Unorm => Ok(TextureFormat::R8Unorm), - GpuTextureFormat::R8Snorm => Ok(TextureFormat::R8Snorm), - GpuTextureFormat::R8Uint => Ok(TextureFormat::R8Uint), - GpuTextureFormat::R8Sint => Ok(TextureFormat::R8Sint), - - GpuTextureFormat::R16Uint => Ok(TextureFormat::R16Uint), - GpuTextureFormat::R16Sint => Ok(TextureFormat::R16Sint), - GpuTextureFormat::R16Float => Ok(TextureFormat::R16Float), - GpuTextureFormat::Rg8Unorm => Ok(TextureFormat::Rg8Unorm), - GpuTextureFormat::Rg8Snorm => Ok(TextureFormat::Rg8Snorm), - GpuTextureFormat::Rg8Uint => Ok(TextureFormat::Rg8Uint), - GpuTextureFormat::Rg8Sint => Ok(TextureFormat::Rg8Sint), - - GpuTextureFormat::R32Uint => Ok(TextureFormat::R32Uint), - GpuTextureFormat::R32Sint => Ok(TextureFormat::R32Sint), - GpuTextureFormat::R32Float => Ok(TextureFormat::R32Float), - GpuTextureFormat::Rg16Uint => Ok(TextureFormat::Rg16Uint), - GpuTextureFormat::Rg16Sint => Ok(TextureFormat::Rg16Sint), - GpuTextureFormat::Rg16Float => Ok(TextureFormat::Rg16Float), - GpuTextureFormat::Rgba8Unorm => Ok(TextureFormat::Rgba8Unorm), - GpuTextureFormat::Rgba8UnormSrgb => Ok(TextureFormat::Rgba8UnormSrgb), - GpuTextureFormat::Rgba8Snorm => Ok(TextureFormat::Rgba8Snorm), - GpuTextureFormat::Rgba8Uint => Ok(TextureFormat::Rgba8Uint), - GpuTextureFormat::Rgba8Sint => Ok(TextureFormat::Rgba8Sint), - GpuTextureFormat::Bgra8Unorm => Ok(TextureFormat::Bgra8Unorm), - GpuTextureFormat::Bgra8UnormSrgb => Ok(TextureFormat::Bgra8UnormSrgb), - GpuTextureFormat::RgB9E5UFloat => Err(not_supported()), // wgpu#967 - GpuTextureFormat::Rgb10a2Unorm => Ok(TextureFormat::Rgb10a2Unorm), - GpuTextureFormat::Rg11b10Float => Ok(TextureFormat::Rg11b10Float), - - GpuTextureFormat::Rg32Uint => Ok(TextureFormat::Rg32Uint), - GpuTextureFormat::Rg32Sint => Ok(TextureFormat::Rg32Sint), - GpuTextureFormat::Rg32Float => Ok(TextureFormat::Rg32Float), - GpuTextureFormat::Rgba16Uint => Ok(TextureFormat::Rgba16Uint), - GpuTextureFormat::Rgba16Sint => Ok(TextureFormat::Rgba16Sint), - GpuTextureFormat::Rgba16Float => Ok(TextureFormat::Rgba16Float), - - GpuTextureFormat::Rgba32Uint => Ok(TextureFormat::Rgba32Uint), - GpuTextureFormat::Rgba32Sint => Ok(TextureFormat::Rgba32Sint), - GpuTextureFormat::Rgba32Float => Ok(TextureFormat::Rgba32Float), - - GpuTextureFormat::Stencil8 => Err(not_supported()), // wgpu#967 - GpuTextureFormat::Depth16Unorm => Err(not_supported()), // wgpu#967 - GpuTextureFormat::Depth24Plus => Ok(TextureFormat::Depth24Plus), - GpuTextureFormat::Depth24PlusStencil8 => { - Ok(TextureFormat::Depth24PlusStencil8) - } - GpuTextureFormat::Depth32Float => Ok(TextureFormat::Depth32Float), - - GpuTextureFormat::Bc1RgbaUnorm => Ok(TextureFormat::Bc1RgbaUnorm), - GpuTextureFormat::Bc1RgbaUnormSrgb => Ok(TextureFormat::Bc1RgbaUnormSrgb), - GpuTextureFormat::Bc2RgbaUnorm => Ok(TextureFormat::Bc2RgbaUnorm), - GpuTextureFormat::Bc2RgbaUnormSrgb => Ok(TextureFormat::Bc2RgbaUnormSrgb), - GpuTextureFormat::Bc3RgbaUnorm => Ok(TextureFormat::Bc3RgbaUnorm), - GpuTextureFormat::Bc3RgbaUnormSrgb => Ok(TextureFormat::Bc3RgbaUnormSrgb), - GpuTextureFormat::Bc4RUnorm => Ok(TextureFormat::Bc4RUnorm), - GpuTextureFormat::Bc4RSnorm => Ok(TextureFormat::Bc4RSnorm), - GpuTextureFormat::Bc5RgUnorm => Ok(TextureFormat::Bc5RgUnorm), - GpuTextureFormat::Bc5RgSnorm => Ok(TextureFormat::Bc5RgSnorm), - GpuTextureFormat::Bc6hRgbUfloat => Ok(TextureFormat::Bc6hRgbUfloat), - GpuTextureFormat::Bc6HRgbFloat => Ok(TextureFormat::Bc6hRgbSfloat), // wgpu#967 - GpuTextureFormat::Bc7RgbaUnorm => Ok(TextureFormat::Bc7RgbaUnorm), - GpuTextureFormat::Bc7RgbaUnormSrgb => Ok(TextureFormat::Bc7RgbaUnormSrgb), - - GpuTextureFormat::Depth24UnormStencil8 => Err(not_supported()), // wgpu#967, - - GpuTextureFormat::Depth32FloatStencil8 => Err(not_supported()), // wgpu#967 - } - } -} - -#[derive(Deserialize)] -#[serde(rename_all = "kebab-case")] -pub enum GpuTextureViewDimension { - #[serde(rename = "1d")] - D1, - #[serde(rename = "2d")] - D2, - #[serde(rename = "2d-array")] - D2Array, - #[serde(rename = "cube")] - Cube, - #[serde(rename = "cube-array")] - CubeArray, - #[serde(rename = "3d")] - D3, -} - -impl From for wgpu_types::TextureViewDimension { - fn from(view_dimension: GpuTextureViewDimension) -> Self { - match view_dimension { - GpuTextureViewDimension::D1 => wgpu_types::TextureViewDimension::D1, - GpuTextureViewDimension::D2 => wgpu_types::TextureViewDimension::D2, - GpuTextureViewDimension::D2Array => { - wgpu_types::TextureViewDimension::D2Array - } - GpuTextureViewDimension::Cube => wgpu_types::TextureViewDimension::Cube, - GpuTextureViewDimension::CubeArray => { - wgpu_types::TextureViewDimension::CubeArray - } - GpuTextureViewDimension::D3 => wgpu_types::TextureViewDimension::D3, - } - } -} - -#[derive(Deserialize)] -#[serde(rename_all = "kebab-case")] -pub enum GpuTextureDimension { - #[serde(rename = "1d")] - D1, - #[serde(rename = "2d")] - D2, - #[serde(rename = "3d")] - D3, -} - -impl From for wgpu_types::TextureDimension { - fn from(texture_dimension: GpuTextureDimension) -> Self { - match texture_dimension { - GpuTextureDimension::D1 => wgpu_types::TextureDimension::D1, - GpuTextureDimension::D2 => wgpu_types::TextureDimension::D2, - GpuTextureDimension::D3 => wgpu_types::TextureDimension::D3, - } - } -} - -#[derive(Deserialize)] -#[serde(rename_all = "kebab-case")] -pub enum GpuTextureAspect { - All, - StencilOnly, - DepthOnly, -} - -impl From for wgpu_types::TextureAspect { - fn from(aspect: GpuTextureAspect) -> wgpu_types::TextureAspect { - match aspect { - GpuTextureAspect::All => wgpu_types::TextureAspect::All, - GpuTextureAspect::StencilOnly => wgpu_types::TextureAspect::StencilOnly, - GpuTextureAspect::DepthOnly => wgpu_types::TextureAspect::DepthOnly, - } - } -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct GpuExtent3D { - pub width: u32, - pub height: u32, - pub depth_or_array_layers: u32, -} - -impl From for wgpu_types::Extent3d { - fn from(extent: GpuExtent3D) -> Self { - wgpu_types::Extent3d { - width: extent.width, - height: extent.height, - depth_or_array_layers: extent.depth_or_array_layers, - } - } -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct CreateTextureArgs { - device_rid: ResourceId, - label: Option, - size: GpuExtent3D, - mip_level_count: u32, - sample_count: u32, - dimension: GpuTextureDimension, - format: GpuTextureFormat, - usage: u32, -} - -pub fn op_webgpu_create_texture( - state: &mut OpState, - args: CreateTextureArgs, - _: (), -) -> Result { - let instance = state.borrow::(); - let device_resource = state - .resource_table - .get::(args.device_rid)?; - let device = device_resource.0; - - let descriptor = wgpu_core::resource::TextureDescriptor { - label: args.label.map(Cow::from), - size: args.size.into(), - mip_level_count: args.mip_level_count, - sample_count: args.sample_count, - dimension: args.dimension.into(), - format: args.format.try_into()?, - usage: wgpu_types::TextureUsages::from_bits_truncate(args.usage), - }; - - gfx_put!(device => instance.device_create_texture( - device, - &descriptor, - std::marker::PhantomData - ) => state, WebGpuTexture) -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct CreateTextureViewArgs { - texture_rid: ResourceId, - label: Option, - format: Option, - dimension: Option, - aspect: GpuTextureAspect, - base_mip_level: u32, - mip_level_count: Option, - base_array_layer: u32, - array_layer_count: Option, -} - -pub fn op_webgpu_create_texture_view( - state: &mut OpState, - args: CreateTextureViewArgs, - _: (), -) -> Result { - let instance = state.borrow::(); - let texture_resource = state - .resource_table - .get::(args.texture_rid)?; - let texture = texture_resource.0; - - let descriptor = wgpu_core::resource::TextureViewDescriptor { - label: args.label.map(Cow::from), - format: args.format.map(|s| s.try_into()).transpose()?, - dimension: args.dimension.map(|s| s.into()), - range: wgpu_types::ImageSubresourceRange { - aspect: args.aspect.into(), - base_mip_level: args.base_mip_level, - mip_level_count: std::num::NonZeroU32::new( - args.mip_level_count.unwrap_or(0), - ), - base_array_layer: args.base_array_layer, - array_layer_count: std::num::NonZeroU32::new( - args.array_layer_count.unwrap_or(0), - ), - }, - }; - - gfx_put!(texture => instance.texture_create_view( - texture, - &descriptor, - std::marker::PhantomData - ) => state, WebGpuTextureView) -} diff --git a/ext/webgpu/webgpu.idl b/ext/webgpu/webgpu.idl index 02650699688999..79d65791d4e6fa 100644 --- a/ext/webgpu/webgpu.idl +++ b/ext/webgpu/webgpu.idl @@ -6,7 +6,7 @@ dictionary GPUObjectDescriptorBase { USVString label; }; -[Exposed=(Window, DedicatedWorker)] +[Exposed=(Window, DedicatedWorker), SecureContext] interface GPUSupportedLimits { readonly attribute unsigned long maxTextureDimension1D; readonly attribute unsigned long maxTextureDimension2D; @@ -36,7 +36,7 @@ interface GPUSupportedLimits { readonly attribute unsigned long maxComputeWorkgroupsPerDimension; }; -[Exposed=(Window, DedicatedWorker)] +[Exposed=(Window, DedicatedWorker), SecureContext] interface GPUSupportedFeatures { readonly setlike; }; @@ -46,12 +46,12 @@ enum GPUPredefinedColorSpace { }; interface mixin NavigatorGPU { - [SameObject] readonly attribute GPU gpu; + [SameObject, SecureContext] readonly attribute GPU gpu; }; Navigator includes NavigatorGPU; WorkerNavigator includes NavigatorGPU; -[Exposed=(Window, DedicatedWorker)] +[Exposed=(Window, DedicatedWorker), SecureContext] interface GPU { Promise requestAdapter(optional GPURequestAdapterOptions options = {}); }; @@ -63,10 +63,10 @@ dictionary GPURequestAdapterOptions { enum GPUPowerPreference { "low-power", - "high-performance" + "high-performance", }; -[Exposed=(Window, DedicatedWorker)] +[Exposed=(Window, DedicatedWorker), SecureContext] interface GPUAdapter { readonly attribute DOMString name; [SameObject] readonly attribute GPUSupportedFeatures features; @@ -82,15 +82,18 @@ dictionary GPUDeviceDescriptor : GPUObjectDescriptorBase { }; enum GPUFeatureName { - "depth-clamping", + "depth-clip-control", "depth24unorm-stencil8", "depth32float-stencil8", "pipeline-statistics-query", "texture-compression-bc", + "texture-compression-etc2", + "texture-compression-astc", "timestamp-query", + "indirect-first-instance", }; -[Exposed=(Window, DedicatedWorker)] +[Exposed=(Window, DedicatedWorker), SecureContext] interface GPUDevice : EventTarget { [SameObject] readonly attribute GPUSupportedFeatures features; [SameObject] readonly attribute GPUSupportedLimits limits; @@ -120,7 +123,7 @@ interface GPUDevice : EventTarget { }; GPUDevice includes GPUObjectBase; -[Exposed=(Window, DedicatedWorker)] +[Exposed=(Window, DedicatedWorker), SecureContext] interface GPUBuffer { Promise mapAsync(GPUMapModeFlags mode, optional GPUSize64 offset = 0, optional GPUSize64 size); ArrayBuffer getMappedRange(optional GPUSize64 offset = 0, optional GPUSize64 size); @@ -158,7 +161,7 @@ interface GPUMapMode { const GPUFlagsConstant WRITE = 0x0002; }; -[Exposed=(Window, DedicatedWorker)] +[Exposed=(Window, DedicatedWorker), SecureContext] interface GPUTexture { GPUTextureView createView(optional GPUTextureViewDescriptor descriptor = {}); @@ -191,7 +194,7 @@ interface GPUTextureUsage { const GPUFlagsConstant RENDER_ATTACHMENT = 0x10; }; -[Exposed=(Window, DedicatedWorker)] +[Exposed=(Window, DedicatedWorker), SecureContext] interface GPUTextureView { }; GPUTextureView includes GPUObjectBase; @@ -212,13 +215,13 @@ enum GPUTextureViewDimension { "2d-array", "cube", "cube-array", - "3d" + "3d", }; enum GPUTextureAspect { "all", "stencil-only", - "depth-only" + "depth-only", }; enum GPUTextureFormat { @@ -293,6 +296,50 @@ enum GPUTextureFormat { "bc7-rgba-unorm", "bc7-rgba-unorm-srgb", + // ETC2 compressed formats usable if "texture-compression-etc2" is both + // supported by the device/user agent and enabled in requestDevice. + "etc2-rgb8unorm", + "etc2-rgb8unorm-srgb", + "etc2-rgb8a1unorm", + "etc2-rgb8a1unorm-srgb", + "etc2-rgba8unorm", + "etc2-rgba8unorm-srgb", + "eac-r11unorm", + "eac-r11snorm", + "eac-rg11unorm", + "eac-rg11snorm", + + // ASTC compressed formats usable if "texture-compression-astc" is both + // supported by the device/user agent and enabled in requestDevice. + "astc-4x4-unorm", + "astc-4x4-unorm-srgb", + "astc-5x4-unorm", + "astc-5x4-unorm-srgb", + "astc-5x5-unorm", + "astc-5x5-unorm-srgb", + "astc-6x5-unorm", + "astc-6x5-unorm-srgb", + "astc-6x6-unorm", + "astc-6x6-unorm-srgb", + "astc-8x5-unorm", + "astc-8x5-unorm-srgb", + "astc-8x6-unorm", + "astc-8x6-unorm-srgb", + "astc-8x8-unorm", + "astc-8x8-unorm-srgb", + "astc-10x5-unorm", + "astc-10x5-unorm-srgb", + "astc-10x6-unorm", + "astc-10x6-unorm-srgb", + "astc-10x8-unorm", + "astc-10x8-unorm-srgb", + "astc-10x10-unorm", + "astc-10x10-unorm-srgb", + "astc-12x10-unorm", + "astc-12x10-unorm-srgb", + "astc-12x12-unorm", + "astc-12x12-unorm-srgb", + // "depth24unorm-stencil8" feature "depth24unorm-stencil8", @@ -300,7 +347,7 @@ enum GPUTextureFormat { "depth32float-stencil8", }; -[Exposed=(Window, DedicatedWorker)] +[Exposed=(Window, DedicatedWorker), SecureContext] interface GPUSampler { }; GPUSampler includes GPUObjectBase; @@ -321,12 +368,12 @@ dictionary GPUSamplerDescriptor : GPUObjectDescriptorBase { enum GPUAddressMode { "clamp-to-edge", "repeat", - "mirror-repeat" + "mirror-repeat", }; enum GPUFilterMode { "nearest", - "linear" + "linear", }; enum GPUCompareFunction { @@ -337,10 +384,10 @@ enum GPUCompareFunction { "greater", "not-equal", "greater-equal", - "always" + "always", }; -[Exposed=(Window, DedicatedWorker)] +[Exposed=(Window, DedicatedWorker), SecureContext] interface GPUBindGroupLayout { }; GPUBindGroupLayout includes GPUObjectBase; @@ -390,11 +437,11 @@ dictionary GPUSamplerBindingLayout { }; enum GPUTextureSampleType { - "float", - "unfilterable-float", - "depth", - "sint", - "uint", + "float", + "unfilterable-float", + "depth", + "sint", + "uint", }; dictionary GPUTextureBindingLayout { @@ -413,7 +460,7 @@ dictionary GPUStorageTextureBindingLayout { GPUTextureViewDimension viewDimension = "2d"; }; -[Exposed=(Window, DedicatedWorker)] +[Exposed=(Window, DedicatedWorker), SecureContext] interface GPUBindGroup { }; GPUBindGroup includes GPUObjectBase; @@ -436,7 +483,7 @@ dictionary GPUBufferBinding { GPUSize64 size; }; -[Exposed=(Window, DedicatedWorker)] +[Exposed=(Window, DedicatedWorker), SecureContext] interface GPUPipelineLayout { }; GPUPipelineLayout includes GPUObjectBase; @@ -445,7 +492,7 @@ dictionary GPUPipelineLayoutDescriptor : GPUObjectDescriptorBase { required sequence bindGroupLayouts; }; -[Exposed=(Window, DedicatedWorker)] +[Exposed=(Window, DedicatedWorker), SecureContext] interface GPUShaderModule { Promise compilationInfo(); }; @@ -459,10 +506,10 @@ dictionary GPUShaderModuleDescriptor : GPUObjectDescriptorBase { enum GPUCompilationMessageType { "error", "warning", - "info" + "info", }; -[Exposed=(Window, DedicatedWorker), Serializable] +[Exposed=(Window, DedicatedWorker), Serializable, SecureContext] interface GPUCompilationMessage { readonly attribute DOMString message; readonly attribute GPUCompilationMessageType type; @@ -472,7 +519,7 @@ interface GPUCompilationMessage { readonly attribute unsigned long long length; }; -[Exposed=(Window, DedicatedWorker), Serializable] +[Exposed=(Window, DedicatedWorker), Serializable, SecureContext] interface GPUCompilationInfo { readonly attribute FrozenArray messages; }; @@ -493,7 +540,7 @@ dictionary GPUProgrammableStage { typedef double GPUPipelineConstantValue; // May represent WGSL’s bool, f32, i32, u32. -[Exposed=(Window, DedicatedWorker)] +[Exposed=(Window, DedicatedWorker), SecureContext] interface GPUComputePipeline { }; GPUComputePipeline includes GPUObjectBase; @@ -503,7 +550,7 @@ dictionary GPUComputePipelineDescriptor : GPUPipelineDescriptorBase { required GPUProgrammableStage compute; }; -[Exposed=(Window, DedicatedWorker)] +[Exposed=(Window, DedicatedWorker), SecureContext] interface GPURenderPipeline { }; GPURenderPipeline includes GPUObjectBase; @@ -522,7 +569,7 @@ enum GPUPrimitiveTopology { "line-list", "line-strip", "triangle-list", - "triangle-strip" + "triangle-strip", }; dictionary GPUPrimitiveState { @@ -531,19 +578,19 @@ dictionary GPUPrimitiveState { GPUFrontFace frontFace = "ccw"; GPUCullMode cullMode = "none"; - // Enable depth clamping (requires "depth-clamping" feature) - boolean clampDepth = false; + // Requires "depth-clip-control" feature. + boolean unclippedDepth = false; }; enum GPUFrontFace { "ccw", - "cw" + "cw", }; enum GPUCullMode { "none", "front", - "back" + "back", }; dictionary GPUMultisampleState { @@ -552,7 +599,7 @@ dictionary GPUMultisampleState { boolean alphaToCoverageEnabled = false; }; -dictionary GPUFragmentState: GPUProgrammableStage { +dictionary GPUFragmentState : GPUProgrammableStage { required sequence targets; }; @@ -579,9 +626,9 @@ interface GPUColorWrite { }; dictionary GPUBlendComponent { + GPUBlendOperation operation = "add"; GPUBlendFactor srcFactor = "one"; GPUBlendFactor dstFactor = "zero"; - GPUBlendOperation operation = "add"; }; enum GPUBlendFactor { @@ -597,7 +644,7 @@ enum GPUBlendFactor { "one-minus-dst-alpha", "src-alpha-saturated", "constant", - "one-minus-constant" + "one-minus-constant", }; enum GPUBlendOperation { @@ -605,7 +652,7 @@ enum GPUBlendOperation { "subtract", "reverse-subtract", "min", - "max" + "max", }; dictionary GPUDepthStencilState { @@ -640,12 +687,12 @@ enum GPUStencilOperation { "increment-clamp", "decrement-clamp", "increment-wrap", - "decrement-wrap" + "decrement-wrap", }; enum GPUIndexFormat { "uint16", - "uint32" + "uint32", }; enum GPUVertexFormat { @@ -683,10 +730,10 @@ enum GPUVertexFormat { enum GPUVertexStepMode { "vertex", - "instance" + "instance", }; -dictionary GPUVertexState: GPUProgrammableStage { +dictionary GPUVertexState : GPUProgrammableStage { sequence buffers = []; }; @@ -703,16 +750,15 @@ dictionary GPUVertexAttribute { required GPUIndex32 shaderLocation; }; -[Exposed=(Window, DedicatedWorker)] +[Exposed=(Window, DedicatedWorker), SecureContext] interface GPUCommandBuffer { - readonly attribute Promise executionTime; }; GPUCommandBuffer includes GPUObjectBase; dictionary GPUCommandBufferDescriptor : GPUObjectDescriptorBase { }; -[Exposed=(Window, DedicatedWorker)] +[Exposed=(Window, DedicatedWorker), SecureContext] interface GPUCommandEncoder { GPURenderPassEncoder beginRenderPass(GPURenderPassDescriptor descriptor); GPUComputePassEncoder beginComputePass(optional GPUComputePassDescriptor descriptor = {}); @@ -739,6 +785,11 @@ interface GPUCommandEncoder { GPUImageCopyTexture destination, GPUExtent3D copySize); + undefined clearBuffer( + GPUBuffer destination, + GPUSize64 destinationOffset, + GPUSize64 size); + undefined pushDebugGroup(USVString groupLabel); undefined popDebugGroup(); undefined insertDebugMarker(USVString markerLabel); @@ -757,7 +808,6 @@ interface GPUCommandEncoder { GPUCommandEncoder includes GPUObjectBase; dictionary GPUCommandEncoderDescriptor : GPUObjectDescriptorBase { - boolean measureExecutionTime = false; }; dictionary GPUImageDataLayout { @@ -791,7 +841,7 @@ interface mixin GPUProgrammablePassEncoder { undefined insertDebugMarker(USVString markerLabel); }; -[Exposed=(Window, DedicatedWorker)] +[Exposed=(Window, DedicatedWorker), SecureContext] interface GPUComputePassEncoder { undefined setPipeline(GPUComputePipeline pipeline); undefined dispatch(GPUSize32 x, optional GPUSize32 y = 1, optional GPUSize32 z = 1); @@ -827,7 +877,7 @@ interface mixin GPURenderEncoderBase { undefined drawIndexedIndirect(GPUBuffer indirectBuffer, GPUSize64 indirectOffset); }; -[Exposed=(Window, DedicatedWorker)] +[Exposed=(Window, DedicatedWorker), SecureContext] interface GPURenderPassEncoder { undefined setViewport(float x, float y, float width, float height, @@ -881,12 +931,12 @@ dictionary GPURenderPassDepthStencilAttachment { }; enum GPULoadOp { - "load" + "load", }; enum GPUStoreOp { "store", - "discard" + "discard", }; dictionary GPURenderPassLayout: GPUObjectDescriptorBase { @@ -895,7 +945,7 @@ dictionary GPURenderPassLayout: GPUObjectDescriptorBase { GPUSize32 sampleCount = 1; }; -[Exposed=(Window, DedicatedWorker)] +[Exposed=(Window, DedicatedWorker), SecureContext] interface GPURenderBundle { }; GPURenderBundle includes GPUObjectBase; @@ -903,7 +953,7 @@ GPURenderBundle includes GPUObjectBase; dictionary GPURenderBundleDescriptor : GPUObjectDescriptorBase { }; -[Exposed=(Window, DedicatedWorker)] +[Exposed=(Window, DedicatedWorker), SecureContext] interface GPURenderBundleEncoder { GPURenderBundle finish(optional GPURenderBundleDescriptor descriptor = {}); }; @@ -916,7 +966,7 @@ dictionary GPURenderBundleEncoderDescriptor : GPURenderPassLayout { boolean stencilReadOnly = false; }; -[Exposed=(Window, DedicatedWorker)] +[Exposed=(Window, DedicatedWorker), SecureContext] interface GPUQueue { undefined submit(sequence commandBuffers); @@ -930,14 +980,14 @@ interface GPUQueue { optional GPUSize64 size); undefined writeTexture( - GPUImageCopyTexture destination, - [AllowShared] BufferSource data, - GPUImageDataLayout dataLayout, - GPUExtent3D size); + GPUImageCopyTexture destination, + [AllowShared] BufferSource data, + GPUImageDataLayout dataLayout, + GPUExtent3D size); }; GPUQueue includes GPUObjectBase; -[Exposed=(Window, DedicatedWorker)] +[Exposed=(Window, DedicatedWorker), SecureContext] interface GPUQuerySet { undefined destroy(); }; @@ -952,7 +1002,7 @@ dictionary GPUQuerySetDescriptor : GPUObjectDescriptorBase { enum GPUQueryType { "occlusion", "pipeline-statistics", - "timestamp" + "timestamp", }; enum GPUPipelineStatisticName { @@ -960,14 +1010,14 @@ enum GPUPipelineStatisticName { "clipper-invocations", "clipper-primitives-out", "fragment-shader-invocations", - "compute-shader-invocations" + "compute-shader-invocations", }; enum GPUDeviceLostReason { "destroyed", }; -[Exposed=(Window, DedicatedWorker)] +[Exposed=(Window, DedicatedWorker), SecureContext] interface GPUDeviceLostInfo { readonly attribute (GPUDeviceLostReason or undefined) reason; readonly attribute DOMString message; @@ -979,15 +1029,15 @@ partial interface GPUDevice { enum GPUErrorFilter { "out-of-memory", - "validation" + "validation", }; -[Exposed=(Window, DedicatedWorker)] +[Exposed=(Window, DedicatedWorker), SecureContext] interface GPUOutOfMemoryError { constructor(); }; -[Exposed=(Window, DedicatedWorker)] +[Exposed=(Window, DedicatedWorker), SecureContext] interface GPUValidationError { constructor(DOMString message); readonly attribute DOMString message; @@ -1000,9 +1050,7 @@ partial interface GPUDevice { Promise popErrorScope(); }; -[ - Exposed=(Window, DedicatedWorker) -] +[Exposed=(Window, DedicatedWorker), SecureContext] interface GPUUncapturedErrorEvent : Event { constructor( DOMString type, @@ -1060,3 +1108,4 @@ dictionary GPUExtent3DDict { GPUIntegerCoordinate depthOrArrayLayers = 1; }; typedef (sequence or GPUExtent3DDict) GPUExtent3D; + diff --git a/tools/wgpu_sync.js b/tools/wgpu_sync.js new file mode 100755 index 00000000000000..211866fe0b0bea --- /dev/null +++ b/tools/wgpu_sync.js @@ -0,0 +1,59 @@ +#!/usr/bin/env -S deno run --unstable --allow-read --allow-write --allow-run +// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. + +import { join, ROOT_PATH } from './util.js'; + + +const COMMIT = "c00e471274b6c21acda89b4b13d41742c0285d71"; // Release 12 +const REPO = "gfx-rs/wgpu"; +const V_WGPU = "0.12.0"; +const V_DENO_CORE = "0.114.0"; +const TARGET_DIR = join(ROOT_PATH, 'ext', 'webgpu'); + + +async function bashThrough(subcmd, opts = {}) { + const p = Deno.run({ ...opts, cmd: ["bash", "-c", subcmd] }); + + // Exit process on failure + const { success, code } = await p.status(); + if (!success) { + Deno.exit(code); + } + // Cleanup + p.close(); +} + +async function clearTargetDir() { + await bashThrough(`rm -r ${TARGET_DIR}/*`); +} + +async function checkoutUpstream() { + // Path of deno_webgpu inside the TAR + const tarPrefix = `gfx-rs-wgpu-${COMMIT.slice(0, 7)}/deno_webgpu/`; + const cmd = `curl -L https://api.github.com/repos/${REPO}/tarball/${COMMIT} | tar -C '${TARGET_DIR}' -xzvf - --strip=2 '${tarPrefix}'`; + // console.log(cmd); + await bashThrough(cmd); +} + +async function patchCargo() { + const webgpuCargo = join(ROOT_PATH, 'ext', 'webgpu', 'Cargo.toml'); + const data = await Deno.readTextFile(webgpuCargo); + + // Patch ext/webgpu/Cargo.toml's contents + const patched = data + .replace(`version = "0.17.0"`, `version = "0.33.0"`) + .replace(`edition = "2018"`, `edition = "2021"`) + .replace(/^deno_core \= .*$/gm, `deno_core = { version = "${V_DENO_CORE}", path = "../../core" }`) + .replace(/^wgpu-core \= .*$/gm, `wgpu-core = { version = "${V_WGPU}", features = ["trace", "replay", "serde"] }`) + .replace(/^wgpu-types \= .*$/gm, `wgpu-types = { version = "${V_WGPU}", features = ["trace", "replay", "serde"] }`) + + await Deno.writeTextFile(webgpuCargo, patched); +} + +async function main() { + await clearTargetDir(); + await checkoutUpstream(); + await patchCargo(); +} + +await main(); From 7558b585c048e7bafe99ddd6c48d64de153032c0 Mon Sep 17 00:00:00 2001 From: Aaron O'Mullan Date: Mon, 17 Jan 2022 22:12:41 +0100 Subject: [PATCH 02/16] sync against tip --- Cargo.lock | 17 +++++++---------- ext/webgpu/Cargo.toml | 4 ++-- ext/webgpu/src/lib.rs | 6 +++--- tools/wgpu_sync.js | 33 ++++++++++++++++++++++----------- 4 files changed, 34 insertions(+), 26 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 117d6c40a53c96..861275b1b1999e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -136,9 +136,9 @@ dependencies = [ [[package]] name = "ash" -version = "0.34.0+1.2.203" +version = "0.33.3+1.2.191" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0f780da53d0063880d45554306489f09dd8d1bda47688b4a57bc579119356df" +checksum = "cc4f1d82f164f838ae413296d1131aa6fa79b917d25bebaa7033d25620c09219" dependencies = [ "libloading", ] @@ -4893,9 +4893,8 @@ dependencies = [ [[package]] name = "wgpu-core" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4688c000eb841ca55f7b35db659b78d6e1cd77d7caf8fb929f4e181f754047d" +version = "0.12.0" +source = "git+https://github.com/gfx-rs/wgpu?rev=c00e471274b6c21acda89b4b13d41742c0285d71#c00e471274b6c21acda89b4b13d41742c0285d71" dependencies = [ "arrayvec 0.7.2", "bitflags", @@ -4917,9 +4916,8 @@ dependencies = [ [[package]] name = "wgpu-hal" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92e33cb9c380dd1166f316dfc511ad9646f72cf2deb47e90bd714db3617a6998" +version = "0.12.0" +source = "git+https://github.com/gfx-rs/wgpu?rev=c00e471274b6c21acda89b4b13d41742c0285d71#c00e471274b6c21acda89b4b13d41742c0285d71" dependencies = [ "arrayvec 0.7.2", "ash", @@ -4956,8 +4954,7 @@ dependencies = [ [[package]] name = "wgpu-types" version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "549533d9e1cdd4b4cda7718d33ff500fc4c34b5467b71d76b547ae0324f3b2a2" +source = "git+https://github.com/gfx-rs/wgpu?rev=c00e471274b6c21acda89b4b13d41742c0285d71#c00e471274b6c21acda89b4b13d41742c0285d71" dependencies = [ "bitflags", "bitflags_serde_shim", diff --git a/ext/webgpu/Cargo.toml b/ext/webgpu/Cargo.toml index de5bf7ed4c45ef..741027e292780b 100644 --- a/ext/webgpu/Cargo.toml +++ b/ext/webgpu/Cargo.toml @@ -14,5 +14,5 @@ description = "WebGPU implementation for Deno" deno_core = { version = "0.114.0", path = "../../core" } serde = { version = "1.0", features = ["derive"] } tokio = { version = "1.10", features = ["full"] } -wgpu-core = { version = "0.12.0", features = ["trace", "replay", "serde"] } -wgpu-types = { version = "0.12.0", features = ["trace", "replay", "serde"] } +wgpu-core = { git = "https://github.com/gfx-rs/wgpu", rev = "0183e7d1e85ac95f2461426a910b2f86f5373119", features = ["trace", "replay", "serde"] } +wgpu-types = { git = "https://github.com/gfx-rs/wgpu", rev = "0183e7d1e85ac95f2461426a910b2f86f5373119", features = ["trace", "replay", "serde"] } diff --git a/ext/webgpu/src/lib.rs b/ext/webgpu/src/lib.rs index db5ac1a8cf9204..fa193e5704f4f9 100644 --- a/ext/webgpu/src/lib.rs +++ b/ext/webgpu/src/lib.rs @@ -202,8 +202,8 @@ fn deserialize_features(features: &wgpu_types::Features) -> Vec<&'static str> { if features.contains(wgpu_types::Features::VERTEX_WRITABLE_STORAGE) { return_features.push("vertex-writable-storage"); } - if features.contains(wgpu_types::Features::CLEAR_COMMANDS) { - return_features.push("clear-commands"); + if features.contains(wgpu_types::Features::CLEAR_TEXTURE) { + return_features.push("clear-texture"); } if features.contains(wgpu_types::Features::SPIRV_SHADER_PASSTHROUGH) { return_features.push("spirv-shader-passthrough"); @@ -417,7 +417,7 @@ impl From for wgpu_types::Features { required_features.0.contains("vertex-writable-storage"), ); features.set( - wgpu_types::Features::CLEAR_COMMANDS, + wgpu_types::Features::CLEAR_TEXTURE, required_features.0.contains("clear-commands"), ); features.set( diff --git a/tools/wgpu_sync.js b/tools/wgpu_sync.js index 211866fe0b0bea..49b939fc55cdf7 100755 --- a/tools/wgpu_sync.js +++ b/tools/wgpu_sync.js @@ -1,15 +1,14 @@ #!/usr/bin/env -S deno run --unstable --allow-read --allow-write --allow-run // Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. -import { join, ROOT_PATH } from './util.js'; +import { join, ROOT_PATH } from "./util.js"; - -const COMMIT = "c00e471274b6c21acda89b4b13d41742c0285d71"; // Release 12 +// const COMMIT = "c00e471274b6c21acda89b4b13d41742c0285d71"; // Release 12 +const COMMIT = "0183e7d1e85ac95f2461426a910b2f86f5373119"; // tip const REPO = "gfx-rs/wgpu"; const V_WGPU = "0.12.0"; const V_DENO_CORE = "0.114.0"; -const TARGET_DIR = join(ROOT_PATH, 'ext', 'webgpu'); - +const TARGET_DIR = join(ROOT_PATH, "ext", "webgpu"); async function bashThrough(subcmd, opts = {}) { const p = Deno.run({ ...opts, cmd: ["bash", "-c", subcmd] }); @@ -30,22 +29,34 @@ async function clearTargetDir() { async function checkoutUpstream() { // Path of deno_webgpu inside the TAR const tarPrefix = `gfx-rs-wgpu-${COMMIT.slice(0, 7)}/deno_webgpu/`; - const cmd = `curl -L https://api.github.com/repos/${REPO}/tarball/${COMMIT} | tar -C '${TARGET_DIR}' -xzvf - --strip=2 '${tarPrefix}'`; + const cmd = + `curl -L https://api.github.com/repos/${REPO}/tarball/${COMMIT} | tar -C '${TARGET_DIR}' -xzvf - --strip=2 '${tarPrefix}'`; // console.log(cmd); await bashThrough(cmd); } async function patchCargo() { - const webgpuCargo = join(ROOT_PATH, 'ext', 'webgpu', 'Cargo.toml'); + const webgpuCargo = join(ROOT_PATH, "ext", "webgpu", "Cargo.toml"); const data = await Deno.readTextFile(webgpuCargo); - + // Patch ext/webgpu/Cargo.toml's contents const patched = data .replace(`version = "0.17.0"`, `version = "0.33.0"`) .replace(`edition = "2018"`, `edition = "2021"`) - .replace(/^deno_core \= .*$/gm, `deno_core = { version = "${V_DENO_CORE}", path = "../../core" }`) - .replace(/^wgpu-core \= .*$/gm, `wgpu-core = { version = "${V_WGPU}", features = ["trace", "replay", "serde"] }`) - .replace(/^wgpu-types \= .*$/gm, `wgpu-types = { version = "${V_WGPU}", features = ["trace", "replay", "serde"] }`) + .replace( + /^deno_core \= .*$/gm, + `deno_core = { version = "${V_DENO_CORE}", path = "../../core" }`, + ) + // .replace(/^wgpu-core \= .*$/gm, `wgpu-core = { version = "${V_WGPU}", features = ["trace", "replay", "serde"] }`) + // .replace(/^wgpu-types \= .*$/gm, `wgpu-types = { version = "${V_WGPU}", features = ["trace", "replay", "serde"] }`) + .replace( + /^wgpu-core \= .*$/gm, + `wgpu-core = { git = "https://github.com/${REPO}", rev = "${COMMIT}", features = ["trace", "replay", "serde"] }`, + ) + .replace( + /^wgpu-types \= .*$/gm, + `wgpu-types = { git = "https://github.com/${REPO}", rev = "${COMMIT}", features = ["trace", "replay", "serde"] }`, + ); await Deno.writeTextFile(webgpuCargo, patched); } From f75824099d14b3c6f9ccd291afb3c6aea7b84403 Mon Sep 17 00:00:00 2001 From: Aaron O'Mullan Date: Mon, 17 Jan 2022 22:13:15 +0100 Subject: [PATCH 03/16] fmt --- ext/webgpu/01_webgpu.js | 53 +- ext/webgpu/src/binding.rs | 418 +++++---- ext/webgpu/src/buffer.rs | 300 +++--- ext/webgpu/src/bundle.rs | 632 +++++++------ ext/webgpu/src/command_encoder.rs | 882 +++++++++--------- ext/webgpu/src/compute_pass.rs | 455 ++++----- ext/webgpu/src/error.rs | 279 +++--- ext/webgpu/src/lib.rs | 1442 +++++++++++++++-------------- ext/webgpu/src/pipeline.rs | 581 ++++++------ ext/webgpu/src/queue.rs | 173 ++-- ext/webgpu/src/render_pass.rs | 830 ++++++++--------- ext/webgpu/src/sampler.rs | 80 +- ext/webgpu/src/shader.rs | 43 +- ext/webgpu/src/texture.rs | 128 +-- 14 files changed, 3205 insertions(+), 3091 deletions(-) diff --git a/ext/webgpu/01_webgpu.js b/ext/webgpu/01_webgpu.js index ec1c5a81393eed..fa412ca17e2139 100644 --- a/ext/webgpu/01_webgpu.js +++ b/ext/webgpu/01_webgpu.js @@ -219,10 +219,10 @@ */ /** - * @param {string} name - * @param {InnerGPUAdapter} inner - * @returns {GPUAdapter} - */ + * @param {string} name + * @param {InnerGPUAdapter} inner + * @returns {GPUAdapter} + */ function createGPUAdapter(name, inner) { /** @type {GPUAdapter} */ const adapter = webidl.createBranded(GPUAdapter); @@ -544,7 +544,6 @@ const _message = Symbol("[[message]]"); /** - * * @param {string | undefined} reason * @param {string} message * @returns {GPUDeviceLostInfo} @@ -850,7 +849,7 @@ descriptor.usage, options, ); - device.trackResource((buffer)); + device.trackResource(buffer); return buffer; } @@ -879,7 +878,7 @@ device, rid, ); - device.trackResource((texture)); + device.trackResource(texture); return texture; } @@ -906,7 +905,7 @@ device, rid, ); - device.trackResource((sampler)); + device.trackResource(sampler); return sampler; } @@ -949,7 +948,7 @@ device, rid, ); - device.trackResource((bindGroupLayout)); + device.trackResource(bindGroupLayout); return bindGroupLayout; } @@ -991,7 +990,7 @@ device, rid, ); - device.trackResource((pipelineLayout)); + device.trackResource(pipelineLayout); return pipelineLayout; } @@ -1084,7 +1083,7 @@ device, rid, ); - device.trackResource((bindGroup)); + device.trackResource(bindGroup); return bindGroup; } @@ -1116,7 +1115,7 @@ device, rid, ); - device.trackResource((shaderModule)); + device.trackResource(shaderModule); return shaderModule; } @@ -1173,7 +1172,7 @@ device, rid, ); - device.trackResource((computePipeline)); + device.trackResource(computePipeline); return computePipeline; } @@ -1248,7 +1247,7 @@ device, rid, ); - device.trackResource((renderPipeline)); + device.trackResource(renderPipeline); return renderPipeline; } @@ -1285,7 +1284,7 @@ device, rid, ); - device.trackResource((commandEncoder)); + device.trackResource(commandEncoder); return commandEncoder; } @@ -1320,7 +1319,7 @@ device, rid, ); - device.trackResource((renderBundleEncoder)); + device.trackResource(renderBundleEncoder); return renderBundleEncoder; } @@ -1352,7 +1351,7 @@ rid, descriptor, ); - device.trackResource((querySet)); + device.trackResource(querySet); return querySet; } @@ -2269,8 +2268,8 @@ /** * @param {string | null} label - * @param {InnerGPUDevice} device - * @param {number} rid + * @param {InnerGPUDevice} device + * @param {number} rid * @returns {GPUBindGroup} */ function createGPUBindGroup(label, device, rid) { @@ -2312,8 +2311,8 @@ /** * @param {string | null} label - * @param {InnerGPUDevice} device - * @param {number} rid + * @param {InnerGPUDevice} device + * @param {number} rid * @returns {GPUShaderModule} */ function createGPUShaderModule(label, device, rid) { @@ -2437,7 +2436,7 @@ device, rid, ); - device.trackResource((bindGroupLayout)); + device.trackResource(bindGroupLayout); return bindGroupLayout; } @@ -2512,7 +2511,7 @@ device, rid, ); - device.trackResource((bindGroupLayout)); + device.trackResource(bindGroupLayout); return bindGroupLayout; } @@ -3068,8 +3067,7 @@ */ clearBuffer(destination, destinationOffset, size) { webidl.assertBranded(this, GPUCommandEncoder); - const prefix = - "Failed to execute 'clearBuffer' on 'GPUCommandEncoder'"; + const prefix = "Failed to execute 'clearBuffer' on 'GPUCommandEncoder'"; webidl.requiredArguments(arguments.length, 3, { prefix }); destination = webidl.converters.GPUBuffer(destination, { prefix, @@ -3321,7 +3319,7 @@ device, rid, ); - device.trackResource((commandBuffer)); + device.trackResource(commandBuffer); return commandBuffer; } @@ -3420,7 +3418,6 @@ } /** - * * @param {number} x * @param {number} y * @param {number} width @@ -4646,7 +4643,7 @@ device, rid, ); - device.trackResource((renderBundle)); + device.trackResource(renderBundle); return renderBundle; } diff --git a/ext/webgpu/src/binding.rs b/ext/webgpu/src/binding.rs index 68915c3531bdcc..d9a4b57574aed3 100644 --- a/ext/webgpu/src/binding.rs +++ b/ext/webgpu/src/binding.rs @@ -9,194 +9,203 @@ use std::convert::{TryFrom, TryInto}; use super::error::WebGpuResult; -pub(crate) struct WebGpuBindGroupLayout(pub(crate) wgpu_core::id::BindGroupLayoutId); +pub(crate) struct WebGpuBindGroupLayout( + pub(crate) wgpu_core::id::BindGroupLayoutId, +); impl Resource for WebGpuBindGroupLayout { - fn name(&self) -> Cow { - "webGPUBindGroupLayout".into() - } + fn name(&self) -> Cow { + "webGPUBindGroupLayout".into() + } } pub(crate) struct WebGpuBindGroup(pub(crate) wgpu_core::id::BindGroupId); impl Resource for WebGpuBindGroup { - fn name(&self) -> Cow { - "webGPUBindGroup".into() - } + fn name(&self) -> Cow { + "webGPUBindGroup".into() + } } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct GpuBufferBindingLayout { - r#type: GpuBufferBindingType, - has_dynamic_offset: bool, - min_binding_size: u64, + r#type: GpuBufferBindingType, + has_dynamic_offset: bool, + min_binding_size: u64, } #[derive(Deserialize)] #[serde(rename_all = "kebab-case")] enum GpuBufferBindingType { - Uniform, - Storage, - ReadOnlyStorage, + Uniform, + Storage, + ReadOnlyStorage, } impl From for wgpu_types::BufferBindingType { - fn from(binding_type: GpuBufferBindingType) -> Self { - match binding_type { - GpuBufferBindingType::Uniform => wgpu_types::BufferBindingType::Uniform, - GpuBufferBindingType::Storage => { - wgpu_types::BufferBindingType::Storage { read_only: false } - } - GpuBufferBindingType::ReadOnlyStorage => { - wgpu_types::BufferBindingType::Storage { read_only: true } - } - } + fn from(binding_type: GpuBufferBindingType) -> Self { + match binding_type { + GpuBufferBindingType::Uniform => wgpu_types::BufferBindingType::Uniform, + GpuBufferBindingType::Storage => { + wgpu_types::BufferBindingType::Storage { read_only: false } + } + GpuBufferBindingType::ReadOnlyStorage => { + wgpu_types::BufferBindingType::Storage { read_only: true } + } } + } } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct GpuSamplerBindingLayout { - r#type: wgpu_types::SamplerBindingType, + r#type: wgpu_types::SamplerBindingType, } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct GpuTextureBindingLayout { - sample_type: GpuTextureSampleType, - view_dimension: wgpu_types::TextureViewDimension, - multisampled: bool, + sample_type: GpuTextureSampleType, + view_dimension: wgpu_types::TextureViewDimension, + multisampled: bool, } #[derive(Deserialize)] #[serde(rename_all = "kebab-case")] enum GpuTextureSampleType { - Float, - UnfilterableFloat, - Depth, - Sint, - Uint, + Float, + UnfilterableFloat, + Depth, + Sint, + Uint, } impl From for wgpu_types::TextureSampleType { - fn from(sample_type: GpuTextureSampleType) -> Self { - match sample_type { - GpuTextureSampleType::Float => { - wgpu_types::TextureSampleType::Float { filterable: true } - } - GpuTextureSampleType::UnfilterableFloat => { - wgpu_types::TextureSampleType::Float { filterable: false } - } - GpuTextureSampleType::Depth => wgpu_types::TextureSampleType::Depth, - GpuTextureSampleType::Sint => wgpu_types::TextureSampleType::Sint, - GpuTextureSampleType::Uint => wgpu_types::TextureSampleType::Uint, - } + fn from(sample_type: GpuTextureSampleType) -> Self { + match sample_type { + GpuTextureSampleType::Float => { + wgpu_types::TextureSampleType::Float { filterable: true } + } + GpuTextureSampleType::UnfilterableFloat => { + wgpu_types::TextureSampleType::Float { filterable: false } + } + GpuTextureSampleType::Depth => wgpu_types::TextureSampleType::Depth, + GpuTextureSampleType::Sint => wgpu_types::TextureSampleType::Sint, + GpuTextureSampleType::Uint => wgpu_types::TextureSampleType::Uint, } + } } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct GpuStorageTextureBindingLayout { - access: GpuStorageTextureAccess, - format: wgpu_types::TextureFormat, - view_dimension: wgpu_types::TextureViewDimension, + access: GpuStorageTextureAccess, + format: wgpu_types::TextureFormat, + view_dimension: wgpu_types::TextureViewDimension, } #[derive(Deserialize)] #[serde(rename_all = "kebab-case")] enum GpuStorageTextureAccess { - WriteOnly, + WriteOnly, } impl From for wgpu_types::StorageTextureAccess { - fn from(access: GpuStorageTextureAccess) -> Self { - match access { - GpuStorageTextureAccess::WriteOnly => wgpu_types::StorageTextureAccess::WriteOnly, - } + fn from(access: GpuStorageTextureAccess) -> Self { + match access { + GpuStorageTextureAccess::WriteOnly => { + wgpu_types::StorageTextureAccess::WriteOnly + } } + } } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct GpuBindGroupLayoutEntry { - binding: u32, - visibility: u32, - #[serde(flatten)] - binding_type: GpuBindingType, + binding: u32, + visibility: u32, + #[serde(flatten)] + binding_type: GpuBindingType, } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] enum GpuBindingType { - Buffer(GpuBufferBindingLayout), - Sampler(GpuSamplerBindingLayout), - Texture(GpuTextureBindingLayout), - StorageTexture(GpuStorageTextureBindingLayout), + Buffer(GpuBufferBindingLayout), + Sampler(GpuSamplerBindingLayout), + Texture(GpuTextureBindingLayout), + StorageTexture(GpuStorageTextureBindingLayout), } impl TryFrom for wgpu_types::BindingType { - type Error = AnyError; - - fn try_from(binding_type: GpuBindingType) -> Result { - let binding_type = match binding_type { - GpuBindingType::Buffer(buffer) => wgpu_types::BindingType::Buffer { - ty: buffer.r#type.into(), - has_dynamic_offset: buffer.has_dynamic_offset, - min_binding_size: std::num::NonZeroU64::new(buffer.min_binding_size), - }, - GpuBindingType::Sampler(sampler) => wgpu_types::BindingType::Sampler(sampler.r#type), - GpuBindingType::Texture(texture) => wgpu_types::BindingType::Texture { - sample_type: texture.sample_type.into(), - view_dimension: texture.view_dimension, - multisampled: texture.multisampled, - }, - GpuBindingType::StorageTexture(storage_texture) => { - wgpu_types::BindingType::StorageTexture { - access: storage_texture.access.into(), - format: storage_texture.format, - view_dimension: storage_texture.view_dimension, - } - } - }; - Ok(binding_type) - } + type Error = AnyError; + + fn try_from( + binding_type: GpuBindingType, + ) -> Result { + let binding_type = match binding_type { + GpuBindingType::Buffer(buffer) => wgpu_types::BindingType::Buffer { + ty: buffer.r#type.into(), + has_dynamic_offset: buffer.has_dynamic_offset, + min_binding_size: std::num::NonZeroU64::new(buffer.min_binding_size), + }, + GpuBindingType::Sampler(sampler) => { + wgpu_types::BindingType::Sampler(sampler.r#type) + } + GpuBindingType::Texture(texture) => wgpu_types::BindingType::Texture { + sample_type: texture.sample_type.into(), + view_dimension: texture.view_dimension, + multisampled: texture.multisampled, + }, + GpuBindingType::StorageTexture(storage_texture) => { + wgpu_types::BindingType::StorageTexture { + access: storage_texture.access.into(), + format: storage_texture.format, + view_dimension: storage_texture.view_dimension, + } + } + }; + Ok(binding_type) + } } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct CreateBindGroupLayoutArgs { - device_rid: ResourceId, - label: Option, - entries: Vec, + device_rid: ResourceId, + label: Option, + entries: Vec, } pub fn op_webgpu_create_bind_group_layout( - state: &mut OpState, - args: CreateBindGroupLayoutArgs, - _: (), + state: &mut OpState, + args: CreateBindGroupLayoutArgs, + _: (), ) -> Result { - let instance = state.borrow::(); - let device_resource = state - .resource_table - .get::(args.device_rid)?; - let device = device_resource.0; - - let mut entries = vec![]; - - for entry in args.entries { - entries.push(wgpu_types::BindGroupLayoutEntry { - binding: entry.binding, - visibility: wgpu_types::ShaderStages::from_bits(entry.visibility).unwrap(), - ty: entry.binding_type.try_into()?, - count: None, // native-only - }); - } - - let descriptor = wgpu_core::binding_model::BindGroupLayoutDescriptor { - label: args.label.map(Cow::from), - entries: Cow::from(entries), - }; - - gfx_put!(device => instance.device_create_bind_group_layout( + let instance = state.borrow::(); + let device_resource = state + .resource_table + .get::(args.device_rid)?; + let device = device_resource.0; + + let mut entries = vec![]; + + for entry in args.entries { + entries.push(wgpu_types::BindGroupLayoutEntry { + binding: entry.binding, + visibility: wgpu_types::ShaderStages::from_bits(entry.visibility) + .unwrap(), + ty: entry.binding_type.try_into()?, + count: None, // native-only + }); + } + + let descriptor = wgpu_core::binding_model::BindGroupLayoutDescriptor { + label: args.label.map(Cow::from), + entries: Cow::from(entries), + }; + + gfx_put!(device => instance.device_create_bind_group_layout( device, &descriptor, std::marker::PhantomData @@ -206,36 +215,37 @@ pub fn op_webgpu_create_bind_group_layout( #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct CreatePipelineLayoutArgs { - device_rid: ResourceId, - label: Option, - bind_group_layouts: Vec, + device_rid: ResourceId, + label: Option, + bind_group_layouts: Vec, } pub fn op_webgpu_create_pipeline_layout( - state: &mut OpState, - args: CreatePipelineLayoutArgs, - _: (), + state: &mut OpState, + args: CreatePipelineLayoutArgs, + _: (), ) -> Result { - let instance = state.borrow::(); - let device_resource = state - .resource_table - .get::(args.device_rid)?; - let device = device_resource.0; - - let mut bind_group_layouts = vec![]; - - for rid in &args.bind_group_layouts { - let bind_group_layout = state.resource_table.get::(*rid)?; - bind_group_layouts.push(bind_group_layout.0); - } - - let descriptor = wgpu_core::binding_model::PipelineLayoutDescriptor { - label: args.label.map(Cow::from), - bind_group_layouts: Cow::from(bind_group_layouts), - push_constant_ranges: Default::default(), - }; - - gfx_put!(device => instance.device_create_pipeline_layout( + let instance = state.borrow::(); + let device_resource = state + .resource_table + .get::(args.device_rid)?; + let device = device_resource.0; + + let mut bind_group_layouts = vec![]; + + for rid in &args.bind_group_layouts { + let bind_group_layout = + state.resource_table.get::(*rid)?; + bind_group_layouts.push(bind_group_layout.0); + } + + let descriptor = wgpu_core::binding_model::PipelineLayoutDescriptor { + label: args.label.map(Cow::from), + bind_group_layouts: Cow::from(bind_group_layouts), + push_constant_ranges: Default::default(), + }; + + gfx_put!(device => instance.device_create_pipeline_layout( device, &descriptor, std::marker::PhantomData @@ -245,81 +255,85 @@ pub fn op_webgpu_create_pipeline_layout( #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct GpuBindGroupEntry { - binding: u32, - kind: String, - resource: ResourceId, - offset: Option, - size: Option, + binding: u32, + kind: String, + resource: ResourceId, + offset: Option, + size: Option, } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct CreateBindGroupArgs { - device_rid: ResourceId, - label: Option, - layout: ResourceId, - entries: Vec, + device_rid: ResourceId, + label: Option, + layout: ResourceId, + entries: Vec, } pub fn op_webgpu_create_bind_group( - state: &mut OpState, - args: CreateBindGroupArgs, - _: (), + state: &mut OpState, + args: CreateBindGroupArgs, + _: (), ) -> Result { - let instance = state.borrow::(); - let device_resource = state - .resource_table - .get::(args.device_rid)?; - let device = device_resource.0; - - let mut entries = vec![]; - - for entry in &args.entries { - let e = wgpu_core::binding_model::BindGroupEntry { - binding: entry.binding, - resource: match entry.kind.as_str() { - "GPUSampler" => { - let sampler_resource = state - .resource_table - .get::(entry.resource)?; - wgpu_core::binding_model::BindingResource::Sampler(sampler_resource.0) - } - "GPUTextureView" => { - let texture_view_resource = - state - .resource_table - .get::(entry.resource)?; - wgpu_core::binding_model::BindingResource::TextureView(texture_view_resource.0) - } - "GPUBufferBinding" => { - let buffer_resource = state - .resource_table - .get::(entry.resource)?; - wgpu_core::binding_model::BindingResource::Buffer( - wgpu_core::binding_model::BufferBinding { - buffer_id: buffer_resource.0, - offset: entry.offset.unwrap_or(0), - size: std::num::NonZeroU64::new(entry.size.unwrap_or(0)), - }, - ) - } - _ => unreachable!(), + let instance = state.borrow::(); + let device_resource = state + .resource_table + .get::(args.device_rid)?; + let device = device_resource.0; + + let mut entries = vec![]; + + for entry in &args.entries { + let e = wgpu_core::binding_model::BindGroupEntry { + binding: entry.binding, + resource: match entry.kind.as_str() { + "GPUSampler" => { + let sampler_resource = + state + .resource_table + .get::(entry.resource)?; + wgpu_core::binding_model::BindingResource::Sampler(sampler_resource.0) + } + "GPUTextureView" => { + let texture_view_resource = + state + .resource_table + .get::(entry.resource)?; + wgpu_core::binding_model::BindingResource::TextureView( + texture_view_resource.0, + ) + } + "GPUBufferBinding" => { + let buffer_resource = + state + .resource_table + .get::(entry.resource)?; + wgpu_core::binding_model::BindingResource::Buffer( + wgpu_core::binding_model::BufferBinding { + buffer_id: buffer_resource.0, + offset: entry.offset.unwrap_or(0), + size: std::num::NonZeroU64::new(entry.size.unwrap_or(0)), }, - }; - entries.push(e); - } + ) + } + _ => unreachable!(), + }, + }; + entries.push(e); + } - let bind_group_layout = state - .resource_table - .get::(args.layout)?; + let bind_group_layout = state + .resource_table + .get::(args.layout)?; - let descriptor = wgpu_core::binding_model::BindGroupDescriptor { - label: args.label.map(Cow::from), - layout: bind_group_layout.0, - entries: Cow::from(entries), - }; + let descriptor = wgpu_core::binding_model::BindGroupDescriptor { + label: args.label.map(Cow::from), + layout: bind_group_layout.0, + entries: Cow::from(entries), + }; - gfx_put!(device => instance.device_create_bind_group( + gfx_put!(device => instance.device_create_bind_group( device, &descriptor, std::marker::PhantomData diff --git a/ext/webgpu/src/buffer.rs b/ext/webgpu/src/buffer.rs index e93318b2d83df7..30818194fab932 100644 --- a/ext/webgpu/src/buffer.rs +++ b/ext/webgpu/src/buffer.rs @@ -18,48 +18,48 @@ use super::error::WebGpuResult; pub(crate) struct WebGpuBuffer(pub(crate) wgpu_core::id::BufferId); impl Resource for WebGpuBuffer { - fn name(&self) -> Cow { - "webGPUBuffer".into() - } + fn name(&self) -> Cow { + "webGPUBuffer".into() + } } struct WebGpuBufferMapped(*mut u8, usize); impl Resource for WebGpuBufferMapped { - fn name(&self) -> Cow { - "webGPUBufferMapped".into() - } + fn name(&self) -> Cow { + "webGPUBufferMapped".into() + } } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct CreateBufferArgs { - device_rid: ResourceId, - label: Option, - size: u64, - usage: u32, - mapped_at_creation: bool, + device_rid: ResourceId, + label: Option, + size: u64, + usage: u32, + mapped_at_creation: bool, } pub fn op_webgpu_create_buffer( - state: &mut OpState, - args: CreateBufferArgs, - _: (), + state: &mut OpState, + args: CreateBufferArgs, + _: (), ) -> Result { - let instance = state.borrow::(); - let device_resource = state - .resource_table - .get::(args.device_rid)?; - let device = device_resource.0; - - let descriptor = wgpu_core::resource::BufferDescriptor { - label: args.label.map(Cow::from), - size: args.size, - usage: wgpu_types::BufferUsages::from_bits(args.usage) - .ok_or_else(|| type_error("usage is not valid"))?, - mapped_at_creation: args.mapped_at_creation, - }; - - gfx_put!(device => instance.device_create_buffer( + let instance = state.borrow::(); + let device_resource = state + .resource_table + .get::(args.device_rid)?; + let device = device_resource.0; + + let descriptor = wgpu_core::resource::BufferDescriptor { + label: args.label.map(Cow::from), + size: args.size, + usage: wgpu_types::BufferUsages::from_bits(args.usage) + .ok_or_else(|| type_error("usage is not valid"))?, + mapped_at_creation: args.mapped_at_creation, + }; + + gfx_put!(device => instance.device_create_buffer( device, &descriptor, std::marker::PhantomData @@ -69,155 +69,161 @@ pub fn op_webgpu_create_buffer( #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct BufferGetMapAsyncArgs { - buffer_rid: ResourceId, - device_rid: ResourceId, - mode: u32, - offset: u64, - size: u64, + buffer_rid: ResourceId, + device_rid: ResourceId, + mode: u32, + offset: u64, + size: u64, } pub async fn op_webgpu_buffer_get_map_async( - state: Rc>, - args: BufferGetMapAsyncArgs, - _: (), + state: Rc>, + args: BufferGetMapAsyncArgs, + _: (), ) -> Result { - let (sender, receiver) = oneshot::channel::>(); - - let device; - { - let state_ = state.borrow(); - let instance = state_.borrow::(); - let buffer_resource = state_.resource_table.get::(args.buffer_rid)?; - let buffer = buffer_resource.0; - let device_resource = state_ - .resource_table - .get::(args.device_rid)?; - device = device_resource.0; - - let boxed_sender = Box::new(sender); - let sender_ptr = Box::into_raw(boxed_sender) as *mut u8; - - extern "C" fn buffer_map_future_wrapper( - status: wgpu_core::resource::BufferMapAsyncStatus, - user_data: *mut u8, - ) { - let sender_ptr = user_data as *mut oneshot::Sender>; - let boxed_sender = unsafe { Box::from_raw(sender_ptr) }; - boxed_sender - .send(match status { - wgpu_core::resource::BufferMapAsyncStatus::Success => Ok(()), - _ => unreachable!(), // TODO - }) - .unwrap(); - } - - // TODO(lucacasonato): error handling - let maybe_err = gfx_select!(buffer => instance.buffer_map_async( - buffer, - args.offset..(args.offset + args.size), - wgpu_core::resource::BufferMapOperation { - host: match args.mode { - 1 => wgpu_core::device::HostMap::Read, - 2 => wgpu_core::device::HostMap::Write, - _ => unreachable!(), - }, - callback: buffer_map_future_wrapper, - user_data: sender_ptr, - } - )) - .err(); - - if maybe_err.is_some() { - return Ok(WebGpuResult::maybe_err(maybe_err)); - } + let (sender, receiver) = oneshot::channel::>(); + + let device; + { + let state_ = state.borrow(); + let instance = state_.borrow::(); + let buffer_resource = + state_.resource_table.get::(args.buffer_rid)?; + let buffer = buffer_resource.0; + let device_resource = state_ + .resource_table + .get::(args.device_rid)?; + device = device_resource.0; + + let boxed_sender = Box::new(sender); + let sender_ptr = Box::into_raw(boxed_sender) as *mut u8; + + extern "C" fn buffer_map_future_wrapper( + status: wgpu_core::resource::BufferMapAsyncStatus, + user_data: *mut u8, + ) { + let sender_ptr = user_data as *mut oneshot::Sender>; + let boxed_sender = unsafe { Box::from_raw(sender_ptr) }; + boxed_sender + .send(match status { + wgpu_core::resource::BufferMapAsyncStatus::Success => Ok(()), + _ => unreachable!(), // TODO + }) + .unwrap(); + } + + // TODO(lucacasonato): error handling + let maybe_err = gfx_select!(buffer => instance.buffer_map_async( + buffer, + args.offset..(args.offset + args.size), + wgpu_core::resource::BufferMapOperation { + host: match args.mode { + 1 => wgpu_core::device::HostMap::Read, + 2 => wgpu_core::device::HostMap::Write, + _ => unreachable!(), + }, + callback: buffer_map_future_wrapper, + user_data: sender_ptr, + } + )) + .err(); + + if maybe_err.is_some() { + return Ok(WebGpuResult::maybe_err(maybe_err)); + } + } + + let done = Rc::new(RefCell::new(false)); + let done_ = done.clone(); + let device_poll_fut = async move { + while !*done.borrow() { + { + let state = state.borrow(); + let instance = state.borrow::(); + gfx_select!(device => instance.device_poll(device, false)).unwrap() + } + tokio::time::sleep(Duration::from_millis(10)).await; } + Ok::<(), AnyError>(()) + }; - let done = Rc::new(RefCell::new(false)); - let done_ = done.clone(); - let device_poll_fut = async move { - while !*done.borrow() { - { - let state = state.borrow(); - let instance = state.borrow::(); - gfx_select!(device => instance.device_poll(device, false)).unwrap() - } - tokio::time::sleep(Duration::from_millis(10)).await; - } - Ok::<(), AnyError>(()) - }; - - let receiver_fut = async move { - receiver.await??; - let mut done = done_.borrow_mut(); - *done = true; - Ok::<(), AnyError>(()) - }; - - tokio::try_join!(device_poll_fut, receiver_fut)?; - - Ok(WebGpuResult::empty()) + let receiver_fut = async move { + receiver.await??; + let mut done = done_.borrow_mut(); + *done = true; + Ok::<(), AnyError>(()) + }; + + tokio::try_join!(device_poll_fut, receiver_fut)?; + + Ok(WebGpuResult::empty()) } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct BufferGetMappedRangeArgs { - buffer_rid: ResourceId, - offset: u64, - size: Option, + buffer_rid: ResourceId, + offset: u64, + size: Option, } pub fn op_webgpu_buffer_get_mapped_range( - state: &mut OpState, - args: BufferGetMappedRangeArgs, - mut zero_copy: ZeroCopyBuf, + state: &mut OpState, + args: BufferGetMappedRangeArgs, + mut zero_copy: ZeroCopyBuf, ) -> Result { - let instance = state.borrow::(); - let buffer_resource = state.resource_table.get::(args.buffer_rid)?; - let buffer = buffer_resource.0; + let instance = state.borrow::(); + let buffer_resource = + state.resource_table.get::(args.buffer_rid)?; + let buffer = buffer_resource.0; - let (slice_pointer, range_size) = gfx_select!(buffer => instance.buffer_get_mapped_range( + let (slice_pointer, range_size) = + gfx_select!(buffer => instance.buffer_get_mapped_range( buffer, args.offset, args.size )) .map_err(|e| DomExceptionOperationError::new(&e.to_string()))?; - let slice = unsafe { std::slice::from_raw_parts_mut(slice_pointer, range_size as usize) }; - zero_copy.copy_from_slice(slice); + let slice = unsafe { + std::slice::from_raw_parts_mut(slice_pointer, range_size as usize) + }; + zero_copy.copy_from_slice(slice); - let rid = state - .resource_table - .add(WebGpuBufferMapped(slice_pointer, range_size as usize)); + let rid = state + .resource_table + .add(WebGpuBufferMapped(slice_pointer, range_size as usize)); - Ok(WebGpuResult::rid(rid)) + Ok(WebGpuResult::rid(rid)) } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct BufferUnmapArgs { - buffer_rid: ResourceId, - mapped_rid: ResourceId, + buffer_rid: ResourceId, + mapped_rid: ResourceId, } pub fn op_webgpu_buffer_unmap( - state: &mut OpState, - args: BufferUnmapArgs, - zero_copy: Option, + state: &mut OpState, + args: BufferUnmapArgs, + zero_copy: Option, ) -> Result { - let mapped_resource = state - .resource_table - .take::(args.mapped_rid)?; - let instance = state.borrow::(); - let buffer_resource = state.resource_table.get::(args.buffer_rid)?; - let buffer = buffer_resource.0; - - let slice_pointer = mapped_resource.0; - let size = mapped_resource.1; - - if let Some(buffer) = zero_copy { - let slice = unsafe { std::slice::from_raw_parts_mut(slice_pointer, size) }; - slice.copy_from_slice(&buffer); - } - - gfx_ok!(buffer => instance.buffer_unmap(buffer)) + let mapped_resource = state + .resource_table + .take::(args.mapped_rid)?; + let instance = state.borrow::(); + let buffer_resource = + state.resource_table.get::(args.buffer_rid)?; + let buffer = buffer_resource.0; + + let slice_pointer = mapped_resource.0; + let size = mapped_resource.1; + + if let Some(buffer) = zero_copy { + let slice = unsafe { std::slice::from_raw_parts_mut(slice_pointer, size) }; + slice.copy_from_slice(&buffer); + } + + gfx_ok!(buffer => instance.buffer_unmap(buffer)) } diff --git a/ext/webgpu/src/bundle.rs b/ext/webgpu/src/bundle.rs index 541e328f6c2d3d..eaf47f5d1a8e0b 100644 --- a/ext/webgpu/src/bundle.rs +++ b/ext/webgpu/src/bundle.rs @@ -11,107 +11,111 @@ use std::rc::Rc; use super::error::WebGpuResult; -struct WebGpuRenderBundleEncoder(RefCell); +struct WebGpuRenderBundleEncoder( + RefCell, +); impl Resource for WebGpuRenderBundleEncoder { - fn name(&self) -> Cow { - "webGPURenderBundleEncoder".into() - } + fn name(&self) -> Cow { + "webGPURenderBundleEncoder".into() + } } pub(crate) struct WebGpuRenderBundle(pub(crate) wgpu_core::id::RenderBundleId); impl Resource for WebGpuRenderBundle { - fn name(&self) -> Cow { - "webGPURenderBundle".into() - } + fn name(&self) -> Cow { + "webGPURenderBundle".into() + } } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct CreateRenderBundleEncoderArgs { - device_rid: ResourceId, - label: Option, - color_formats: Vec, - depth_stencil_format: Option, - sample_count: u32, - depth_read_only: bool, - stencil_read_only: bool, + device_rid: ResourceId, + label: Option, + color_formats: Vec, + depth_stencil_format: Option, + sample_count: u32, + depth_read_only: bool, + stencil_read_only: bool, } pub fn op_webgpu_create_render_bundle_encoder( - state: &mut OpState, - args: CreateRenderBundleEncoderArgs, - _: (), + state: &mut OpState, + args: CreateRenderBundleEncoderArgs, + _: (), ) -> Result { - let device_resource = state - .resource_table - .get::(args.device_rid)?; - let device = device_resource.0; - - let mut color_formats = vec![]; - - for format in args.color_formats { - color_formats.push(format); - } - - let depth_stencil = if let Some(format) = args.depth_stencil_format { - Some(wgpu_types::RenderBundleDepthStencil { - format, - depth_read_only: args.depth_read_only, - stencil_read_only: args.stencil_read_only, - }) - } else { - None - }; - - let descriptor = wgpu_core::command::RenderBundleEncoderDescriptor { - label: args.label.map(Cow::from), - color_formats: Cow::from(color_formats), - sample_count: args.sample_count, - depth_stencil, - multiview: None, - }; - - let res = wgpu_core::command::RenderBundleEncoder::new(&descriptor, device, None); - let (render_bundle_encoder, maybe_err) = match res { - Ok(encoder) => (encoder, None), - Err(e) => ( - wgpu_core::command::RenderBundleEncoder::dummy(device), - Some(e), - ), - }; - - let rid = state - .resource_table - .add(WebGpuRenderBundleEncoder(RefCell::new( - render_bundle_encoder, - ))); - - Ok(WebGpuResult::rid_err(rid, maybe_err)) + let device_resource = state + .resource_table + .get::(args.device_rid)?; + let device = device_resource.0; + + let mut color_formats = vec![]; + + for format in args.color_formats { + color_formats.push(format); + } + + let depth_stencil = if let Some(format) = args.depth_stencil_format { + Some(wgpu_types::RenderBundleDepthStencil { + format, + depth_read_only: args.depth_read_only, + stencil_read_only: args.stencil_read_only, + }) + } else { + None + }; + + let descriptor = wgpu_core::command::RenderBundleEncoderDescriptor { + label: args.label.map(Cow::from), + color_formats: Cow::from(color_formats), + sample_count: args.sample_count, + depth_stencil, + multiview: None, + }; + + let res = + wgpu_core::command::RenderBundleEncoder::new(&descriptor, device, None); + let (render_bundle_encoder, maybe_err) = match res { + Ok(encoder) => (encoder, None), + Err(e) => ( + wgpu_core::command::RenderBundleEncoder::dummy(device), + Some(e), + ), + }; + + let rid = state + .resource_table + .add(WebGpuRenderBundleEncoder(RefCell::new( + render_bundle_encoder, + ))); + + Ok(WebGpuResult::rid_err(rid, maybe_err)) } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct RenderBundleEncoderFinishArgs { - render_bundle_encoder_rid: ResourceId, - label: Option, + render_bundle_encoder_rid: ResourceId, + label: Option, } pub fn op_webgpu_render_bundle_encoder_finish( - state: &mut OpState, - args: RenderBundleEncoderFinishArgs, - _: (), + state: &mut OpState, + args: RenderBundleEncoderFinishArgs, + _: (), ) -> Result { - let render_bundle_encoder_resource = state - .resource_table - .take::(args.render_bundle_encoder_rid)?; - let render_bundle_encoder = Rc::try_unwrap(render_bundle_encoder_resource) - .ok() - .expect("unwrapping render_bundle_encoder_resource should succeed") - .0 - .into_inner(); - let instance = state.borrow::(); - - gfx_put!(render_bundle_encoder.parent() => instance.render_bundle_encoder_finish( + let render_bundle_encoder_resource = + state + .resource_table + .take::(args.render_bundle_encoder_rid)?; + let render_bundle_encoder = Rc::try_unwrap(render_bundle_encoder_resource) + .ok() + .expect("unwrapping render_bundle_encoder_resource should succeed") + .0 + .into_inner(); + let instance = state.borrow::(); + + gfx_put!(render_bundle_encoder.parent() => instance.render_bundle_encoder_finish( render_bundle_encoder, &wgpu_core::command::RenderBundleDescriptor { label: args.label.map(Cow::from), @@ -123,321 +127,333 @@ pub fn op_webgpu_render_bundle_encoder_finish( #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct RenderBundleEncoderSetBindGroupArgs { - render_bundle_encoder_rid: ResourceId, - index: u32, - bind_group: ResourceId, - dynamic_offsets_data: ZeroCopyBuf, - dynamic_offsets_data_start: usize, - dynamic_offsets_data_length: usize, + render_bundle_encoder_rid: ResourceId, + index: u32, + bind_group: ResourceId, + dynamic_offsets_data: ZeroCopyBuf, + dynamic_offsets_data_start: usize, + dynamic_offsets_data_length: usize, } pub fn op_webgpu_render_bundle_encoder_set_bind_group( - state: &mut OpState, - args: RenderBundleEncoderSetBindGroupArgs, - _: (), + state: &mut OpState, + args: RenderBundleEncoderSetBindGroupArgs, + _: (), ) -> Result { - let bind_group_resource = state - .resource_table - .get::(args.bind_group)?; - let render_bundle_encoder_resource = state - .resource_table - .get::(args.render_bundle_encoder_rid)?; - - // Align the data - assert!(args.dynamic_offsets_data.len() % std::mem::size_of::() == 0); - // SAFETY: A u8 to u32 cast is safe because we asserted that the length is a - // multiple of 4. - let (prefix, dynamic_offsets_data, suffix) = - unsafe { args.dynamic_offsets_data.align_to::() }; - assert!(prefix.is_empty()); - assert!(suffix.is_empty()); - - let start = args.dynamic_offsets_data_start; - let len = args.dynamic_offsets_data_length; - - // Assert that length and start are both in bounds - assert!(start <= dynamic_offsets_data.len()); - assert!(len <= dynamic_offsets_data.len() - start); - - let dynamic_offsets_data: &[u32] = &dynamic_offsets_data[start..start + len]; - - // SAFETY: the raw pointer and length are of the same slice, and that slice - // lives longer than the below function invocation. - unsafe { - wgpu_core::command::bundle_ffi::wgpu_render_bundle_set_bind_group( - &mut render_bundle_encoder_resource.0.borrow_mut(), - args.index, - bind_group_resource.0, - dynamic_offsets_data.as_ptr(), - dynamic_offsets_data.len(), - ); - } - - Ok(WebGpuResult::empty()) + let bind_group_resource = + state + .resource_table + .get::(args.bind_group)?; + let render_bundle_encoder_resource = + state + .resource_table + .get::(args.render_bundle_encoder_rid)?; + + // Align the data + assert!(args.dynamic_offsets_data.len() % std::mem::size_of::() == 0); + // SAFETY: A u8 to u32 cast is safe because we asserted that the length is a + // multiple of 4. + let (prefix, dynamic_offsets_data, suffix) = + unsafe { args.dynamic_offsets_data.align_to::() }; + assert!(prefix.is_empty()); + assert!(suffix.is_empty()); + + let start = args.dynamic_offsets_data_start; + let len = args.dynamic_offsets_data_length; + + // Assert that length and start are both in bounds + assert!(start <= dynamic_offsets_data.len()); + assert!(len <= dynamic_offsets_data.len() - start); + + let dynamic_offsets_data: &[u32] = &dynamic_offsets_data[start..start + len]; + + // SAFETY: the raw pointer and length are of the same slice, and that slice + // lives longer than the below function invocation. + unsafe { + wgpu_core::command::bundle_ffi::wgpu_render_bundle_set_bind_group( + &mut render_bundle_encoder_resource.0.borrow_mut(), + args.index, + bind_group_resource.0, + dynamic_offsets_data.as_ptr(), + dynamic_offsets_data.len(), + ); + } + + Ok(WebGpuResult::empty()) } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct RenderBundleEncoderPushDebugGroupArgs { - render_bundle_encoder_rid: ResourceId, - group_label: String, + render_bundle_encoder_rid: ResourceId, + group_label: String, } pub fn op_webgpu_render_bundle_encoder_push_debug_group( - state: &mut OpState, - args: RenderBundleEncoderPushDebugGroupArgs, - _: (), + state: &mut OpState, + args: RenderBundleEncoderPushDebugGroupArgs, + _: (), ) -> Result { - let render_bundle_encoder_resource = state - .resource_table - .get::(args.render_bundle_encoder_rid)?; - - let label = std::ffi::CString::new(args.group_label).unwrap(); - // SAFETY: the string the raw pointer points to lives longer than the below - // function invocation. - unsafe { - wgpu_core::command::bundle_ffi::wgpu_render_bundle_push_debug_group( - &mut render_bundle_encoder_resource.0.borrow_mut(), - label.as_ptr(), - ); - } - - Ok(WebGpuResult::empty()) + let render_bundle_encoder_resource = + state + .resource_table + .get::(args.render_bundle_encoder_rid)?; + + let label = std::ffi::CString::new(args.group_label).unwrap(); + // SAFETY: the string the raw pointer points to lives longer than the below + // function invocation. + unsafe { + wgpu_core::command::bundle_ffi::wgpu_render_bundle_push_debug_group( + &mut render_bundle_encoder_resource.0.borrow_mut(), + label.as_ptr(), + ); + } + + Ok(WebGpuResult::empty()) } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct RenderBundleEncoderPopDebugGroupArgs { - render_bundle_encoder_rid: ResourceId, + render_bundle_encoder_rid: ResourceId, } pub fn op_webgpu_render_bundle_encoder_pop_debug_group( - state: &mut OpState, - args: RenderBundleEncoderPopDebugGroupArgs, - _: (), + state: &mut OpState, + args: RenderBundleEncoderPopDebugGroupArgs, + _: (), ) -> Result { - let render_bundle_encoder_resource = state - .resource_table - .get::(args.render_bundle_encoder_rid)?; + let render_bundle_encoder_resource = + state + .resource_table + .get::(args.render_bundle_encoder_rid)?; - wgpu_core::command::bundle_ffi::wgpu_render_bundle_pop_debug_group( - &mut render_bundle_encoder_resource.0.borrow_mut(), - ); + wgpu_core::command::bundle_ffi::wgpu_render_bundle_pop_debug_group( + &mut render_bundle_encoder_resource.0.borrow_mut(), + ); - Ok(WebGpuResult::empty()) + Ok(WebGpuResult::empty()) } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct RenderBundleEncoderInsertDebugMarkerArgs { - render_bundle_encoder_rid: ResourceId, - marker_label: String, + render_bundle_encoder_rid: ResourceId, + marker_label: String, } pub fn op_webgpu_render_bundle_encoder_insert_debug_marker( - state: &mut OpState, - args: RenderBundleEncoderInsertDebugMarkerArgs, - _: (), + state: &mut OpState, + args: RenderBundleEncoderInsertDebugMarkerArgs, + _: (), ) -> Result { - let render_bundle_encoder_resource = state - .resource_table - .get::(args.render_bundle_encoder_rid)?; - - let label = std::ffi::CString::new(args.marker_label).unwrap(); - // SAFETY: the string the raw pointer points to lives longer than the below - // function invocation. - unsafe { - wgpu_core::command::bundle_ffi::wgpu_render_bundle_insert_debug_marker( - &mut render_bundle_encoder_resource.0.borrow_mut(), - label.as_ptr(), - ); - } - - Ok(WebGpuResult::empty()) + let render_bundle_encoder_resource = + state + .resource_table + .get::(args.render_bundle_encoder_rid)?; + + let label = std::ffi::CString::new(args.marker_label).unwrap(); + // SAFETY: the string the raw pointer points to lives longer than the below + // function invocation. + unsafe { + wgpu_core::command::bundle_ffi::wgpu_render_bundle_insert_debug_marker( + &mut render_bundle_encoder_resource.0.borrow_mut(), + label.as_ptr(), + ); + } + + Ok(WebGpuResult::empty()) } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct RenderBundleEncoderSetPipelineArgs { - render_bundle_encoder_rid: ResourceId, - pipeline: ResourceId, + render_bundle_encoder_rid: ResourceId, + pipeline: ResourceId, } pub fn op_webgpu_render_bundle_encoder_set_pipeline( - state: &mut OpState, - args: RenderBundleEncoderSetPipelineArgs, - _: (), + state: &mut OpState, + args: RenderBundleEncoderSetPipelineArgs, + _: (), ) -> Result { - let render_pipeline_resource = state - .resource_table - .get::(args.pipeline)?; - let render_bundle_encoder_resource = state - .resource_table - .get::(args.render_bundle_encoder_rid)?; - - wgpu_core::command::bundle_ffi::wgpu_render_bundle_set_pipeline( - &mut render_bundle_encoder_resource.0.borrow_mut(), - render_pipeline_resource.0, - ); - - Ok(WebGpuResult::empty()) + let render_pipeline_resource = + state + .resource_table + .get::(args.pipeline)?; + let render_bundle_encoder_resource = + state + .resource_table + .get::(args.render_bundle_encoder_rid)?; + + wgpu_core::command::bundle_ffi::wgpu_render_bundle_set_pipeline( + &mut render_bundle_encoder_resource.0.borrow_mut(), + render_pipeline_resource.0, + ); + + Ok(WebGpuResult::empty()) } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct RenderBundleEncoderSetIndexBufferArgs { - render_bundle_encoder_rid: ResourceId, - buffer: ResourceId, - index_format: wgpu_types::IndexFormat, - offset: u64, - size: u64, + render_bundle_encoder_rid: ResourceId, + buffer: ResourceId, + index_format: wgpu_types::IndexFormat, + offset: u64, + size: u64, } pub fn op_webgpu_render_bundle_encoder_set_index_buffer( - state: &mut OpState, - args: RenderBundleEncoderSetIndexBufferArgs, - _: (), + state: &mut OpState, + args: RenderBundleEncoderSetIndexBufferArgs, + _: (), ) -> Result { - let buffer_resource = state - .resource_table - .get::(args.buffer)?; - let render_bundle_encoder_resource = state - .resource_table - .get::(args.render_bundle_encoder_rid)?; - - render_bundle_encoder_resource - .0 - .borrow_mut() - .set_index_buffer( - buffer_resource.0, - args.index_format, - args.offset, - std::num::NonZeroU64::new(args.size), - ); - - Ok(WebGpuResult::empty()) + let buffer_resource = state + .resource_table + .get::(args.buffer)?; + let render_bundle_encoder_resource = + state + .resource_table + .get::(args.render_bundle_encoder_rid)?; + + render_bundle_encoder_resource + .0 + .borrow_mut() + .set_index_buffer( + buffer_resource.0, + args.index_format, + args.offset, + std::num::NonZeroU64::new(args.size), + ); + + Ok(WebGpuResult::empty()) } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct RenderBundleEncoderSetVertexBufferArgs { - render_bundle_encoder_rid: ResourceId, - slot: u32, - buffer: ResourceId, - offset: u64, - size: u64, + render_bundle_encoder_rid: ResourceId, + slot: u32, + buffer: ResourceId, + offset: u64, + size: u64, } pub fn op_webgpu_render_bundle_encoder_set_vertex_buffer( - state: &mut OpState, - args: RenderBundleEncoderSetVertexBufferArgs, - _: (), + state: &mut OpState, + args: RenderBundleEncoderSetVertexBufferArgs, + _: (), ) -> Result { - let buffer_resource = state - .resource_table - .get::(args.buffer)?; - let render_bundle_encoder_resource = state - .resource_table - .get::(args.render_bundle_encoder_rid)?; - - wgpu_core::command::bundle_ffi::wgpu_render_bundle_set_vertex_buffer( - &mut render_bundle_encoder_resource.0.borrow_mut(), - args.slot, - buffer_resource.0, - args.offset, - std::num::NonZeroU64::new(args.size), - ); - - Ok(WebGpuResult::empty()) + let buffer_resource = state + .resource_table + .get::(args.buffer)?; + let render_bundle_encoder_resource = + state + .resource_table + .get::(args.render_bundle_encoder_rid)?; + + wgpu_core::command::bundle_ffi::wgpu_render_bundle_set_vertex_buffer( + &mut render_bundle_encoder_resource.0.borrow_mut(), + args.slot, + buffer_resource.0, + args.offset, + std::num::NonZeroU64::new(args.size), + ); + + Ok(WebGpuResult::empty()) } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct RenderBundleEncoderDrawArgs { - render_bundle_encoder_rid: ResourceId, - vertex_count: u32, - instance_count: u32, - first_vertex: u32, - first_instance: u32, + render_bundle_encoder_rid: ResourceId, + vertex_count: u32, + instance_count: u32, + first_vertex: u32, + first_instance: u32, } pub fn op_webgpu_render_bundle_encoder_draw( - state: &mut OpState, - args: RenderBundleEncoderDrawArgs, - _: (), + state: &mut OpState, + args: RenderBundleEncoderDrawArgs, + _: (), ) -> Result { - let render_bundle_encoder_resource = state - .resource_table - .get::(args.render_bundle_encoder_rid)?; - - wgpu_core::command::bundle_ffi::wgpu_render_bundle_draw( - &mut render_bundle_encoder_resource.0.borrow_mut(), - args.vertex_count, - args.instance_count, - args.first_vertex, - args.first_instance, - ); - - Ok(WebGpuResult::empty()) + let render_bundle_encoder_resource = + state + .resource_table + .get::(args.render_bundle_encoder_rid)?; + + wgpu_core::command::bundle_ffi::wgpu_render_bundle_draw( + &mut render_bundle_encoder_resource.0.borrow_mut(), + args.vertex_count, + args.instance_count, + args.first_vertex, + args.first_instance, + ); + + Ok(WebGpuResult::empty()) } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct RenderBundleEncoderDrawIndexedArgs { - render_bundle_encoder_rid: ResourceId, - index_count: u32, - instance_count: u32, - first_index: u32, - base_vertex: i32, - first_instance: u32, + render_bundle_encoder_rid: ResourceId, + index_count: u32, + instance_count: u32, + first_index: u32, + base_vertex: i32, + first_instance: u32, } pub fn op_webgpu_render_bundle_encoder_draw_indexed( - state: &mut OpState, - args: RenderBundleEncoderDrawIndexedArgs, - _: (), + state: &mut OpState, + args: RenderBundleEncoderDrawIndexedArgs, + _: (), ) -> Result { - let render_bundle_encoder_resource = state - .resource_table - .get::(args.render_bundle_encoder_rid)?; - - wgpu_core::command::bundle_ffi::wgpu_render_bundle_draw_indexed( - &mut render_bundle_encoder_resource.0.borrow_mut(), - args.index_count, - args.instance_count, - args.first_index, - args.base_vertex, - args.first_instance, - ); - - Ok(WebGpuResult::empty()) + let render_bundle_encoder_resource = + state + .resource_table + .get::(args.render_bundle_encoder_rid)?; + + wgpu_core::command::bundle_ffi::wgpu_render_bundle_draw_indexed( + &mut render_bundle_encoder_resource.0.borrow_mut(), + args.index_count, + args.instance_count, + args.first_index, + args.base_vertex, + args.first_instance, + ); + + Ok(WebGpuResult::empty()) } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct RenderBundleEncoderDrawIndirectArgs { - render_bundle_encoder_rid: ResourceId, - indirect_buffer: ResourceId, - indirect_offset: u64, + render_bundle_encoder_rid: ResourceId, + indirect_buffer: ResourceId, + indirect_offset: u64, } pub fn op_webgpu_render_bundle_encoder_draw_indirect( - state: &mut OpState, - args: RenderBundleEncoderDrawIndirectArgs, - _: (), + state: &mut OpState, + args: RenderBundleEncoderDrawIndirectArgs, + _: (), ) -> Result { - let buffer_resource = state - .resource_table - .get::(args.indirect_buffer)?; - let render_bundle_encoder_resource = state - .resource_table - .get::(args.render_bundle_encoder_rid)?; - - wgpu_core::command::bundle_ffi::wgpu_render_bundle_draw_indirect( - &mut render_bundle_encoder_resource.0.borrow_mut(), - buffer_resource.0, - args.indirect_offset, - ); - - Ok(WebGpuResult::empty()) + let buffer_resource = state + .resource_table + .get::(args.indirect_buffer)?; + let render_bundle_encoder_resource = + state + .resource_table + .get::(args.render_bundle_encoder_rid)?; + + wgpu_core::command::bundle_ffi::wgpu_render_bundle_draw_indirect( + &mut render_bundle_encoder_resource.0.borrow_mut(), + buffer_resource.0, + args.indirect_offset, + ); + + Ok(WebGpuResult::empty()) } diff --git a/ext/webgpu/src/command_encoder.rs b/ext/webgpu/src/command_encoder.rs index f6e969381d4db1..4dc482fec243e6 100644 --- a/ext/webgpu/src/command_encoder.rs +++ b/ext/webgpu/src/command_encoder.rs @@ -10,44 +10,48 @@ use std::num::NonZeroU32; use super::error::WebGpuResult; -pub(crate) struct WebGpuCommandEncoder(pub(crate) wgpu_core::id::CommandEncoderId); +pub(crate) struct WebGpuCommandEncoder( + pub(crate) wgpu_core::id::CommandEncoderId, +); impl Resource for WebGpuCommandEncoder { - fn name(&self) -> Cow { - "webGPUCommandEncoder".into() - } + fn name(&self) -> Cow { + "webGPUCommandEncoder".into() + } } -pub(crate) struct WebGpuCommandBuffer(pub(crate) wgpu_core::id::CommandBufferId); +pub(crate) struct WebGpuCommandBuffer( + pub(crate) wgpu_core::id::CommandBufferId, +); impl Resource for WebGpuCommandBuffer { - fn name(&self) -> Cow { - "webGPUCommandBuffer".into() - } + fn name(&self) -> Cow { + "webGPUCommandBuffer".into() + } } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct CreateCommandEncoderArgs { - device_rid: ResourceId, - label: Option, - _measure_execution_time: Option, // not yet implemented + device_rid: ResourceId, + label: Option, + _measure_execution_time: Option, // not yet implemented } pub fn op_webgpu_create_command_encoder( - state: &mut OpState, - args: CreateCommandEncoderArgs, - _: (), + state: &mut OpState, + args: CreateCommandEncoderArgs, + _: (), ) -> Result { - let instance = state.borrow::(); - let device_resource = state - .resource_table - .get::(args.device_rid)?; - let device = device_resource.0; + let instance = state.borrow::(); + let device_resource = state + .resource_table + .get::(args.device_rid)?; + let device = device_resource.0; - let descriptor = wgpu_types::CommandEncoderDescriptor { - label: args.label.map(Cow::from), - }; + let descriptor = wgpu_types::CommandEncoderDescriptor { + label: args.label.map(Cow::from), + }; - gfx_put!(device => instance.device_create_command_encoder( + gfx_put!(device => instance.device_create_command_encoder( device, &descriptor, std::marker::PhantomData @@ -57,565 +61,585 @@ pub fn op_webgpu_create_command_encoder( #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct GpuRenderPassColorAttachment { - view: ResourceId, - resolve_target: Option, - load_op: GpuLoadOp, - store_op: wgpu_core::command::StoreOp, + view: ResourceId, + resolve_target: Option, + load_op: GpuLoadOp, + store_op: wgpu_core::command::StoreOp, } #[derive(Deserialize)] #[serde(rename_all = "kebab-case")] enum GpuLoadOp { - Load, - Clear(T), + Load, + Clear(T), } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct GpuRenderPassDepthStencilAttachment { - view: ResourceId, - depth_load_op: GpuLoadOp, - depth_store_op: wgpu_core::command::StoreOp, - depth_read_only: bool, - stencil_load_op: GpuLoadOp, - stencil_store_op: wgpu_core::command::StoreOp, - stencil_read_only: bool, + view: ResourceId, + depth_load_op: GpuLoadOp, + depth_store_op: wgpu_core::command::StoreOp, + depth_read_only: bool, + stencil_load_op: GpuLoadOp, + stencil_store_op: wgpu_core::command::StoreOp, + stencil_read_only: bool, } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct CommandEncoderBeginRenderPassArgs { - command_encoder_rid: ResourceId, - label: Option, - color_attachments: Vec, - depth_stencil_attachment: Option, - _occlusion_query_set: Option, // not yet implemented + command_encoder_rid: ResourceId, + label: Option, + color_attachments: Vec, + depth_stencil_attachment: Option, + _occlusion_query_set: Option, // not yet implemented } pub fn op_webgpu_command_encoder_begin_render_pass( - state: &mut OpState, - args: CommandEncoderBeginRenderPassArgs, - _: (), + state: &mut OpState, + args: CommandEncoderBeginRenderPassArgs, + _: (), ) -> Result { - let command_encoder_resource = state + let command_encoder_resource = state + .resource_table + .get::(args.command_encoder_rid)?; + + let mut color_attachments = vec![]; + + for color_attachment in args.color_attachments { + let texture_view_resource = + state .resource_table - .get::(args.command_encoder_rid)?; - - let mut color_attachments = vec![]; - - for color_attachment in args.color_attachments { - let texture_view_resource = state - .resource_table - .get::(color_attachment.view)?; - - let resolve_target = color_attachment - .resolve_target - .map(|rid| { - state - .resource_table - .get::(rid) - }) - .transpose()? - .map(|texture| texture.0); - - let attachment = wgpu_core::command::RenderPassColorAttachment { - view: texture_view_resource.0, - resolve_target, - channel: match color_attachment.load_op { - GpuLoadOp::Load => wgpu_core::command::PassChannel { - load_op: wgpu_core::command::LoadOp::Load, - store_op: color_attachment.store_op, - clear_value: Default::default(), - read_only: false, - }, - GpuLoadOp::Clear(color) => wgpu_core::command::PassChannel { - load_op: wgpu_core::command::LoadOp::Clear, - store_op: color_attachment.store_op, - clear_value: color, - read_only: false, - }, - }, - }; - - color_attachments.push(attachment) - } - - let mut depth_stencil_attachment = None; - - if let Some(attachment) = args.depth_stencil_attachment { - let texture_view_resource = state - .resource_table - .get::(attachment.view)?; - - depth_stencil_attachment = Some(wgpu_core::command::RenderPassDepthStencilAttachment { - view: texture_view_resource.0, - depth: match attachment.depth_load_op { - GpuLoadOp::Load => wgpu_core::command::PassChannel { - load_op: wgpu_core::command::LoadOp::Load, - store_op: attachment.depth_store_op, - clear_value: 0.0, - read_only: attachment.depth_read_only, - }, - GpuLoadOp::Clear(value) => wgpu_core::command::PassChannel { - load_op: wgpu_core::command::LoadOp::Clear, - store_op: attachment.depth_store_op, - clear_value: value, - read_only: attachment.depth_read_only, - }, - }, - stencil: match attachment.stencil_load_op { - GpuLoadOp::Load => wgpu_core::command::PassChannel { - load_op: wgpu_core::command::LoadOp::Load, - store_op: attachment.stencil_store_op, - clear_value: 0, - read_only: attachment.stencil_read_only, - }, - GpuLoadOp::Clear(value) => wgpu_core::command::PassChannel { - load_op: wgpu_core::command::LoadOp::Clear, - store_op: attachment.stencil_store_op, - clear_value: value, - read_only: attachment.stencil_read_only, - }, - }, - }); - } - - let descriptor = wgpu_core::command::RenderPassDescriptor { - label: args.label.map(Cow::from), - color_attachments: Cow::from(color_attachments), - depth_stencil_attachment: depth_stencil_attachment.as_ref(), + .get::(color_attachment.view)?; + + let resolve_target = color_attachment + .resolve_target + .map(|rid| { + state + .resource_table + .get::(rid) + }) + .transpose()? + .map(|texture| texture.0); + + let attachment = wgpu_core::command::RenderPassColorAttachment { + view: texture_view_resource.0, + resolve_target, + channel: match color_attachment.load_op { + GpuLoadOp::Load => wgpu_core::command::PassChannel { + load_op: wgpu_core::command::LoadOp::Load, + store_op: color_attachment.store_op, + clear_value: Default::default(), + read_only: false, + }, + GpuLoadOp::Clear(color) => wgpu_core::command::PassChannel { + load_op: wgpu_core::command::LoadOp::Clear, + store_op: color_attachment.store_op, + clear_value: color, + read_only: false, + }, + }, }; - let render_pass = wgpu_core::command::RenderPass::new(command_encoder_resource.0, &descriptor); + color_attachments.push(attachment) + } - let rid = state + let mut depth_stencil_attachment = None; + + if let Some(attachment) = args.depth_stencil_attachment { + let texture_view_resource = + state .resource_table - .add(super::render_pass::WebGpuRenderPass(RefCell::new( - render_pass, - ))); + .get::(attachment.view)?; + + depth_stencil_attachment = + Some(wgpu_core::command::RenderPassDepthStencilAttachment { + view: texture_view_resource.0, + depth: match attachment.depth_load_op { + GpuLoadOp::Load => wgpu_core::command::PassChannel { + load_op: wgpu_core::command::LoadOp::Load, + store_op: attachment.depth_store_op, + clear_value: 0.0, + read_only: attachment.depth_read_only, + }, + GpuLoadOp::Clear(value) => wgpu_core::command::PassChannel { + load_op: wgpu_core::command::LoadOp::Clear, + store_op: attachment.depth_store_op, + clear_value: value, + read_only: attachment.depth_read_only, + }, + }, + stencil: match attachment.stencil_load_op { + GpuLoadOp::Load => wgpu_core::command::PassChannel { + load_op: wgpu_core::command::LoadOp::Load, + store_op: attachment.stencil_store_op, + clear_value: 0, + read_only: attachment.stencil_read_only, + }, + GpuLoadOp::Clear(value) => wgpu_core::command::PassChannel { + load_op: wgpu_core::command::LoadOp::Clear, + store_op: attachment.stencil_store_op, + clear_value: value, + read_only: attachment.stencil_read_only, + }, + }, + }); + } + + let descriptor = wgpu_core::command::RenderPassDescriptor { + label: args.label.map(Cow::from), + color_attachments: Cow::from(color_attachments), + depth_stencil_attachment: depth_stencil_attachment.as_ref(), + }; + + let render_pass = wgpu_core::command::RenderPass::new( + command_encoder_resource.0, + &descriptor, + ); - Ok(WebGpuResult::rid(rid)) + let rid = state + .resource_table + .add(super::render_pass::WebGpuRenderPass(RefCell::new( + render_pass, + ))); + + Ok(WebGpuResult::rid(rid)) } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct CommandEncoderBeginComputePassArgs { - command_encoder_rid: ResourceId, - label: Option, + command_encoder_rid: ResourceId, + label: Option, } pub fn op_webgpu_command_encoder_begin_compute_pass( - state: &mut OpState, - args: CommandEncoderBeginComputePassArgs, - _: (), + state: &mut OpState, + args: CommandEncoderBeginComputePassArgs, + _: (), ) -> Result { - let command_encoder_resource = state - .resource_table - .get::(args.command_encoder_rid)?; + let command_encoder_resource = state + .resource_table + .get::(args.command_encoder_rid)?; - let descriptor = wgpu_core::command::ComputePassDescriptor { - label: args.label.map(Cow::from), - }; + let descriptor = wgpu_core::command::ComputePassDescriptor { + label: args.label.map(Cow::from), + }; - let compute_pass = - wgpu_core::command::ComputePass::new(command_encoder_resource.0, &descriptor); + let compute_pass = wgpu_core::command::ComputePass::new( + command_encoder_resource.0, + &descriptor, + ); - let rid = state - .resource_table - .add(super::compute_pass::WebGpuComputePass(RefCell::new( - compute_pass, - ))); + let rid = state + .resource_table + .add(super::compute_pass::WebGpuComputePass(RefCell::new( + compute_pass, + ))); - Ok(WebGpuResult::rid(rid)) + Ok(WebGpuResult::rid(rid)) } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct CommandEncoderCopyBufferToBufferArgs { - command_encoder_rid: ResourceId, - source: ResourceId, - source_offset: u64, - destination: ResourceId, - destination_offset: u64, - size: u64, + command_encoder_rid: ResourceId, + source: ResourceId, + source_offset: u64, + destination: ResourceId, + destination_offset: u64, + size: u64, } pub fn op_webgpu_command_encoder_copy_buffer_to_buffer( - state: &mut OpState, - args: CommandEncoderCopyBufferToBufferArgs, - _: (), + state: &mut OpState, + args: CommandEncoderCopyBufferToBufferArgs, + _: (), ) -> Result { - let instance = state.borrow::(); - let command_encoder_resource = state - .resource_table - .get::(args.command_encoder_rid)?; - let command_encoder = command_encoder_resource.0; - let source_buffer_resource = state - .resource_table - .get::(args.source)?; - let source_buffer = source_buffer_resource.0; - let destination_buffer_resource = state - .resource_table - .get::(args.destination)?; - let destination_buffer = destination_buffer_resource.0; - - gfx_ok!(command_encoder => instance.command_encoder_copy_buffer_to_buffer( - command_encoder, - source_buffer, - args.source_offset, - destination_buffer, - args.destination_offset, - args.size - )) + let instance = state.borrow::(); + let command_encoder_resource = state + .resource_table + .get::(args.command_encoder_rid)?; + let command_encoder = command_encoder_resource.0; + let source_buffer_resource = + state + .resource_table + .get::(args.source)?; + let source_buffer = source_buffer_resource.0; + let destination_buffer_resource = + state + .resource_table + .get::(args.destination)?; + let destination_buffer = destination_buffer_resource.0; + + gfx_ok!(command_encoder => instance.command_encoder_copy_buffer_to_buffer( + command_encoder, + source_buffer, + args.source_offset, + destination_buffer, + args.destination_offset, + args.size + )) } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct GpuImageCopyBuffer { - buffer: ResourceId, - offset: u64, - bytes_per_row: Option, - rows_per_image: Option, + buffer: ResourceId, + offset: u64, + bytes_per_row: Option, + rows_per_image: Option, } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct GpuImageCopyTexture { - pub texture: ResourceId, - pub mip_level: u32, - pub origin: wgpu_types::Origin3d, - pub aspect: wgpu_types::TextureAspect, + pub texture: ResourceId, + pub mip_level: u32, + pub origin: wgpu_types::Origin3d, + pub aspect: wgpu_types::TextureAspect, } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct CommandEncoderCopyBufferToTextureArgs { - command_encoder_rid: ResourceId, - source: GpuImageCopyBuffer, - destination: GpuImageCopyTexture, - copy_size: wgpu_types::Extent3d, + command_encoder_rid: ResourceId, + source: GpuImageCopyBuffer, + destination: GpuImageCopyTexture, + copy_size: wgpu_types::Extent3d, } pub fn op_webgpu_command_encoder_copy_buffer_to_texture( - state: &mut OpState, - args: CommandEncoderCopyBufferToTextureArgs, - _: (), + state: &mut OpState, + args: CommandEncoderCopyBufferToTextureArgs, + _: (), ) -> Result { - let instance = state.borrow::(); - let command_encoder_resource = state - .resource_table - .get::(args.command_encoder_rid)?; - let command_encoder = command_encoder_resource.0; - let source_buffer_resource = state - .resource_table - .get::(args.source.buffer)?; - let destination_texture_resource = state - .resource_table - .get::(args.destination.texture)?; - - let source = wgpu_core::command::ImageCopyBuffer { - buffer: source_buffer_resource.0, - layout: wgpu_types::ImageDataLayout { - offset: args.source.offset, - bytes_per_row: NonZeroU32::new(args.source.bytes_per_row.unwrap_or(0)), - rows_per_image: NonZeroU32::new(args.source.rows_per_image.unwrap_or(0)), - }, - }; - let destination = wgpu_core::command::ImageCopyTexture { - texture: destination_texture_resource.0, - mip_level: args.destination.mip_level, - origin: args.destination.origin, - aspect: args.destination.aspect, - }; - gfx_ok!(command_encoder => instance.command_encoder_copy_buffer_to_texture( - command_encoder, - &source, - &destination, - &args.copy_size - )) + let instance = state.borrow::(); + let command_encoder_resource = state + .resource_table + .get::(args.command_encoder_rid)?; + let command_encoder = command_encoder_resource.0; + let source_buffer_resource = + state + .resource_table + .get::(args.source.buffer)?; + let destination_texture_resource = + state + .resource_table + .get::(args.destination.texture)?; + + let source = wgpu_core::command::ImageCopyBuffer { + buffer: source_buffer_resource.0, + layout: wgpu_types::ImageDataLayout { + offset: args.source.offset, + bytes_per_row: NonZeroU32::new(args.source.bytes_per_row.unwrap_or(0)), + rows_per_image: NonZeroU32::new(args.source.rows_per_image.unwrap_or(0)), + }, + }; + let destination = wgpu_core::command::ImageCopyTexture { + texture: destination_texture_resource.0, + mip_level: args.destination.mip_level, + origin: args.destination.origin, + aspect: args.destination.aspect, + }; + gfx_ok!(command_encoder => instance.command_encoder_copy_buffer_to_texture( + command_encoder, + &source, + &destination, + &args.copy_size + )) } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct CommandEncoderCopyTextureToBufferArgs { - command_encoder_rid: ResourceId, - source: GpuImageCopyTexture, - destination: GpuImageCopyBuffer, - copy_size: wgpu_types::Extent3d, + command_encoder_rid: ResourceId, + source: GpuImageCopyTexture, + destination: GpuImageCopyBuffer, + copy_size: wgpu_types::Extent3d, } pub fn op_webgpu_command_encoder_copy_texture_to_buffer( - state: &mut OpState, - args: CommandEncoderCopyTextureToBufferArgs, - _: (), + state: &mut OpState, + args: CommandEncoderCopyTextureToBufferArgs, + _: (), ) -> Result { - let instance = state.borrow::(); - let command_encoder_resource = state - .resource_table - .get::(args.command_encoder_rid)?; - let command_encoder = command_encoder_resource.0; - let source_texture_resource = state - .resource_table - .get::(args.source.texture)?; - let destination_buffer_resource = state - .resource_table - .get::(args.destination.buffer)?; - - let source = wgpu_core::command::ImageCopyTexture { - texture: source_texture_resource.0, - mip_level: args.source.mip_level, - origin: args.source.origin, - aspect: args.source.aspect, - }; - let destination = wgpu_core::command::ImageCopyBuffer { - buffer: destination_buffer_resource.0, - layout: wgpu_types::ImageDataLayout { - offset: args.destination.offset, - bytes_per_row: NonZeroU32::new(args.destination.bytes_per_row.unwrap_or(0)), - rows_per_image: NonZeroU32::new(args.destination.rows_per_image.unwrap_or(0)), - }, - }; - gfx_ok!(command_encoder => instance.command_encoder_copy_texture_to_buffer( - command_encoder, - &source, - &destination, - &args.copy_size - )) + let instance = state.borrow::(); + let command_encoder_resource = state + .resource_table + .get::(args.command_encoder_rid)?; + let command_encoder = command_encoder_resource.0; + let source_texture_resource = + state + .resource_table + .get::(args.source.texture)?; + let destination_buffer_resource = + state + .resource_table + .get::(args.destination.buffer)?; + + let source = wgpu_core::command::ImageCopyTexture { + texture: source_texture_resource.0, + mip_level: args.source.mip_level, + origin: args.source.origin, + aspect: args.source.aspect, + }; + let destination = wgpu_core::command::ImageCopyBuffer { + buffer: destination_buffer_resource.0, + layout: wgpu_types::ImageDataLayout { + offset: args.destination.offset, + bytes_per_row: NonZeroU32::new( + args.destination.bytes_per_row.unwrap_or(0), + ), + rows_per_image: NonZeroU32::new( + args.destination.rows_per_image.unwrap_or(0), + ), + }, + }; + gfx_ok!(command_encoder => instance.command_encoder_copy_texture_to_buffer( + command_encoder, + &source, + &destination, + &args.copy_size + )) } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct CommandEncoderCopyTextureToTextureArgs { - command_encoder_rid: ResourceId, - source: GpuImageCopyTexture, - destination: GpuImageCopyTexture, - copy_size: wgpu_types::Extent3d, + command_encoder_rid: ResourceId, + source: GpuImageCopyTexture, + destination: GpuImageCopyTexture, + copy_size: wgpu_types::Extent3d, } pub fn op_webgpu_command_encoder_copy_texture_to_texture( - state: &mut OpState, - args: CommandEncoderCopyTextureToTextureArgs, - _: (), + state: &mut OpState, + args: CommandEncoderCopyTextureToTextureArgs, + _: (), ) -> Result { - let instance = state.borrow::(); - let command_encoder_resource = state - .resource_table - .get::(args.command_encoder_rid)?; - let command_encoder = command_encoder_resource.0; - let source_texture_resource = state - .resource_table - .get::(args.source.texture)?; - let destination_texture_resource = state - .resource_table - .get::(args.destination.texture)?; - - let source = wgpu_core::command::ImageCopyTexture { - texture: source_texture_resource.0, - mip_level: args.source.mip_level, - origin: args.source.origin, - aspect: args.source.aspect, - }; - let destination = wgpu_core::command::ImageCopyTexture { - texture: destination_texture_resource.0, - mip_level: args.destination.mip_level, - origin: args.destination.origin, - aspect: args.destination.aspect, - }; - gfx_ok!(command_encoder => instance.command_encoder_copy_texture_to_texture( - command_encoder, - &source, - &destination, - &args.copy_size - )) + let instance = state.borrow::(); + let command_encoder_resource = state + .resource_table + .get::(args.command_encoder_rid)?; + let command_encoder = command_encoder_resource.0; + let source_texture_resource = + state + .resource_table + .get::(args.source.texture)?; + let destination_texture_resource = + state + .resource_table + .get::(args.destination.texture)?; + + let source = wgpu_core::command::ImageCopyTexture { + texture: source_texture_resource.0, + mip_level: args.source.mip_level, + origin: args.source.origin, + aspect: args.source.aspect, + }; + let destination = wgpu_core::command::ImageCopyTexture { + texture: destination_texture_resource.0, + mip_level: args.destination.mip_level, + origin: args.destination.origin, + aspect: args.destination.aspect, + }; + gfx_ok!(command_encoder => instance.command_encoder_copy_texture_to_texture( + command_encoder, + &source, + &destination, + &args.copy_size + )) } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct CommandEncoderClearBufferArgs { - command_encoder_rid: u32, - destination_rid: u32, - destination_offset: u64, - size: u64, + command_encoder_rid: u32, + destination_rid: u32, + destination_offset: u64, + size: u64, } pub fn op_webgpu_command_encoder_clear_buffer( - state: &mut OpState, - args: CommandEncoderClearBufferArgs, - _: (), + state: &mut OpState, + args: CommandEncoderClearBufferArgs, + _: (), ) -> Result { - let instance = state.borrow::(); - let command_encoder_resource = state - .resource_table - .get::(args.command_encoder_rid)?; - let command_encoder = command_encoder_resource.0; - let destination_resource = state - .resource_table - .get::(args.destination_rid)?; - - gfx_ok!(command_encoder => instance.command_encoder_clear_buffer( - command_encoder, - destination_resource.0, - args.destination_offset, - std::num::NonZeroU64::new(args.size) - )) + let instance = state.borrow::(); + let command_encoder_resource = state + .resource_table + .get::(args.command_encoder_rid)?; + let command_encoder = command_encoder_resource.0; + let destination_resource = state + .resource_table + .get::(args.destination_rid)?; + + gfx_ok!(command_encoder => instance.command_encoder_clear_buffer( + command_encoder, + destination_resource.0, + args.destination_offset, + std::num::NonZeroU64::new(args.size) + )) } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct CommandEncoderPushDebugGroupArgs { - command_encoder_rid: ResourceId, - group_label: String, + command_encoder_rid: ResourceId, + group_label: String, } pub fn op_webgpu_command_encoder_push_debug_group( - state: &mut OpState, - args: CommandEncoderPushDebugGroupArgs, - _: (), + state: &mut OpState, + args: CommandEncoderPushDebugGroupArgs, + _: (), ) -> Result { - let instance = state.borrow::(); - let command_encoder_resource = state - .resource_table - .get::(args.command_encoder_rid)?; - let command_encoder = command_encoder_resource.0; + let instance = state.borrow::(); + let command_encoder_resource = state + .resource_table + .get::(args.command_encoder_rid)?; + let command_encoder = command_encoder_resource.0; - gfx_ok!(command_encoder => instance + gfx_ok!(command_encoder => instance .command_encoder_push_debug_group(command_encoder, &args.group_label)) } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct CommandEncoderPopDebugGroupArgs { - command_encoder_rid: ResourceId, + command_encoder_rid: ResourceId, } pub fn op_webgpu_command_encoder_pop_debug_group( - state: &mut OpState, - args: CommandEncoderPopDebugGroupArgs, - _: (), + state: &mut OpState, + args: CommandEncoderPopDebugGroupArgs, + _: (), ) -> Result { - let instance = state.borrow::(); - let command_encoder_resource = state - .resource_table - .get::(args.command_encoder_rid)?; - let command_encoder = command_encoder_resource.0; + let instance = state.borrow::(); + let command_encoder_resource = state + .resource_table + .get::(args.command_encoder_rid)?; + let command_encoder = command_encoder_resource.0; - gfx_ok!(command_encoder => instance.command_encoder_pop_debug_group(command_encoder)) + gfx_ok!(command_encoder => instance.command_encoder_pop_debug_group(command_encoder)) } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct CommandEncoderInsertDebugMarkerArgs { - command_encoder_rid: ResourceId, - marker_label: String, + command_encoder_rid: ResourceId, + marker_label: String, } pub fn op_webgpu_command_encoder_insert_debug_marker( - state: &mut OpState, - args: CommandEncoderInsertDebugMarkerArgs, - _: (), + state: &mut OpState, + args: CommandEncoderInsertDebugMarkerArgs, + _: (), ) -> Result { - let instance = state.borrow::(); - let command_encoder_resource = state - .resource_table - .get::(args.command_encoder_rid)?; - let command_encoder = command_encoder_resource.0; + let instance = state.borrow::(); + let command_encoder_resource = state + .resource_table + .get::(args.command_encoder_rid)?; + let command_encoder = command_encoder_resource.0; - gfx_ok!(command_encoder => instance.command_encoder_insert_debug_marker( - command_encoder, - &args.marker_label - )) + gfx_ok!(command_encoder => instance.command_encoder_insert_debug_marker( + command_encoder, + &args.marker_label + )) } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct CommandEncoderWriteTimestampArgs { - command_encoder_rid: ResourceId, - query_set: ResourceId, - query_index: u32, + command_encoder_rid: ResourceId, + query_set: ResourceId, + query_index: u32, } pub fn op_webgpu_command_encoder_write_timestamp( - state: &mut OpState, - args: CommandEncoderWriteTimestampArgs, - _: (), + state: &mut OpState, + args: CommandEncoderWriteTimestampArgs, + _: (), ) -> Result { - let instance = state.borrow::(); - let command_encoder_resource = state - .resource_table - .get::(args.command_encoder_rid)?; - let command_encoder = command_encoder_resource.0; - let query_set_resource = state - .resource_table - .get::(args.query_set)?; - - gfx_ok!(command_encoder => instance.command_encoder_write_timestamp( - command_encoder, - query_set_resource.0, - args.query_index - )) + let instance = state.borrow::(); + let command_encoder_resource = state + .resource_table + .get::(args.command_encoder_rid)?; + let command_encoder = command_encoder_resource.0; + let query_set_resource = state + .resource_table + .get::(args.query_set)?; + + gfx_ok!(command_encoder => instance.command_encoder_write_timestamp( + command_encoder, + query_set_resource.0, + args.query_index + )) } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct CommandEncoderResolveQuerySetArgs { - command_encoder_rid: ResourceId, - query_set: ResourceId, - first_query: u32, - query_count: u32, - destination: ResourceId, - destination_offset: u64, + command_encoder_rid: ResourceId, + query_set: ResourceId, + first_query: u32, + query_count: u32, + destination: ResourceId, + destination_offset: u64, } pub fn op_webgpu_command_encoder_resolve_query_set( - state: &mut OpState, - args: CommandEncoderResolveQuerySetArgs, - _: (), + state: &mut OpState, + args: CommandEncoderResolveQuerySetArgs, + _: (), ) -> Result { - let instance = state.borrow::(); - let command_encoder_resource = state - .resource_table - .get::(args.command_encoder_rid)?; - let command_encoder = command_encoder_resource.0; - let query_set_resource = state - .resource_table - .get::(args.query_set)?; - let destination_resource = state - .resource_table - .get::(args.destination)?; - - gfx_ok!(command_encoder => instance.command_encoder_resolve_query_set( - command_encoder, - query_set_resource.0, - args.first_query, - args.query_count, - destination_resource.0, - args.destination_offset - )) + let instance = state.borrow::(); + let command_encoder_resource = state + .resource_table + .get::(args.command_encoder_rid)?; + let command_encoder = command_encoder_resource.0; + let query_set_resource = state + .resource_table + .get::(args.query_set)?; + let destination_resource = state + .resource_table + .get::(args.destination)?; + + gfx_ok!(command_encoder => instance.command_encoder_resolve_query_set( + command_encoder, + query_set_resource.0, + args.first_query, + args.query_count, + destination_resource.0, + args.destination_offset + )) } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct CommandEncoderFinishArgs { - command_encoder_rid: ResourceId, - label: Option, + command_encoder_rid: ResourceId, + label: Option, } pub fn op_webgpu_command_encoder_finish( - state: &mut OpState, - args: CommandEncoderFinishArgs, - _: (), + state: &mut OpState, + args: CommandEncoderFinishArgs, + _: (), ) -> Result { - let command_encoder_resource = state - .resource_table - .take::(args.command_encoder_rid)?; - let command_encoder = command_encoder_resource.0; - let instance = state.borrow::(); + let command_encoder_resource = state + .resource_table + .take::(args.command_encoder_rid)?; + let command_encoder = command_encoder_resource.0; + let instance = state.borrow::(); - let descriptor = wgpu_types::CommandBufferDescriptor { - label: args.label.map(Cow::from), - }; + let descriptor = wgpu_types::CommandBufferDescriptor { + label: args.label.map(Cow::from), + }; - gfx_put!(command_encoder => instance.command_encoder_finish( + gfx_put!(command_encoder => instance.command_encoder_finish( command_encoder, &descriptor ) => state, WebGpuCommandBuffer) diff --git a/ext/webgpu/src/compute_pass.rs b/ext/webgpu/src/compute_pass.rs index cd3b088949ed07..2122850adb8e54 100644 --- a/ext/webgpu/src/compute_pass.rs +++ b/ext/webgpu/src/compute_pass.rs @@ -10,340 +10,345 @@ use std::cell::RefCell; use super::error::WebGpuResult; -pub(crate) struct WebGpuComputePass(pub(crate) RefCell); +pub(crate) struct WebGpuComputePass( + pub(crate) RefCell, +); impl Resource for WebGpuComputePass { - fn name(&self) -> Cow { - "webGPUComputePass".into() - } + fn name(&self) -> Cow { + "webGPUComputePass".into() + } } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct ComputePassSetPipelineArgs { - compute_pass_rid: ResourceId, - pipeline: ResourceId, + compute_pass_rid: ResourceId, + pipeline: ResourceId, } pub fn op_webgpu_compute_pass_set_pipeline( - state: &mut OpState, - args: ComputePassSetPipelineArgs, - _: (), + state: &mut OpState, + args: ComputePassSetPipelineArgs, + _: (), ) -> Result { - let compute_pipeline_resource = state - .resource_table - .get::(args.pipeline)?; - let compute_pass_resource = state - .resource_table - .get::(args.compute_pass_rid)?; - - wgpu_core::command::compute_ffi::wgpu_compute_pass_set_pipeline( - &mut compute_pass_resource.0.borrow_mut(), - compute_pipeline_resource.0, - ); - - Ok(WebGpuResult::empty()) + let compute_pipeline_resource = + state + .resource_table + .get::(args.pipeline)?; + let compute_pass_resource = state + .resource_table + .get::(args.compute_pass_rid)?; + + wgpu_core::command::compute_ffi::wgpu_compute_pass_set_pipeline( + &mut compute_pass_resource.0.borrow_mut(), + compute_pipeline_resource.0, + ); + + Ok(WebGpuResult::empty()) } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct ComputePassDispatchArgs { - compute_pass_rid: ResourceId, - x: u32, - y: u32, - z: u32, + compute_pass_rid: ResourceId, + x: u32, + y: u32, + z: u32, } pub fn op_webgpu_compute_pass_dispatch( - state: &mut OpState, - args: ComputePassDispatchArgs, - _: (), + state: &mut OpState, + args: ComputePassDispatchArgs, + _: (), ) -> Result { - let compute_pass_resource = state - .resource_table - .get::(args.compute_pass_rid)?; - - wgpu_core::command::compute_ffi::wgpu_compute_pass_dispatch( - &mut compute_pass_resource.0.borrow_mut(), - args.x, - args.y, - args.z, - ); - - Ok(WebGpuResult::empty()) + let compute_pass_resource = state + .resource_table + .get::(args.compute_pass_rid)?; + + wgpu_core::command::compute_ffi::wgpu_compute_pass_dispatch( + &mut compute_pass_resource.0.borrow_mut(), + args.x, + args.y, + args.z, + ); + + Ok(WebGpuResult::empty()) } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct ComputePassDispatchIndirectArgs { - compute_pass_rid: ResourceId, - indirect_buffer: ResourceId, - indirect_offset: u64, + compute_pass_rid: ResourceId, + indirect_buffer: ResourceId, + indirect_offset: u64, } pub fn op_webgpu_compute_pass_dispatch_indirect( - state: &mut OpState, - args: ComputePassDispatchIndirectArgs, - _: (), + state: &mut OpState, + args: ComputePassDispatchIndirectArgs, + _: (), ) -> Result { - let buffer_resource = state - .resource_table - .get::(args.indirect_buffer)?; - let compute_pass_resource = state - .resource_table - .get::(args.compute_pass_rid)?; - - wgpu_core::command::compute_ffi::wgpu_compute_pass_dispatch_indirect( - &mut compute_pass_resource.0.borrow_mut(), - buffer_resource.0, - args.indirect_offset, - ); - - Ok(WebGpuResult::empty()) + let buffer_resource = state + .resource_table + .get::(args.indirect_buffer)?; + let compute_pass_resource = state + .resource_table + .get::(args.compute_pass_rid)?; + + wgpu_core::command::compute_ffi::wgpu_compute_pass_dispatch_indirect( + &mut compute_pass_resource.0.borrow_mut(), + buffer_resource.0, + args.indirect_offset, + ); + + Ok(WebGpuResult::empty()) } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct ComputePassBeginPipelineStatisticsQueryArgs { - compute_pass_rid: ResourceId, - query_set: ResourceId, - query_index: u32, + compute_pass_rid: ResourceId, + query_set: ResourceId, + query_index: u32, } pub fn op_webgpu_compute_pass_begin_pipeline_statistics_query( - state: &mut OpState, - args: ComputePassBeginPipelineStatisticsQueryArgs, - _: (), + state: &mut OpState, + args: ComputePassBeginPipelineStatisticsQueryArgs, + _: (), ) -> Result { - let compute_pass_resource = state - .resource_table - .get::(args.compute_pass_rid)?; - let query_set_resource = state - .resource_table - .get::(args.query_set)?; - - wgpu_core::command::compute_ffi::wgpu_compute_pass_begin_pipeline_statistics_query( + let compute_pass_resource = state + .resource_table + .get::(args.compute_pass_rid)?; + let query_set_resource = state + .resource_table + .get::(args.query_set)?; + + wgpu_core::command::compute_ffi::wgpu_compute_pass_begin_pipeline_statistics_query( &mut compute_pass_resource.0.borrow_mut(), query_set_resource.0, args.query_index, ); - Ok(WebGpuResult::empty()) + Ok(WebGpuResult::empty()) } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct ComputePassEndPipelineStatisticsQueryArgs { - compute_pass_rid: ResourceId, + compute_pass_rid: ResourceId, } pub fn op_webgpu_compute_pass_end_pipeline_statistics_query( - state: &mut OpState, - args: ComputePassEndPipelineStatisticsQueryArgs, - _: (), + state: &mut OpState, + args: ComputePassEndPipelineStatisticsQueryArgs, + _: (), ) -> Result { - let compute_pass_resource = state - .resource_table - .get::(args.compute_pass_rid)?; + let compute_pass_resource = state + .resource_table + .get::(args.compute_pass_rid)?; - wgpu_core::command::compute_ffi::wgpu_compute_pass_end_pipeline_statistics_query( + wgpu_core::command::compute_ffi::wgpu_compute_pass_end_pipeline_statistics_query( &mut compute_pass_resource.0.borrow_mut(), ); - Ok(WebGpuResult::empty()) + Ok(WebGpuResult::empty()) } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct ComputePassWriteTimestampArgs { - compute_pass_rid: ResourceId, - query_set: ResourceId, - query_index: u32, + compute_pass_rid: ResourceId, + query_set: ResourceId, + query_index: u32, } pub fn op_webgpu_compute_pass_write_timestamp( - state: &mut OpState, - args: ComputePassWriteTimestampArgs, - _: (), + state: &mut OpState, + args: ComputePassWriteTimestampArgs, + _: (), ) -> Result { - let compute_pass_resource = state - .resource_table - .get::(args.compute_pass_rid)?; - let query_set_resource = state - .resource_table - .get::(args.query_set)?; - - wgpu_core::command::compute_ffi::wgpu_compute_pass_write_timestamp( - &mut compute_pass_resource.0.borrow_mut(), - query_set_resource.0, - args.query_index, - ); - - Ok(WebGpuResult::empty()) + let compute_pass_resource = state + .resource_table + .get::(args.compute_pass_rid)?; + let query_set_resource = state + .resource_table + .get::(args.query_set)?; + + wgpu_core::command::compute_ffi::wgpu_compute_pass_write_timestamp( + &mut compute_pass_resource.0.borrow_mut(), + query_set_resource.0, + args.query_index, + ); + + Ok(WebGpuResult::empty()) } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct ComputePassEndPassArgs { - command_encoder_rid: ResourceId, - compute_pass_rid: ResourceId, + command_encoder_rid: ResourceId, + compute_pass_rid: ResourceId, } pub fn op_webgpu_compute_pass_end_pass( - state: &mut OpState, - args: ComputePassEndPassArgs, - _: (), + state: &mut OpState, + args: ComputePassEndPassArgs, + _: (), ) -> Result { - let command_encoder_resource = - state - .resource_table - .get::(args.command_encoder_rid)?; - let command_encoder = command_encoder_resource.0; - let compute_pass_resource = state - .resource_table - .take::(args.compute_pass_rid)?; - let compute_pass = &compute_pass_resource.0.borrow(); - let instance = state.borrow::(); - - gfx_ok!(command_encoder => instance.command_encoder_run_compute_pass( - command_encoder, - compute_pass - )) + let command_encoder_resource = state + .resource_table + .get::( + args.command_encoder_rid, + )?; + let command_encoder = command_encoder_resource.0; + let compute_pass_resource = state + .resource_table + .take::(args.compute_pass_rid)?; + let compute_pass = &compute_pass_resource.0.borrow(); + let instance = state.borrow::(); + + gfx_ok!(command_encoder => instance.command_encoder_run_compute_pass( + command_encoder, + compute_pass + )) } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct ComputePassSetBindGroupArgs { - compute_pass_rid: ResourceId, - index: u32, - bind_group: ResourceId, - dynamic_offsets_data: ZeroCopyBuf, - dynamic_offsets_data_start: usize, - dynamic_offsets_data_length: usize, + compute_pass_rid: ResourceId, + index: u32, + bind_group: ResourceId, + dynamic_offsets_data: ZeroCopyBuf, + dynamic_offsets_data_start: usize, + dynamic_offsets_data_length: usize, } pub fn op_webgpu_compute_pass_set_bind_group( - state: &mut OpState, - args: ComputePassSetBindGroupArgs, - _: (), + state: &mut OpState, + args: ComputePassSetBindGroupArgs, + _: (), ) -> Result { - let bind_group_resource = state - .resource_table - .get::(args.bind_group)?; - let compute_pass_resource = state - .resource_table - .get::(args.compute_pass_rid)?; - - // Align the data - assert!(args.dynamic_offsets_data_start % std::mem::size_of::() == 0); - // SAFETY: A u8 to u32 cast is safe because we asserted that the length is a - // multiple of 4. - let (prefix, dynamic_offsets_data, suffix) = - unsafe { args.dynamic_offsets_data.align_to::() }; - assert!(prefix.is_empty()); - assert!(suffix.is_empty()); - - let start = args.dynamic_offsets_data_start; - let len = args.dynamic_offsets_data_length; - - // Assert that length and start are both in bounds - assert!(start <= dynamic_offsets_data.len()); - assert!(len <= dynamic_offsets_data.len() - start); - - let dynamic_offsets_data: &[u32] = &dynamic_offsets_data[start..start + len]; - - // SAFETY: the raw pointer and length are of the same slice, and that slice - // lives longer than the below function invocation. - unsafe { - wgpu_core::command::compute_ffi::wgpu_compute_pass_set_bind_group( - &mut compute_pass_resource.0.borrow_mut(), - args.index, - bind_group_resource.0, - dynamic_offsets_data.as_ptr(), - dynamic_offsets_data.len(), - ); - } - - Ok(WebGpuResult::empty()) + let bind_group_resource = + state + .resource_table + .get::(args.bind_group)?; + let compute_pass_resource = state + .resource_table + .get::(args.compute_pass_rid)?; + + // Align the data + assert!(args.dynamic_offsets_data_start % std::mem::size_of::() == 0); + // SAFETY: A u8 to u32 cast is safe because we asserted that the length is a + // multiple of 4. + let (prefix, dynamic_offsets_data, suffix) = + unsafe { args.dynamic_offsets_data.align_to::() }; + assert!(prefix.is_empty()); + assert!(suffix.is_empty()); + + let start = args.dynamic_offsets_data_start; + let len = args.dynamic_offsets_data_length; + + // Assert that length and start are both in bounds + assert!(start <= dynamic_offsets_data.len()); + assert!(len <= dynamic_offsets_data.len() - start); + + let dynamic_offsets_data: &[u32] = &dynamic_offsets_data[start..start + len]; + + // SAFETY: the raw pointer and length are of the same slice, and that slice + // lives longer than the below function invocation. + unsafe { + wgpu_core::command::compute_ffi::wgpu_compute_pass_set_bind_group( + &mut compute_pass_resource.0.borrow_mut(), + args.index, + bind_group_resource.0, + dynamic_offsets_data.as_ptr(), + dynamic_offsets_data.len(), + ); + } + + Ok(WebGpuResult::empty()) } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct ComputePassPushDebugGroupArgs { - compute_pass_rid: ResourceId, - group_label: String, + compute_pass_rid: ResourceId, + group_label: String, } pub fn op_webgpu_compute_pass_push_debug_group( - state: &mut OpState, - args: ComputePassPushDebugGroupArgs, - _: (), + state: &mut OpState, + args: ComputePassPushDebugGroupArgs, + _: (), ) -> Result { - let compute_pass_resource = state - .resource_table - .get::(args.compute_pass_rid)?; - - let label = std::ffi::CString::new(args.group_label).unwrap(); - // SAFETY: the string the raw pointer points to lives longer than the below - // function invocation. - unsafe { - wgpu_core::command::compute_ffi::wgpu_compute_pass_push_debug_group( - &mut compute_pass_resource.0.borrow_mut(), - label.as_ptr(), - 0, // wgpu#975 - ); - } - - Ok(WebGpuResult::empty()) + let compute_pass_resource = state + .resource_table + .get::(args.compute_pass_rid)?; + + let label = std::ffi::CString::new(args.group_label).unwrap(); + // SAFETY: the string the raw pointer points to lives longer than the below + // function invocation. + unsafe { + wgpu_core::command::compute_ffi::wgpu_compute_pass_push_debug_group( + &mut compute_pass_resource.0.borrow_mut(), + label.as_ptr(), + 0, // wgpu#975 + ); + } + + Ok(WebGpuResult::empty()) } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct ComputePassPopDebugGroupArgs { - compute_pass_rid: ResourceId, + compute_pass_rid: ResourceId, } pub fn op_webgpu_compute_pass_pop_debug_group( - state: &mut OpState, - args: ComputePassPopDebugGroupArgs, - _: (), + state: &mut OpState, + args: ComputePassPopDebugGroupArgs, + _: (), ) -> Result { - let compute_pass_resource = state - .resource_table - .get::(args.compute_pass_rid)?; + let compute_pass_resource = state + .resource_table + .get::(args.compute_pass_rid)?; - wgpu_core::command::compute_ffi::wgpu_compute_pass_pop_debug_group( - &mut compute_pass_resource.0.borrow_mut(), - ); + wgpu_core::command::compute_ffi::wgpu_compute_pass_pop_debug_group( + &mut compute_pass_resource.0.borrow_mut(), + ); - Ok(WebGpuResult::empty()) + Ok(WebGpuResult::empty()) } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct ComputePassInsertDebugMarkerArgs { - compute_pass_rid: ResourceId, - marker_label: String, + compute_pass_rid: ResourceId, + marker_label: String, } pub fn op_webgpu_compute_pass_insert_debug_marker( - state: &mut OpState, - args: ComputePassInsertDebugMarkerArgs, - _: (), + state: &mut OpState, + args: ComputePassInsertDebugMarkerArgs, + _: (), ) -> Result { - let compute_pass_resource = state - .resource_table - .get::(args.compute_pass_rid)?; - - let label = std::ffi::CString::new(args.marker_label).unwrap(); - // SAFETY: the string the raw pointer points to lives longer than the below - // function invocation. - unsafe { - wgpu_core::command::compute_ffi::wgpu_compute_pass_insert_debug_marker( - &mut compute_pass_resource.0.borrow_mut(), - label.as_ptr(), - 0, // wgpu#975 - ); - } - - Ok(WebGpuResult::empty()) + let compute_pass_resource = state + .resource_table + .get::(args.compute_pass_rid)?; + + let label = std::ffi::CString::new(args.marker_label).unwrap(); + // SAFETY: the string the raw pointer points to lives longer than the below + // function invocation. + unsafe { + wgpu_core::command::compute_ffi::wgpu_compute_pass_insert_debug_marker( + &mut compute_pass_resource.0.borrow_mut(), + label.as_ptr(), + 0, // wgpu#975 + ); + } + + Ok(WebGpuResult::empty()) } diff --git a/ext/webgpu/src/error.rs b/ext/webgpu/src/error.rs index 26d7f7b24617a5..42c451746b0d76 100644 --- a/ext/webgpu/src/error.rs +++ b/ext/webgpu/src/error.rs @@ -31,259 +31,262 @@ use wgpu_core::resource::CreateTextureViewError; #[derive(Serialize)] pub struct WebGpuResult { - pub rid: Option, - pub err: Option, + pub rid: Option, + pub err: Option, } impl WebGpuResult { - pub fn rid(rid: ResourceId) -> Self { - Self { - rid: Some(rid), - err: None, - } + pub fn rid(rid: ResourceId) -> Self { + Self { + rid: Some(rid), + err: None, } - - pub fn rid_err>(rid: ResourceId, err: Option) -> Self { - Self { - rid: Some(rid), - err: err.map(|e| e.into()), - } + } + + pub fn rid_err>( + rid: ResourceId, + err: Option, + ) -> Self { + Self { + rid: Some(rid), + err: err.map(|e| e.into()), } + } - pub fn maybe_err>(err: Option) -> Self { - Self { - rid: None, - err: err.map(|e| e.into()), - } + pub fn maybe_err>(err: Option) -> Self { + Self { + rid: None, + err: err.map(|e| e.into()), } + } - pub fn empty() -> Self { - Self { - rid: None, - err: None, - } + pub fn empty() -> Self { + Self { + rid: None, + err: None, } + } } #[derive(Serialize)] #[serde(tag = "type", content = "value")] #[serde(rename_all = "kebab-case")] pub enum WebGpuError { - Lost, - OutOfMemory, - Validation(String), + Lost, + OutOfMemory, + Validation(String), } impl From for WebGpuError { - fn from(err: CreateBufferError) -> Self { - match err { - CreateBufferError::Device(err) => err.into(), - CreateBufferError::AccessError(err) => err.into(), - err => WebGpuError::Validation(err.to_string()), - } + fn from(err: CreateBufferError) -> Self { + match err { + CreateBufferError::Device(err) => err.into(), + CreateBufferError::AccessError(err) => err.into(), + err => WebGpuError::Validation(err.to_string()), } + } } impl From for WebGpuError { - fn from(err: DeviceError) -> Self { - match err { - DeviceError::Lost => WebGpuError::Lost, - DeviceError::OutOfMemory => WebGpuError::OutOfMemory, - DeviceError::Invalid => WebGpuError::Validation(err.to_string()), - } + fn from(err: DeviceError) -> Self { + match err { + DeviceError::Lost => WebGpuError::Lost, + DeviceError::OutOfMemory => WebGpuError::OutOfMemory, + DeviceError::Invalid => WebGpuError::Validation(err.to_string()), } + } } impl From for WebGpuError { - fn from(err: BufferAccessError) -> Self { - match err { - BufferAccessError::Device(err) => err.into(), - err => WebGpuError::Validation(err.to_string()), - } + fn from(err: BufferAccessError) -> Self { + match err { + BufferAccessError::Device(err) => err.into(), + err => WebGpuError::Validation(err.to_string()), } + } } impl From for WebGpuError { - fn from(err: CreateBindGroupLayoutError) -> Self { - match err { - CreateBindGroupLayoutError::Device(err) => err.into(), - err => WebGpuError::Validation(err.to_string()), - } + fn from(err: CreateBindGroupLayoutError) -> Self { + match err { + CreateBindGroupLayoutError::Device(err) => err.into(), + err => WebGpuError::Validation(err.to_string()), } + } } impl From for WebGpuError { - fn from(err: CreatePipelineLayoutError) -> Self { - match err { - CreatePipelineLayoutError::Device(err) => err.into(), - err => WebGpuError::Validation(err.to_string()), - } + fn from(err: CreatePipelineLayoutError) -> Self { + match err { + CreatePipelineLayoutError::Device(err) => err.into(), + err => WebGpuError::Validation(err.to_string()), } + } } impl From for WebGpuError { - fn from(err: CreateBindGroupError) -> Self { - match err { - CreateBindGroupError::Device(err) => err.into(), - err => WebGpuError::Validation(err.to_string()), - } + fn from(err: CreateBindGroupError) -> Self { + match err { + CreateBindGroupError::Device(err) => err.into(), + err => WebGpuError::Validation(err.to_string()), } + } } impl From for WebGpuError { - fn from(err: RenderBundleError) -> Self { - WebGpuError::Validation(err.to_string()) - } + fn from(err: RenderBundleError) -> Self { + WebGpuError::Validation(err.to_string()) + } } impl From for WebGpuError { - fn from(err: CreateRenderBundleError) -> Self { - WebGpuError::Validation(err.to_string()) - } + fn from(err: CreateRenderBundleError) -> Self { + WebGpuError::Validation(err.to_string()) + } } impl From for WebGpuError { - fn from(err: CopyError) -> Self { - WebGpuError::Validation(err.to_string()) - } + fn from(err: CopyError) -> Self { + WebGpuError::Validation(err.to_string()) + } } impl From for WebGpuError { - fn from(err: CommandEncoderError) -> Self { - WebGpuError::Validation(err.to_string()) - } + fn from(err: CommandEncoderError) -> Self { + WebGpuError::Validation(err.to_string()) + } } impl From for WebGpuError { - fn from(err: QueryError) -> Self { - WebGpuError::Validation(err.to_string()) - } + fn from(err: QueryError) -> Self { + WebGpuError::Validation(err.to_string()) + } } impl From for WebGpuError { - fn from(err: ComputePassError) -> Self { - WebGpuError::Validation(err.to_string()) - } + fn from(err: ComputePassError) -> Self { + WebGpuError::Validation(err.to_string()) + } } impl From for WebGpuError { - fn from(err: CreateComputePipelineError) -> Self { - match err { - CreateComputePipelineError::Device(err) => err.into(), - err => WebGpuError::Validation(err.to_string()), - } + fn from(err: CreateComputePipelineError) -> Self { + match err { + CreateComputePipelineError::Device(err) => err.into(), + err => WebGpuError::Validation(err.to_string()), } + } } impl From for WebGpuError { - fn from(err: GetBindGroupLayoutError) -> Self { - WebGpuError::Validation(err.to_string()) - } + fn from(err: GetBindGroupLayoutError) -> Self { + WebGpuError::Validation(err.to_string()) + } } impl From for WebGpuError { - fn from(err: CreateRenderPipelineError) -> Self { - match err { - CreateRenderPipelineError::Device(err) => err.into(), - err => WebGpuError::Validation(err.to_string()), - } + fn from(err: CreateRenderPipelineError) -> Self { + match err { + CreateRenderPipelineError::Device(err) => err.into(), + err => WebGpuError::Validation(err.to_string()), } + } } impl From for WebGpuError { - fn from(err: RenderPassError) -> Self { - WebGpuError::Validation(err.to_string()) - } + fn from(err: RenderPassError) -> Self { + WebGpuError::Validation(err.to_string()) + } } impl From for WebGpuError { - fn from(err: CreateSamplerError) -> Self { - match err { - CreateSamplerError::Device(err) => err.into(), - err => WebGpuError::Validation(err.to_string()), - } + fn from(err: CreateSamplerError) -> Self { + match err { + CreateSamplerError::Device(err) => err.into(), + err => WebGpuError::Validation(err.to_string()), } + } } impl From for WebGpuError { - fn from(err: CreateShaderModuleError) -> Self { - match err { - CreateShaderModuleError::Device(err) => err.into(), - err => WebGpuError::Validation(err.to_string()), - } + fn from(err: CreateShaderModuleError) -> Self { + match err { + CreateShaderModuleError::Device(err) => err.into(), + err => WebGpuError::Validation(err.to_string()), } + } } impl From for WebGpuError { - fn from(err: CreateTextureError) -> Self { - match err { - CreateTextureError::Device(err) => err.into(), - err => WebGpuError::Validation(err.to_string()), - } + fn from(err: CreateTextureError) -> Self { + match err { + CreateTextureError::Device(err) => err.into(), + err => WebGpuError::Validation(err.to_string()), } + } } impl From for WebGpuError { - fn from(err: CreateTextureViewError) -> Self { - WebGpuError::Validation(err.to_string()) - } + fn from(err: CreateTextureViewError) -> Self { + WebGpuError::Validation(err.to_string()) + } } impl From for WebGpuError { - fn from(err: CreateQuerySetError) -> Self { - match err { - CreateQuerySetError::Device(err) => err.into(), - err => WebGpuError::Validation(err.to_string()), - } + fn from(err: CreateQuerySetError) -> Self { + match err { + CreateQuerySetError::Device(err) => err.into(), + err => WebGpuError::Validation(err.to_string()), } + } } impl From for WebGpuError { - fn from(err: QueueSubmitError) -> Self { - match err { - QueueSubmitError::Queue(err) => err.into(), - err => WebGpuError::Validation(err.to_string()), - } + fn from(err: QueueSubmitError) -> Self { + match err { + QueueSubmitError::Queue(err) => err.into(), + err => WebGpuError::Validation(err.to_string()), } + } } impl From for WebGpuError { - fn from(err: QueueWriteError) -> Self { - match err { - QueueWriteError::Queue(err) => err.into(), - err => WebGpuError::Validation(err.to_string()), - } + fn from(err: QueueWriteError) -> Self { + match err { + QueueWriteError::Queue(err) => err.into(), + err => WebGpuError::Validation(err.to_string()), } + } } impl From for WebGpuError { - fn from(err: ClearError) -> Self { - WebGpuError::Validation(err.to_string()) - } + fn from(err: ClearError) -> Self { + WebGpuError::Validation(err.to_string()) + } } #[derive(Debug)] pub struct DomExceptionOperationError { - pub msg: String, + pub msg: String, } impl DomExceptionOperationError { - pub fn new(msg: &str) -> Self { - DomExceptionOperationError { - msg: msg.to_string(), - } + pub fn new(msg: &str) -> Self { + DomExceptionOperationError { + msg: msg.to_string(), } + } } impl fmt::Display for DomExceptionOperationError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.pad(&self.msg) - } + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad(&self.msg) + } } impl std::error::Error for DomExceptionOperationError {} pub fn get_error_class_name(e: &AnyError) -> Option<&'static str> { - e.downcast_ref::() - .map(|_| "DOMExceptionOperationError") + e.downcast_ref::() + .map(|_| "DOMExceptionOperationError") } diff --git a/ext/webgpu/src/lib.rs b/ext/webgpu/src/lib.rs index fa193e5704f4f9..87c515b25f1b5e 100644 --- a/ext/webgpu/src/lib.rs +++ b/ext/webgpu/src/lib.rs @@ -24,7 +24,7 @@ use error::WebGpuResult; #[macro_use] mod macros { - macro_rules! gfx_select { + macro_rules! gfx_select { ($id:expr => $global:ident.$method:ident( $($param:expr),* )) => { match $id.backend() { #[cfg(not(target_os = "macos"))] @@ -40,7 +40,7 @@ mod macros { }; } - macro_rules! gfx_put { + macro_rules! gfx_put { ($id:expr => $global:ident.$method:ident( $($param:expr),* ) => $state:expr, $rc:expr) => {{ let (val, maybe_err) = gfx_select!($id => $global.$method($($param),*)); let rid = $state.resource_table.add($rc(val)); @@ -48,7 +48,7 @@ mod macros { }}; } - macro_rules! gfx_ok { + macro_rules! gfx_ok { ($id:expr => $global:ident.$method:ident( $($param:expr),* )) => {{ let maybe_err = gfx_select!($id => $global.$method($($param),*)).err(); Ok(WebGpuResult::maybe_err(maybe_err)) @@ -72,482 +72,490 @@ pub mod texture; pub struct Unstable(pub bool); fn check_unstable(state: &OpState, api_name: &str) { - let unstable = state.borrow::(); - if !unstable.0 { - eprintln!( - "Unstable API '{}'. The --unstable flag must be provided.", - api_name - ); - std::process::exit(70); - } + let unstable = state.borrow::(); + if !unstable.0 { + eprintln!( + "Unstable API '{}'. The --unstable flag must be provided.", + api_name + ); + std::process::exit(70); + } } type Instance = wgpu_core::hub::Global; struct WebGpuAdapter(wgpu_core::id::AdapterId); impl Resource for WebGpuAdapter { - fn name(&self) -> Cow { - "webGPUAdapter".into() - } + fn name(&self) -> Cow { + "webGPUAdapter".into() + } } struct WebGpuDevice(wgpu_core::id::DeviceId); impl Resource for WebGpuDevice { - fn name(&self) -> Cow { - "webGPUDevice".into() - } + fn name(&self) -> Cow { + "webGPUDevice".into() + } } struct WebGpuQuerySet(wgpu_core::id::QuerySetId); impl Resource for WebGpuQuerySet { - fn name(&self) -> Cow { - "webGPUQuerySet".into() - } + fn name(&self) -> Cow { + "webGPUQuerySet".into() + } } pub fn init(unstable: bool) -> Extension { - Extension::builder() - .js(include_js_files!( - prefix "deno:deno_webgpu", - "01_webgpu.js", - "02_idl_types.js", - )) - .ops(declare_webgpu_ops()) - .state(move |state| { - // TODO: check & possibly streamline this - // Unstable might be able to be OpMiddleware - // let unstable_checker = state.borrow::(); - // let unstable = unstable_checker.unstable; - state.put(Unstable(unstable)); - Ok(()) - }) - .build() + Extension::builder() + .js(include_js_files!( + prefix "deno:deno_webgpu", + "01_webgpu.js", + "02_idl_types.js", + )) + .ops(declare_webgpu_ops()) + .state(move |state| { + // TODO: check & possibly streamline this + // Unstable might be able to be OpMiddleware + // let unstable_checker = state.borrow::(); + // let unstable = unstable_checker.unstable; + state.put(Unstable(unstable)); + Ok(()) + }) + .build() } fn deserialize_features(features: &wgpu_types::Features) -> Vec<&'static str> { - let mut return_features: Vec<&'static str> = vec![]; + let mut return_features: Vec<&'static str> = vec![]; - if features.contains(wgpu_types::Features::DEPTH_CLIP_CONTROL) { - return_features.push("depth-clip-control"); - } - if features.contains(wgpu_types::Features::PIPELINE_STATISTICS_QUERY) { - return_features.push("pipeline-statistics-query"); - } - if features.contains(wgpu_types::Features::TEXTURE_COMPRESSION_BC) { - return_features.push("texture-compression-bc"); - } - if features.contains(wgpu_types::Features::TEXTURE_COMPRESSION_ETC2) { - return_features.push("texture-compression-etc2"); - } - if features.contains(wgpu_types::Features::TEXTURE_COMPRESSION_ASTC_LDR) { - return_features.push("texture-compression-astc"); - } - if features.contains(wgpu_types::Features::TIMESTAMP_QUERY) { - return_features.push("timestamp-query"); - } - if features.contains(wgpu_types::Features::INDIRECT_FIRST_INSTANCE) { - return_features.push("indirect-first-instance"); - } + if features.contains(wgpu_types::Features::DEPTH_CLIP_CONTROL) { + return_features.push("depth-clip-control"); + } + if features.contains(wgpu_types::Features::PIPELINE_STATISTICS_QUERY) { + return_features.push("pipeline-statistics-query"); + } + if features.contains(wgpu_types::Features::TEXTURE_COMPRESSION_BC) { + return_features.push("texture-compression-bc"); + } + if features.contains(wgpu_types::Features::TEXTURE_COMPRESSION_ETC2) { + return_features.push("texture-compression-etc2"); + } + if features.contains(wgpu_types::Features::TEXTURE_COMPRESSION_ASTC_LDR) { + return_features.push("texture-compression-astc"); + } + if features.contains(wgpu_types::Features::TIMESTAMP_QUERY) { + return_features.push("timestamp-query"); + } + if features.contains(wgpu_types::Features::INDIRECT_FIRST_INSTANCE) { + return_features.push("indirect-first-instance"); + } - // extended from spec - if features.contains(wgpu_types::Features::MAPPABLE_PRIMARY_BUFFERS) { - return_features.push("mappable-primary-buffers"); - } - if features.contains(wgpu_types::Features::TEXTURE_BINDING_ARRAY) { - return_features.push("texture-binding-array"); - } - if features.contains(wgpu_types::Features::BUFFER_BINDING_ARRAY) { - return_features.push("buffer-binding-array"); - } - if features.contains(wgpu_types::Features::STORAGE_RESOURCE_BINDING_ARRAY) { - return_features.push("storage-resource-binding-array"); - } - if features.contains( + // extended from spec + if features.contains(wgpu_types::Features::MAPPABLE_PRIMARY_BUFFERS) { + return_features.push("mappable-primary-buffers"); + } + if features.contains(wgpu_types::Features::TEXTURE_BINDING_ARRAY) { + return_features.push("texture-binding-array"); + } + if features.contains(wgpu_types::Features::BUFFER_BINDING_ARRAY) { + return_features.push("buffer-binding-array"); + } + if features.contains(wgpu_types::Features::STORAGE_RESOURCE_BINDING_ARRAY) { + return_features.push("storage-resource-binding-array"); + } + if features.contains( wgpu_types::Features::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING, ) { return_features.push("sampled-texture-and-storage-buffer-array-non-uniform-indexing"); } - if features.contains( + if features.contains( wgpu_types::Features::UNIFORM_BUFFER_AND_STORAGE_TEXTURE_ARRAY_NON_UNIFORM_INDEXING, ) { return_features.push("uniform-buffer-and-storage-buffer-texture-non-uniform-indexing"); } - if features.contains(wgpu_types::Features::UNSIZED_BINDING_ARRAY) { - return_features.push("unsized-binding-array"); - } - if features.contains(wgpu_types::Features::MULTI_DRAW_INDIRECT) { - return_features.push("multi-draw-indirect"); - } - if features.contains(wgpu_types::Features::MULTI_DRAW_INDIRECT_COUNT) { - return_features.push("multi-draw-indirect-count"); - } - if features.contains(wgpu_types::Features::PUSH_CONSTANTS) { - return_features.push("push-constants"); - } - if features.contains(wgpu_types::Features::ADDRESS_MODE_CLAMP_TO_BORDER) { - return_features.push("address-mode-clamp-to-border"); - } - if features.contains(wgpu_types::Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES) { - return_features.push("texture-adapter-specific-format-features"); - } - if features.contains(wgpu_types::Features::SHADER_FLOAT64) { - return_features.push("shader-float64"); - } - if features.contains(wgpu_types::Features::VERTEX_ATTRIBUTE_64BIT) { - return_features.push("vertex-attribute-64bit"); - } - if features.contains(wgpu_types::Features::CONSERVATIVE_RASTERIZATION) { - return_features.push("conservative-rasterization"); - } - if features.contains(wgpu_types::Features::VERTEX_WRITABLE_STORAGE) { - return_features.push("vertex-writable-storage"); - } - if features.contains(wgpu_types::Features::CLEAR_TEXTURE) { - return_features.push("clear-texture"); - } - if features.contains(wgpu_types::Features::SPIRV_SHADER_PASSTHROUGH) { - return_features.push("spirv-shader-passthrough"); - } - if features.contains(wgpu_types::Features::SHADER_PRIMITIVE_INDEX) { - return_features.push("shader-primitive-index"); - } + if features.contains(wgpu_types::Features::UNSIZED_BINDING_ARRAY) { + return_features.push("unsized-binding-array"); + } + if features.contains(wgpu_types::Features::MULTI_DRAW_INDIRECT) { + return_features.push("multi-draw-indirect"); + } + if features.contains(wgpu_types::Features::MULTI_DRAW_INDIRECT_COUNT) { + return_features.push("multi-draw-indirect-count"); + } + if features.contains(wgpu_types::Features::PUSH_CONSTANTS) { + return_features.push("push-constants"); + } + if features.contains(wgpu_types::Features::ADDRESS_MODE_CLAMP_TO_BORDER) { + return_features.push("address-mode-clamp-to-border"); + } + if features + .contains(wgpu_types::Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES) + { + return_features.push("texture-adapter-specific-format-features"); + } + if features.contains(wgpu_types::Features::SHADER_FLOAT64) { + return_features.push("shader-float64"); + } + if features.contains(wgpu_types::Features::VERTEX_ATTRIBUTE_64BIT) { + return_features.push("vertex-attribute-64bit"); + } + if features.contains(wgpu_types::Features::CONSERVATIVE_RASTERIZATION) { + return_features.push("conservative-rasterization"); + } + if features.contains(wgpu_types::Features::VERTEX_WRITABLE_STORAGE) { + return_features.push("vertex-writable-storage"); + } + if features.contains(wgpu_types::Features::CLEAR_TEXTURE) { + return_features.push("clear-texture"); + } + if features.contains(wgpu_types::Features::SPIRV_SHADER_PASSTHROUGH) { + return_features.push("spirv-shader-passthrough"); + } + if features.contains(wgpu_types::Features::SHADER_PRIMITIVE_INDEX) { + return_features.push("shader-primitive-index"); + } - return_features + return_features } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct RequestAdapterArgs { - power_preference: Option, - force_fallback_adapter: bool, + power_preference: Option, + force_fallback_adapter: bool, } #[derive(Serialize)] #[serde(untagged)] pub enum GpuAdapterDeviceOrErr { - Error { err: String }, - Features(GpuAdapterDevice), + Error { err: String }, + Features(GpuAdapterDevice), } #[derive(Serialize)] #[serde(rename_all = "camelCase")] pub struct GpuAdapterDevice { - rid: ResourceId, - name: Option, - limits: wgpu_types::Limits, - features: Vec<&'static str>, - is_software: bool, + rid: ResourceId, + name: Option, + limits: wgpu_types::Limits, + features: Vec<&'static str>, + is_software: bool, } pub async fn op_webgpu_request_adapter( - state: Rc>, - args: RequestAdapterArgs, - _: (), + state: Rc>, + args: RequestAdapterArgs, + _: (), ) -> Result { - let mut state = state.borrow_mut(); - check_unstable(&state, "navigator.gpu.requestAdapter"); - let backends = std::env::var("DENO_WEBGPU_BACKEND") - .ok() - .map_or_else(wgpu_types::Backends::all, |s| { - wgpu_core::instance::parse_backends_from_comma_list(&s) - }); - let instance = if let Some(instance) = state.try_borrow::() { - instance - } else { - state.put(wgpu_core::hub::Global::new( - "webgpu", - wgpu_core::hub::IdentityManagerFactory, - backends, - )); - state.borrow::() - }; - - let descriptor = wgpu_core::instance::RequestAdapterOptions { - power_preference: match args.power_preference { - Some(power_preference) => power_preference.into(), - None => PowerPreference::default(), - }, - force_fallback_adapter: args.force_fallback_adapter, - compatible_surface: None, // windowless - }; - let res = instance.request_adapter( - &descriptor, - wgpu_core::instance::AdapterInputs::Mask(backends, |_| std::marker::PhantomData), - ); + let mut state = state.borrow_mut(); + check_unstable(&state, "navigator.gpu.requestAdapter"); + let backends = std::env::var("DENO_WEBGPU_BACKEND") + .ok() + .map_or_else(wgpu_types::Backends::all, |s| { + wgpu_core::instance::parse_backends_from_comma_list(&s) + }); + let instance = if let Some(instance) = state.try_borrow::() { + instance + } else { + state.put(wgpu_core::hub::Global::new( + "webgpu", + wgpu_core::hub::IdentityManagerFactory, + backends, + )); + state.borrow::() + }; - let adapter = match res { - Ok(adapter) => adapter, - Err(err) => { - return Ok(GpuAdapterDeviceOrErr::Error { - err: err.to_string(), - }) - } - }; - let name = gfx_select!(adapter => instance.adapter_get_info(adapter))?.name; - let adapter_features = gfx_select!(adapter => instance.adapter_features(adapter))?; - let features = deserialize_features(&adapter_features); - let adapter_limits = gfx_select!(adapter => instance.adapter_limits(adapter))?; - - let rid = state.resource_table.add(WebGpuAdapter(adapter)); - - Ok(GpuAdapterDeviceOrErr::Features(GpuAdapterDevice { - rid, - name: Some(name), - features, - limits: adapter_limits, - is_software: false, - })) + let descriptor = wgpu_core::instance::RequestAdapterOptions { + power_preference: match args.power_preference { + Some(power_preference) => power_preference.into(), + None => PowerPreference::default(), + }, + force_fallback_adapter: args.force_fallback_adapter, + compatible_surface: None, // windowless + }; + let res = instance.request_adapter( + &descriptor, + wgpu_core::instance::AdapterInputs::Mask(backends, |_| { + std::marker::PhantomData + }), + ); + + let adapter = match res { + Ok(adapter) => adapter, + Err(err) => { + return Ok(GpuAdapterDeviceOrErr::Error { + err: err.to_string(), + }) + } + }; + let name = gfx_select!(adapter => instance.adapter_get_info(adapter))?.name; + let adapter_features = + gfx_select!(adapter => instance.adapter_features(adapter))?; + let features = deserialize_features(&adapter_features); + let adapter_limits = + gfx_select!(adapter => instance.adapter_limits(adapter))?; + + let rid = state.resource_table.add(WebGpuAdapter(adapter)); + + Ok(GpuAdapterDeviceOrErr::Features(GpuAdapterDevice { + rid, + name: Some(name), + features, + limits: adapter_limits, + is_software: false, + })) } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct RequestDeviceArgs { - adapter_rid: ResourceId, - label: Option, - required_features: Option, - required_limits: Option, + adapter_rid: ResourceId, + label: Option, + required_features: Option, + required_limits: Option, } #[derive(Deserialize)] pub struct GpuRequiredFeatures(HashSet); impl From for wgpu_types::Features { - fn from(required_features: GpuRequiredFeatures) -> wgpu_types::Features { - let mut features: wgpu_types::Features = wgpu_types::Features::empty(); - features.set( - wgpu_types::Features::DEPTH_CLIP_CONTROL, - required_features.0.contains("depth-clip-control"), - ); - features.set( - wgpu_types::Features::PIPELINE_STATISTICS_QUERY, - required_features.0.contains("pipeline-statistics-query"), - ); - features.set( - wgpu_types::Features::TEXTURE_COMPRESSION_BC, - required_features.0.contains("texture-compression-bc"), - ); - features.set( - wgpu_types::Features::TEXTURE_COMPRESSION_ETC2, - required_features.0.contains("texture-compression-etc2"), - ); - features.set( - wgpu_types::Features::TEXTURE_COMPRESSION_ASTC_LDR, - required_features.0.contains("texture-compression-astc"), - ); - features.set( - wgpu_types::Features::TIMESTAMP_QUERY, - required_features.0.contains("timestamp-query"), - ); - features.set( - wgpu_types::Features::INDIRECT_FIRST_INSTANCE, - required_features.0.contains("indirect-first-instance"), - ); + fn from(required_features: GpuRequiredFeatures) -> wgpu_types::Features { + let mut features: wgpu_types::Features = wgpu_types::Features::empty(); + features.set( + wgpu_types::Features::DEPTH_CLIP_CONTROL, + required_features.0.contains("depth-clip-control"), + ); + features.set( + wgpu_types::Features::PIPELINE_STATISTICS_QUERY, + required_features.0.contains("pipeline-statistics-query"), + ); + features.set( + wgpu_types::Features::TEXTURE_COMPRESSION_BC, + required_features.0.contains("texture-compression-bc"), + ); + features.set( + wgpu_types::Features::TEXTURE_COMPRESSION_ETC2, + required_features.0.contains("texture-compression-etc2"), + ); + features.set( + wgpu_types::Features::TEXTURE_COMPRESSION_ASTC_LDR, + required_features.0.contains("texture-compression-astc"), + ); + features.set( + wgpu_types::Features::TIMESTAMP_QUERY, + required_features.0.contains("timestamp-query"), + ); + features.set( + wgpu_types::Features::INDIRECT_FIRST_INSTANCE, + required_features.0.contains("indirect-first-instance"), + ); - // extended from spec - features.set( - wgpu_types::Features::MAPPABLE_PRIMARY_BUFFERS, - required_features.0.contains("mappable-primary-buffers"), - ); - features.set( - wgpu_types::Features::TEXTURE_BINDING_ARRAY, - required_features.0.contains("texture-binding-array"), - ); - features.set( - wgpu_types::Features::BUFFER_BINDING_ARRAY, - required_features.0.contains("buffer-binding-array"), - ); - features.set( - wgpu_types::Features::STORAGE_RESOURCE_BINDING_ARRAY, - required_features - .0 - .contains("storage-resource-binding-array"), - ); - features.set( + // extended from spec + features.set( + wgpu_types::Features::MAPPABLE_PRIMARY_BUFFERS, + required_features.0.contains("mappable-primary-buffers"), + ); + features.set( + wgpu_types::Features::TEXTURE_BINDING_ARRAY, + required_features.0.contains("texture-binding-array"), + ); + features.set( + wgpu_types::Features::BUFFER_BINDING_ARRAY, + required_features.0.contains("buffer-binding-array"), + ); + features.set( + wgpu_types::Features::STORAGE_RESOURCE_BINDING_ARRAY, + required_features + .0 + .contains("storage-resource-binding-array"), + ); + features.set( wgpu_types::Features::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING, required_features .0 .contains("sampled-texture-and-storage-buffer-array-non-uniform-indexing"), ); - features.set( + features.set( wgpu_types::Features::UNIFORM_BUFFER_AND_STORAGE_TEXTURE_ARRAY_NON_UNIFORM_INDEXING, required_features .0 .contains("uniform-buffer-and-storage-buffer-texture-non-uniform-indexing"), ); - features.set( - wgpu_types::Features::UNSIZED_BINDING_ARRAY, - required_features.0.contains("unsized-binding-array"), - ); - features.set( - wgpu_types::Features::MULTI_DRAW_INDIRECT, - required_features.0.contains("multi-draw-indirect"), - ); - features.set( - wgpu_types::Features::MULTI_DRAW_INDIRECT_COUNT, - required_features.0.contains("multi-draw-indirect-count"), - ); - features.set( - wgpu_types::Features::PUSH_CONSTANTS, - required_features.0.contains("push-constants"), - ); - features.set( - wgpu_types::Features::ADDRESS_MODE_CLAMP_TO_BORDER, - required_features.0.contains("address-mode-clamp-to-border"), - ); - features.set( - wgpu_types::Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES, - required_features - .0 - .contains("texture-adapter-specific-format-features"), - ); - features.set( - wgpu_types::Features::SHADER_FLOAT64, - required_features.0.contains("shader-float64"), - ); - features.set( - wgpu_types::Features::VERTEX_ATTRIBUTE_64BIT, - required_features.0.contains("vertex-attribute-64bit"), - ); - features.set( - wgpu_types::Features::CONSERVATIVE_RASTERIZATION, - required_features.0.contains("conservative-rasterization"), - ); - features.set( - wgpu_types::Features::VERTEX_WRITABLE_STORAGE, - required_features.0.contains("vertex-writable-storage"), - ); - features.set( - wgpu_types::Features::CLEAR_TEXTURE, - required_features.0.contains("clear-commands"), - ); - features.set( - wgpu_types::Features::SPIRV_SHADER_PASSTHROUGH, - required_features.0.contains("spirv-shader-passthrough"), - ); - features.set( - wgpu_types::Features::SHADER_PRIMITIVE_INDEX, - required_features.0.contains("shader-primitive-index"), - ); + features.set( + wgpu_types::Features::UNSIZED_BINDING_ARRAY, + required_features.0.contains("unsized-binding-array"), + ); + features.set( + wgpu_types::Features::MULTI_DRAW_INDIRECT, + required_features.0.contains("multi-draw-indirect"), + ); + features.set( + wgpu_types::Features::MULTI_DRAW_INDIRECT_COUNT, + required_features.0.contains("multi-draw-indirect-count"), + ); + features.set( + wgpu_types::Features::PUSH_CONSTANTS, + required_features.0.contains("push-constants"), + ); + features.set( + wgpu_types::Features::ADDRESS_MODE_CLAMP_TO_BORDER, + required_features.0.contains("address-mode-clamp-to-border"), + ); + features.set( + wgpu_types::Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES, + required_features + .0 + .contains("texture-adapter-specific-format-features"), + ); + features.set( + wgpu_types::Features::SHADER_FLOAT64, + required_features.0.contains("shader-float64"), + ); + features.set( + wgpu_types::Features::VERTEX_ATTRIBUTE_64BIT, + required_features.0.contains("vertex-attribute-64bit"), + ); + features.set( + wgpu_types::Features::CONSERVATIVE_RASTERIZATION, + required_features.0.contains("conservative-rasterization"), + ); + features.set( + wgpu_types::Features::VERTEX_WRITABLE_STORAGE, + required_features.0.contains("vertex-writable-storage"), + ); + features.set( + wgpu_types::Features::CLEAR_TEXTURE, + required_features.0.contains("clear-commands"), + ); + features.set( + wgpu_types::Features::SPIRV_SHADER_PASSTHROUGH, + required_features.0.contains("spirv-shader-passthrough"), + ); + features.set( + wgpu_types::Features::SHADER_PRIMITIVE_INDEX, + required_features.0.contains("shader-primitive-index"), + ); - features - } + features + } } pub async fn op_webgpu_request_device( - state: Rc>, - args: RequestDeviceArgs, - _: (), + state: Rc>, + args: RequestDeviceArgs, + _: (), ) -> Result { - let mut state = state.borrow_mut(); - let adapter_resource = state - .resource_table - .get::(args.adapter_rid)?; - let adapter = adapter_resource.0; - let instance = state.borrow::(); - - let descriptor = wgpu_types::DeviceDescriptor { - label: args.label.map(Cow::from), - features: args.required_features.map(Into::into).unwrap_or_default(), - limits: args.required_limits.map(Into::into).unwrap_or_default(), - }; - - let (device, maybe_err) = gfx_select!(adapter => instance.adapter_request_device( - adapter, - &descriptor, - std::env::var("DENO_WEBGPU_TRACE").ok().as_ref().map(std::path::Path::new), - std::marker::PhantomData - )); - if let Some(err) = maybe_err { - return Err(DomExceptionOperationError::new(&err.to_string()).into()); - } - - let device_features = gfx_select!(device => instance.device_features(device))?; - let features = deserialize_features(&device_features); - let limits = gfx_select!(device => instance.device_limits(device))?; - - let rid = state.resource_table.add(WebGpuDevice(device)); + let mut state = state.borrow_mut(); + let adapter_resource = state + .resource_table + .get::(args.adapter_rid)?; + let adapter = adapter_resource.0; + let instance = state.borrow::(); + + let descriptor = wgpu_types::DeviceDescriptor { + label: args.label.map(Cow::from), + features: args.required_features.map(Into::into).unwrap_or_default(), + limits: args.required_limits.map(Into::into).unwrap_or_default(), + }; + + let (device, maybe_err) = gfx_select!(adapter => instance.adapter_request_device( + adapter, + &descriptor, + std::env::var("DENO_WEBGPU_TRACE").ok().as_ref().map(std::path::Path::new), + std::marker::PhantomData + )); + if let Some(err) = maybe_err { + return Err(DomExceptionOperationError::new(&err.to_string()).into()); + } - Ok(GpuAdapterDevice { - rid, - name: None, - features, - limits, - // TODO(lucacasonato): report correctly from wgpu - is_software: false, - }) + let device_features = + gfx_select!(device => instance.device_features(device))?; + let features = deserialize_features(&device_features); + let limits = gfx_select!(device => instance.device_limits(device))?; + + let rid = state.resource_table.add(WebGpuDevice(device)); + + Ok(GpuAdapterDevice { + rid, + name: None, + features, + limits, + // TODO(lucacasonato): report correctly from wgpu + is_software: false, + }) } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct CreateQuerySetArgs { - device_rid: ResourceId, - label: Option, - #[serde(flatten)] - r#type: GpuQueryType, - count: u32, + device_rid: ResourceId, + label: Option, + #[serde(flatten)] + r#type: GpuQueryType, + count: u32, } #[derive(Deserialize)] #[serde(rename_all = "kebab-case", tag = "type")] enum GpuQueryType { - Occlusion, - #[serde(rename_all = "camelCase")] - PipelineStatistics { - pipeline_statistics: HashSet, - }, - Timestamp, + Occlusion, + #[serde(rename_all = "camelCase")] + PipelineStatistics { + pipeline_statistics: HashSet, + }, + Timestamp, } impl From for wgpu_types::QueryType { - fn from(query_type: GpuQueryType) -> Self { - match query_type { - GpuQueryType::Occlusion => wgpu_types::QueryType::Occlusion, - GpuQueryType::PipelineStatistics { - pipeline_statistics, - } => { - use wgpu_types::PipelineStatisticsTypes; - - let mut types = PipelineStatisticsTypes::empty(); - - if pipeline_statistics.contains("vertex-shader-invocations") { - types.set(PipelineStatisticsTypes::VERTEX_SHADER_INVOCATIONS, true); - } - if pipeline_statistics.contains("clipper-invocations") { - types.set(PipelineStatisticsTypes::CLIPPER_INVOCATIONS, true); - } - if pipeline_statistics.contains("clipper-primitives-out") { - types.set(PipelineStatisticsTypes::CLIPPER_PRIMITIVES_OUT, true); - } - if pipeline_statistics.contains("fragment-shader-invocations") { - types.set(PipelineStatisticsTypes::FRAGMENT_SHADER_INVOCATIONS, true); - } - if pipeline_statistics.contains("compute-shader-invocations") { - types.set(PipelineStatisticsTypes::COMPUTE_SHADER_INVOCATIONS, true); - } - - wgpu_types::QueryType::PipelineStatistics(types) - } - GpuQueryType::Timestamp => wgpu_types::QueryType::Timestamp, + fn from(query_type: GpuQueryType) -> Self { + match query_type { + GpuQueryType::Occlusion => wgpu_types::QueryType::Occlusion, + GpuQueryType::PipelineStatistics { + pipeline_statistics, + } => { + use wgpu_types::PipelineStatisticsTypes; + + let mut types = PipelineStatisticsTypes::empty(); + + if pipeline_statistics.contains("vertex-shader-invocations") { + types.set(PipelineStatisticsTypes::VERTEX_SHADER_INVOCATIONS, true); } + if pipeline_statistics.contains("clipper-invocations") { + types.set(PipelineStatisticsTypes::CLIPPER_INVOCATIONS, true); + } + if pipeline_statistics.contains("clipper-primitives-out") { + types.set(PipelineStatisticsTypes::CLIPPER_PRIMITIVES_OUT, true); + } + if pipeline_statistics.contains("fragment-shader-invocations") { + types.set(PipelineStatisticsTypes::FRAGMENT_SHADER_INVOCATIONS, true); + } + if pipeline_statistics.contains("compute-shader-invocations") { + types.set(PipelineStatisticsTypes::COMPUTE_SHADER_INVOCATIONS, true); + } + + wgpu_types::QueryType::PipelineStatistics(types) + } + GpuQueryType::Timestamp => wgpu_types::QueryType::Timestamp, } + } } pub fn op_webgpu_create_query_set( - state: &mut OpState, - args: CreateQuerySetArgs, - _: (), + state: &mut OpState, + args: CreateQuerySetArgs, + _: (), ) -> Result { - let device_resource = state.resource_table.get::(args.device_rid)?; - let device = device_resource.0; - let instance = &state.borrow::(); - - let descriptor = wgpu_types::QuerySetDescriptor { - label: args.label.map(Cow::from), - ty: args.r#type.into(), - count: args.count, - }; - - gfx_put!(device => instance.device_create_query_set( + let device_resource = + state.resource_table.get::(args.device_rid)?; + let device = device_resource.0; + let instance = &state.borrow::(); + + let descriptor = wgpu_types::QuerySetDescriptor { + label: args.label.map(Cow::from), + ty: args.r#type.into(), + count: args.count, + }; + + gfx_put!(device => instance.device_create_query_set( device, &descriptor, std::marker::PhantomData @@ -555,334 +563,346 @@ pub fn op_webgpu_create_query_set( } fn declare_webgpu_ops() -> Vec<(&'static str, Box)> { - vec![ - // Request device/adapter - ( - "op_webgpu_request_adapter", - op_async(op_webgpu_request_adapter), - ), - ( - "op_webgpu_request_device", - op_async(op_webgpu_request_device), - ), - // Query Set - ( - "op_webgpu_create_query_set", - op_sync(op_webgpu_create_query_set), - ), - // buffer - ( - "op_webgpu_create_buffer", - op_sync(buffer::op_webgpu_create_buffer), - ), - ( - "op_webgpu_buffer_get_mapped_range", - op_sync(buffer::op_webgpu_buffer_get_mapped_range), - ), - ( - "op_webgpu_buffer_unmap", - op_sync(buffer::op_webgpu_buffer_unmap), - ), - // buffer async - ( - "op_webgpu_buffer_get_map_async", - op_async(buffer::op_webgpu_buffer_get_map_async), - ), - // remaining sync ops - - // texture - ( - "op_webgpu_create_texture", - op_sync(texture::op_webgpu_create_texture), - ), - ( - "op_webgpu_create_texture_view", - op_sync(texture::op_webgpu_create_texture_view), - ), - // sampler - ( - "op_webgpu_create_sampler", - op_sync(sampler::op_webgpu_create_sampler), - ), - // binding - ( - "op_webgpu_create_bind_group_layout", - op_sync(binding::op_webgpu_create_bind_group_layout), - ), - ( - "op_webgpu_create_pipeline_layout", - op_sync(binding::op_webgpu_create_pipeline_layout), - ), - ( - "op_webgpu_create_bind_group", - op_sync(binding::op_webgpu_create_bind_group), - ), - // pipeline - ( - "op_webgpu_create_compute_pipeline", - op_sync(pipeline::op_webgpu_create_compute_pipeline), - ), - ( - "op_webgpu_compute_pipeline_get_bind_group_layout", - op_sync(pipeline::op_webgpu_compute_pipeline_get_bind_group_layout), - ), - ( - "op_webgpu_create_render_pipeline", - op_sync(pipeline::op_webgpu_create_render_pipeline), - ), - ( - "op_webgpu_render_pipeline_get_bind_group_layout", - op_sync(pipeline::op_webgpu_render_pipeline_get_bind_group_layout), - ), - // command_encoder - ( - "op_webgpu_create_command_encoder", - op_sync(command_encoder::op_webgpu_create_command_encoder), - ), - ( - "op_webgpu_command_encoder_begin_render_pass", - op_sync(command_encoder::op_webgpu_command_encoder_begin_render_pass), - ), - ( - "op_webgpu_command_encoder_begin_compute_pass", - op_sync(command_encoder::op_webgpu_command_encoder_begin_compute_pass), - ), - ( - "op_webgpu_command_encoder_copy_buffer_to_buffer", - op_sync(command_encoder::op_webgpu_command_encoder_copy_buffer_to_buffer), - ), - ( - "op_webgpu_command_encoder_copy_buffer_to_texture", - op_sync(command_encoder::op_webgpu_command_encoder_copy_buffer_to_texture), - ), - ( - "op_webgpu_command_encoder_copy_texture_to_buffer", - op_sync(command_encoder::op_webgpu_command_encoder_copy_texture_to_buffer), - ), - ( - "op_webgpu_command_encoder_copy_texture_to_texture", - op_sync(command_encoder::op_webgpu_command_encoder_copy_texture_to_texture), - ), - ( - "op_webgpu_command_encoder_clear_buffer", - op_sync(command_encoder::op_webgpu_command_encoder_clear_buffer), - ), - ( - "op_webgpu_command_encoder_push_debug_group", - op_sync(command_encoder::op_webgpu_command_encoder_push_debug_group), - ), - ( - "op_webgpu_command_encoder_pop_debug_group", - op_sync(command_encoder::op_webgpu_command_encoder_pop_debug_group), - ), - ( - "op_webgpu_command_encoder_insert_debug_marker", - op_sync(command_encoder::op_webgpu_command_encoder_insert_debug_marker), - ), - ( - "op_webgpu_command_encoder_write_timestamp", - op_sync(command_encoder::op_webgpu_command_encoder_write_timestamp), - ), - ( - "op_webgpu_command_encoder_resolve_query_set", - op_sync(command_encoder::op_webgpu_command_encoder_resolve_query_set), - ), - ( - "op_webgpu_command_encoder_finish", - op_sync(command_encoder::op_webgpu_command_encoder_finish), - ), - // render_pass - ( - "op_webgpu_render_pass_set_viewport", - op_sync(render_pass::op_webgpu_render_pass_set_viewport), - ), - ( - "op_webgpu_render_pass_set_scissor_rect", - op_sync(render_pass::op_webgpu_render_pass_set_scissor_rect), - ), - ( - "op_webgpu_render_pass_set_blend_constant", - op_sync(render_pass::op_webgpu_render_pass_set_blend_constant), - ), - ( - "op_webgpu_render_pass_set_stencil_reference", - op_sync(render_pass::op_webgpu_render_pass_set_stencil_reference), - ), - ( - "op_webgpu_render_pass_begin_pipeline_statistics_query", - op_sync(render_pass::op_webgpu_render_pass_begin_pipeline_statistics_query), - ), - ( - "op_webgpu_render_pass_end_pipeline_statistics_query", - op_sync(render_pass::op_webgpu_render_pass_end_pipeline_statistics_query), - ), - ( - "op_webgpu_render_pass_write_timestamp", - op_sync(render_pass::op_webgpu_render_pass_write_timestamp), - ), - ( - "op_webgpu_render_pass_execute_bundles", - op_sync(render_pass::op_webgpu_render_pass_execute_bundles), - ), - ( - "op_webgpu_render_pass_end_pass", - op_sync(render_pass::op_webgpu_render_pass_end_pass), - ), - ( - "op_webgpu_render_pass_set_bind_group", - op_sync(render_pass::op_webgpu_render_pass_set_bind_group), - ), - ( - "op_webgpu_render_pass_push_debug_group", - op_sync(render_pass::op_webgpu_render_pass_push_debug_group), - ), - ( - "op_webgpu_render_pass_pop_debug_group", - op_sync(render_pass::op_webgpu_render_pass_pop_debug_group), - ), - ( - "op_webgpu_render_pass_insert_debug_marker", - op_sync(render_pass::op_webgpu_render_pass_insert_debug_marker), - ), - ( - "op_webgpu_render_pass_set_pipeline", - op_sync(render_pass::op_webgpu_render_pass_set_pipeline), - ), - ( - "op_webgpu_render_pass_set_index_buffer", - op_sync(render_pass::op_webgpu_render_pass_set_index_buffer), - ), - ( - "op_webgpu_render_pass_set_vertex_buffer", - op_sync(render_pass::op_webgpu_render_pass_set_vertex_buffer), - ), - ( - "op_webgpu_render_pass_draw", - op_sync(render_pass::op_webgpu_render_pass_draw), - ), - ( - "op_webgpu_render_pass_draw_indexed", - op_sync(render_pass::op_webgpu_render_pass_draw_indexed), - ), - ( - "op_webgpu_render_pass_draw_indirect", - op_sync(render_pass::op_webgpu_render_pass_draw_indirect), - ), - ( - "op_webgpu_render_pass_draw_indexed_indirect", - op_sync(render_pass::op_webgpu_render_pass_draw_indexed_indirect), - ), - // compute_pass - ( - "op_webgpu_compute_pass_set_pipeline", - op_sync(compute_pass::op_webgpu_compute_pass_set_pipeline), - ), - ( - "op_webgpu_compute_pass_dispatch", - op_sync(compute_pass::op_webgpu_compute_pass_dispatch), - ), - ( - "op_webgpu_compute_pass_dispatch_indirect", - op_sync(compute_pass::op_webgpu_compute_pass_dispatch_indirect), - ), - ( - "op_webgpu_compute_pass_begin_pipeline_statistics_query", - op_sync(compute_pass::op_webgpu_compute_pass_begin_pipeline_statistics_query), - ), - ( - "op_webgpu_compute_pass_end_pipeline_statistics_query", - op_sync(compute_pass::op_webgpu_compute_pass_end_pipeline_statistics_query), - ), - ( - "op_webgpu_compute_pass_write_timestamp", - op_sync(compute_pass::op_webgpu_compute_pass_write_timestamp), - ), - ( - "op_webgpu_compute_pass_end_pass", - op_sync(compute_pass::op_webgpu_compute_pass_end_pass), - ), - ( - "op_webgpu_compute_pass_set_bind_group", - op_sync(compute_pass::op_webgpu_compute_pass_set_bind_group), - ), - ( - "op_webgpu_compute_pass_push_debug_group", - op_sync(compute_pass::op_webgpu_compute_pass_push_debug_group), - ), - ( - "op_webgpu_compute_pass_pop_debug_group", - op_sync(compute_pass::op_webgpu_compute_pass_pop_debug_group), - ), - ( - "op_webgpu_compute_pass_insert_debug_marker", - op_sync(compute_pass::op_webgpu_compute_pass_insert_debug_marker), - ), - // bundle - ( - "op_webgpu_create_render_bundle_encoder", - op_sync(bundle::op_webgpu_create_render_bundle_encoder), - ), - ( - "op_webgpu_render_bundle_encoder_finish", - op_sync(bundle::op_webgpu_render_bundle_encoder_finish), - ), - ( - "op_webgpu_render_bundle_encoder_set_bind_group", - op_sync(bundle::op_webgpu_render_bundle_encoder_set_bind_group), - ), - ( - "op_webgpu_render_bundle_encoder_push_debug_group", - op_sync(bundle::op_webgpu_render_bundle_encoder_push_debug_group), - ), - ( - "op_webgpu_render_bundle_encoder_pop_debug_group", - op_sync(bundle::op_webgpu_render_bundle_encoder_pop_debug_group), - ), - ( - "op_webgpu_render_bundle_encoder_insert_debug_marker", - op_sync(bundle::op_webgpu_render_bundle_encoder_insert_debug_marker), - ), - ( - "op_webgpu_render_bundle_encoder_set_pipeline", - op_sync(bundle::op_webgpu_render_bundle_encoder_set_pipeline), - ), - ( - "op_webgpu_render_bundle_encoder_set_index_buffer", - op_sync(bundle::op_webgpu_render_bundle_encoder_set_index_buffer), - ), - ( - "op_webgpu_render_bundle_encoder_set_vertex_buffer", - op_sync(bundle::op_webgpu_render_bundle_encoder_set_vertex_buffer), - ), - ( - "op_webgpu_render_bundle_encoder_draw", - op_sync(bundle::op_webgpu_render_bundle_encoder_draw), - ), - ( - "op_webgpu_render_bundle_encoder_draw_indexed", - op_sync(bundle::op_webgpu_render_bundle_encoder_draw_indexed), - ), - ( - "op_webgpu_render_bundle_encoder_draw_indirect", - op_sync(bundle::op_webgpu_render_bundle_encoder_draw_indirect), - ), - // queue - ( - "op_webgpu_queue_submit", - op_sync(queue::op_webgpu_queue_submit), - ), - ( - "op_webgpu_write_buffer", - op_sync(queue::op_webgpu_write_buffer), - ), - ( - "op_webgpu_write_texture", - op_sync(queue::op_webgpu_write_texture), - ), - // shader - ( - "op_webgpu_create_shader_module", - op_sync(shader::op_webgpu_create_shader_module), - ), - ] + vec![ + // Request device/adapter + ( + "op_webgpu_request_adapter", + op_async(op_webgpu_request_adapter), + ), + ( + "op_webgpu_request_device", + op_async(op_webgpu_request_device), + ), + // Query Set + ( + "op_webgpu_create_query_set", + op_sync(op_webgpu_create_query_set), + ), + // buffer + ( + "op_webgpu_create_buffer", + op_sync(buffer::op_webgpu_create_buffer), + ), + ( + "op_webgpu_buffer_get_mapped_range", + op_sync(buffer::op_webgpu_buffer_get_mapped_range), + ), + ( + "op_webgpu_buffer_unmap", + op_sync(buffer::op_webgpu_buffer_unmap), + ), + // buffer async + ( + "op_webgpu_buffer_get_map_async", + op_async(buffer::op_webgpu_buffer_get_map_async), + ), + // remaining sync ops + + // texture + ( + "op_webgpu_create_texture", + op_sync(texture::op_webgpu_create_texture), + ), + ( + "op_webgpu_create_texture_view", + op_sync(texture::op_webgpu_create_texture_view), + ), + // sampler + ( + "op_webgpu_create_sampler", + op_sync(sampler::op_webgpu_create_sampler), + ), + // binding + ( + "op_webgpu_create_bind_group_layout", + op_sync(binding::op_webgpu_create_bind_group_layout), + ), + ( + "op_webgpu_create_pipeline_layout", + op_sync(binding::op_webgpu_create_pipeline_layout), + ), + ( + "op_webgpu_create_bind_group", + op_sync(binding::op_webgpu_create_bind_group), + ), + // pipeline + ( + "op_webgpu_create_compute_pipeline", + op_sync(pipeline::op_webgpu_create_compute_pipeline), + ), + ( + "op_webgpu_compute_pipeline_get_bind_group_layout", + op_sync(pipeline::op_webgpu_compute_pipeline_get_bind_group_layout), + ), + ( + "op_webgpu_create_render_pipeline", + op_sync(pipeline::op_webgpu_create_render_pipeline), + ), + ( + "op_webgpu_render_pipeline_get_bind_group_layout", + op_sync(pipeline::op_webgpu_render_pipeline_get_bind_group_layout), + ), + // command_encoder + ( + "op_webgpu_create_command_encoder", + op_sync(command_encoder::op_webgpu_create_command_encoder), + ), + ( + "op_webgpu_command_encoder_begin_render_pass", + op_sync(command_encoder::op_webgpu_command_encoder_begin_render_pass), + ), + ( + "op_webgpu_command_encoder_begin_compute_pass", + op_sync(command_encoder::op_webgpu_command_encoder_begin_compute_pass), + ), + ( + "op_webgpu_command_encoder_copy_buffer_to_buffer", + op_sync(command_encoder::op_webgpu_command_encoder_copy_buffer_to_buffer), + ), + ( + "op_webgpu_command_encoder_copy_buffer_to_texture", + op_sync( + command_encoder::op_webgpu_command_encoder_copy_buffer_to_texture, + ), + ), + ( + "op_webgpu_command_encoder_copy_texture_to_buffer", + op_sync( + command_encoder::op_webgpu_command_encoder_copy_texture_to_buffer, + ), + ), + ( + "op_webgpu_command_encoder_copy_texture_to_texture", + op_sync( + command_encoder::op_webgpu_command_encoder_copy_texture_to_texture, + ), + ), + ( + "op_webgpu_command_encoder_clear_buffer", + op_sync(command_encoder::op_webgpu_command_encoder_clear_buffer), + ), + ( + "op_webgpu_command_encoder_push_debug_group", + op_sync(command_encoder::op_webgpu_command_encoder_push_debug_group), + ), + ( + "op_webgpu_command_encoder_pop_debug_group", + op_sync(command_encoder::op_webgpu_command_encoder_pop_debug_group), + ), + ( + "op_webgpu_command_encoder_insert_debug_marker", + op_sync(command_encoder::op_webgpu_command_encoder_insert_debug_marker), + ), + ( + "op_webgpu_command_encoder_write_timestamp", + op_sync(command_encoder::op_webgpu_command_encoder_write_timestamp), + ), + ( + "op_webgpu_command_encoder_resolve_query_set", + op_sync(command_encoder::op_webgpu_command_encoder_resolve_query_set), + ), + ( + "op_webgpu_command_encoder_finish", + op_sync(command_encoder::op_webgpu_command_encoder_finish), + ), + // render_pass + ( + "op_webgpu_render_pass_set_viewport", + op_sync(render_pass::op_webgpu_render_pass_set_viewport), + ), + ( + "op_webgpu_render_pass_set_scissor_rect", + op_sync(render_pass::op_webgpu_render_pass_set_scissor_rect), + ), + ( + "op_webgpu_render_pass_set_blend_constant", + op_sync(render_pass::op_webgpu_render_pass_set_blend_constant), + ), + ( + "op_webgpu_render_pass_set_stencil_reference", + op_sync(render_pass::op_webgpu_render_pass_set_stencil_reference), + ), + ( + "op_webgpu_render_pass_begin_pipeline_statistics_query", + op_sync( + render_pass::op_webgpu_render_pass_begin_pipeline_statistics_query, + ), + ), + ( + "op_webgpu_render_pass_end_pipeline_statistics_query", + op_sync(render_pass::op_webgpu_render_pass_end_pipeline_statistics_query), + ), + ( + "op_webgpu_render_pass_write_timestamp", + op_sync(render_pass::op_webgpu_render_pass_write_timestamp), + ), + ( + "op_webgpu_render_pass_execute_bundles", + op_sync(render_pass::op_webgpu_render_pass_execute_bundles), + ), + ( + "op_webgpu_render_pass_end_pass", + op_sync(render_pass::op_webgpu_render_pass_end_pass), + ), + ( + "op_webgpu_render_pass_set_bind_group", + op_sync(render_pass::op_webgpu_render_pass_set_bind_group), + ), + ( + "op_webgpu_render_pass_push_debug_group", + op_sync(render_pass::op_webgpu_render_pass_push_debug_group), + ), + ( + "op_webgpu_render_pass_pop_debug_group", + op_sync(render_pass::op_webgpu_render_pass_pop_debug_group), + ), + ( + "op_webgpu_render_pass_insert_debug_marker", + op_sync(render_pass::op_webgpu_render_pass_insert_debug_marker), + ), + ( + "op_webgpu_render_pass_set_pipeline", + op_sync(render_pass::op_webgpu_render_pass_set_pipeline), + ), + ( + "op_webgpu_render_pass_set_index_buffer", + op_sync(render_pass::op_webgpu_render_pass_set_index_buffer), + ), + ( + "op_webgpu_render_pass_set_vertex_buffer", + op_sync(render_pass::op_webgpu_render_pass_set_vertex_buffer), + ), + ( + "op_webgpu_render_pass_draw", + op_sync(render_pass::op_webgpu_render_pass_draw), + ), + ( + "op_webgpu_render_pass_draw_indexed", + op_sync(render_pass::op_webgpu_render_pass_draw_indexed), + ), + ( + "op_webgpu_render_pass_draw_indirect", + op_sync(render_pass::op_webgpu_render_pass_draw_indirect), + ), + ( + "op_webgpu_render_pass_draw_indexed_indirect", + op_sync(render_pass::op_webgpu_render_pass_draw_indexed_indirect), + ), + // compute_pass + ( + "op_webgpu_compute_pass_set_pipeline", + op_sync(compute_pass::op_webgpu_compute_pass_set_pipeline), + ), + ( + "op_webgpu_compute_pass_dispatch", + op_sync(compute_pass::op_webgpu_compute_pass_dispatch), + ), + ( + "op_webgpu_compute_pass_dispatch_indirect", + op_sync(compute_pass::op_webgpu_compute_pass_dispatch_indirect), + ), + ( + "op_webgpu_compute_pass_begin_pipeline_statistics_query", + op_sync( + compute_pass::op_webgpu_compute_pass_begin_pipeline_statistics_query, + ), + ), + ( + "op_webgpu_compute_pass_end_pipeline_statistics_query", + op_sync( + compute_pass::op_webgpu_compute_pass_end_pipeline_statistics_query, + ), + ), + ( + "op_webgpu_compute_pass_write_timestamp", + op_sync(compute_pass::op_webgpu_compute_pass_write_timestamp), + ), + ( + "op_webgpu_compute_pass_end_pass", + op_sync(compute_pass::op_webgpu_compute_pass_end_pass), + ), + ( + "op_webgpu_compute_pass_set_bind_group", + op_sync(compute_pass::op_webgpu_compute_pass_set_bind_group), + ), + ( + "op_webgpu_compute_pass_push_debug_group", + op_sync(compute_pass::op_webgpu_compute_pass_push_debug_group), + ), + ( + "op_webgpu_compute_pass_pop_debug_group", + op_sync(compute_pass::op_webgpu_compute_pass_pop_debug_group), + ), + ( + "op_webgpu_compute_pass_insert_debug_marker", + op_sync(compute_pass::op_webgpu_compute_pass_insert_debug_marker), + ), + // bundle + ( + "op_webgpu_create_render_bundle_encoder", + op_sync(bundle::op_webgpu_create_render_bundle_encoder), + ), + ( + "op_webgpu_render_bundle_encoder_finish", + op_sync(bundle::op_webgpu_render_bundle_encoder_finish), + ), + ( + "op_webgpu_render_bundle_encoder_set_bind_group", + op_sync(bundle::op_webgpu_render_bundle_encoder_set_bind_group), + ), + ( + "op_webgpu_render_bundle_encoder_push_debug_group", + op_sync(bundle::op_webgpu_render_bundle_encoder_push_debug_group), + ), + ( + "op_webgpu_render_bundle_encoder_pop_debug_group", + op_sync(bundle::op_webgpu_render_bundle_encoder_pop_debug_group), + ), + ( + "op_webgpu_render_bundle_encoder_insert_debug_marker", + op_sync(bundle::op_webgpu_render_bundle_encoder_insert_debug_marker), + ), + ( + "op_webgpu_render_bundle_encoder_set_pipeline", + op_sync(bundle::op_webgpu_render_bundle_encoder_set_pipeline), + ), + ( + "op_webgpu_render_bundle_encoder_set_index_buffer", + op_sync(bundle::op_webgpu_render_bundle_encoder_set_index_buffer), + ), + ( + "op_webgpu_render_bundle_encoder_set_vertex_buffer", + op_sync(bundle::op_webgpu_render_bundle_encoder_set_vertex_buffer), + ), + ( + "op_webgpu_render_bundle_encoder_draw", + op_sync(bundle::op_webgpu_render_bundle_encoder_draw), + ), + ( + "op_webgpu_render_bundle_encoder_draw_indexed", + op_sync(bundle::op_webgpu_render_bundle_encoder_draw_indexed), + ), + ( + "op_webgpu_render_bundle_encoder_draw_indirect", + op_sync(bundle::op_webgpu_render_bundle_encoder_draw_indirect), + ), + // queue + ( + "op_webgpu_queue_submit", + op_sync(queue::op_webgpu_queue_submit), + ), + ( + "op_webgpu_write_buffer", + op_sync(queue::op_webgpu_write_buffer), + ), + ( + "op_webgpu_write_texture", + op_sync(queue::op_webgpu_write_texture), + ), + // shader + ( + "op_webgpu_create_shader_module", + op_sync(shader::op_webgpu_create_shader_module), + ), + ] } diff --git a/ext/webgpu/src/pipeline.rs b/ext/webgpu/src/pipeline.rs index 106f8d0bce9d09..fd45d66b14eff7 100644 --- a/ext/webgpu/src/pipeline.rs +++ b/ext/webgpu/src/pipeline.rs @@ -13,406 +13,419 @@ use super::error::WebGpuResult; const MAX_BIND_GROUPS: usize = 8; -pub(crate) struct WebGpuPipelineLayout(pub(crate) wgpu_core::id::PipelineLayoutId); +pub(crate) struct WebGpuPipelineLayout( + pub(crate) wgpu_core::id::PipelineLayoutId, +); impl Resource for WebGpuPipelineLayout { - fn name(&self) -> Cow { - "webGPUPipelineLayout".into() - } + fn name(&self) -> Cow { + "webGPUPipelineLayout".into() + } } -pub(crate) struct WebGpuComputePipeline(pub(crate) wgpu_core::id::ComputePipelineId); +pub(crate) struct WebGpuComputePipeline( + pub(crate) wgpu_core::id::ComputePipelineId, +); impl Resource for WebGpuComputePipeline { - fn name(&self) -> Cow { - "webGPUComputePipeline".into() - } + fn name(&self) -> Cow { + "webGPUComputePipeline".into() + } } -pub(crate) struct WebGpuRenderPipeline(pub(crate) wgpu_core::id::RenderPipelineId); +pub(crate) struct WebGpuRenderPipeline( + pub(crate) wgpu_core::id::RenderPipelineId, +); impl Resource for WebGpuRenderPipeline { - fn name(&self) -> Cow { - "webGPURenderPipeline".into() - } + fn name(&self) -> Cow { + "webGPURenderPipeline".into() + } } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct GpuProgrammableStage { - module: ResourceId, - entry_point: String, - // constants: HashMap + module: ResourceId, + entry_point: String, + // constants: HashMap } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct CreateComputePipelineArgs { - device_rid: ResourceId, - label: Option, - layout: Option, - compute: GpuProgrammableStage, + device_rid: ResourceId, + label: Option, + layout: Option, + compute: GpuProgrammableStage, } pub fn op_webgpu_create_compute_pipeline( - state: &mut OpState, - args: CreateComputePipelineArgs, - _: (), + state: &mut OpState, + args: CreateComputePipelineArgs, + _: (), ) -> Result { - let instance = state.borrow::(); - let device_resource = state - .resource_table - .get::(args.device_rid)?; - let device = device_resource.0; - - let pipeline_layout = if let Some(rid) = args.layout { - let id = state.resource_table.get::(rid)?; - Some(id.0) - } else { - None - }; - - let compute_shader_module_resource = state - .resource_table - .get::(args.compute.module)?; - - let descriptor = wgpu_core::pipeline::ComputePipelineDescriptor { - label: args.label.map(Cow::from), - layout: pipeline_layout, - stage: wgpu_core::pipeline::ProgrammableStageDescriptor { - module: compute_shader_module_resource.0, - entry_point: Cow::from(args.compute.entry_point), - // TODO(lucacasonato): support args.compute.constants - }, - }; - let implicit_pipelines = match args.layout { - Some(_) => None, - None => Some(wgpu_core::device::ImplicitPipelineIds { - root_id: std::marker::PhantomData, - group_ids: &[std::marker::PhantomData; MAX_BIND_GROUPS], - }), - }; - - let (compute_pipeline, maybe_err) = gfx_select!(device => instance.device_create_compute_pipeline( - device, - &descriptor, - std::marker::PhantomData, - implicit_pipelines - )); - - let rid = state - .resource_table - .add(WebGpuComputePipeline(compute_pipeline)); - - Ok(WebGpuResult::rid_err(rid, maybe_err)) + let instance = state.borrow::(); + let device_resource = state + .resource_table + .get::(args.device_rid)?; + let device = device_resource.0; + + let pipeline_layout = if let Some(rid) = args.layout { + let id = state.resource_table.get::(rid)?; + Some(id.0) + } else { + None + }; + + let compute_shader_module_resource = + state + .resource_table + .get::(args.compute.module)?; + + let descriptor = wgpu_core::pipeline::ComputePipelineDescriptor { + label: args.label.map(Cow::from), + layout: pipeline_layout, + stage: wgpu_core::pipeline::ProgrammableStageDescriptor { + module: compute_shader_module_resource.0, + entry_point: Cow::from(args.compute.entry_point), + // TODO(lucacasonato): support args.compute.constants + }, + }; + let implicit_pipelines = match args.layout { + Some(_) => None, + None => Some(wgpu_core::device::ImplicitPipelineIds { + root_id: std::marker::PhantomData, + group_ids: &[std::marker::PhantomData; MAX_BIND_GROUPS], + }), + }; + + let (compute_pipeline, maybe_err) = gfx_select!(device => instance.device_create_compute_pipeline( + device, + &descriptor, + std::marker::PhantomData, + implicit_pipelines + )); + + let rid = state + .resource_table + .add(WebGpuComputePipeline(compute_pipeline)); + + Ok(WebGpuResult::rid_err(rid, maybe_err)) } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct ComputePipelineGetBindGroupLayoutArgs { - compute_pipeline_rid: ResourceId, - index: u32, + compute_pipeline_rid: ResourceId, + index: u32, } #[derive(Serialize)] #[serde(rename_all = "camelCase")] pub struct PipelineLayout { - rid: ResourceId, - label: String, - err: Option, + rid: ResourceId, + label: String, + err: Option, } pub fn op_webgpu_compute_pipeline_get_bind_group_layout( - state: &mut OpState, - args: ComputePipelineGetBindGroupLayoutArgs, - _: (), + state: &mut OpState, + args: ComputePipelineGetBindGroupLayoutArgs, + _: (), ) -> Result { - let instance = state.borrow::(); - let compute_pipeline_resource = state - .resource_table - .get::(args.compute_pipeline_rid)?; - let compute_pipeline = compute_pipeline_resource.0; + let instance = state.borrow::(); + let compute_pipeline_resource = state + .resource_table + .get::(args.compute_pipeline_rid)?; + let compute_pipeline = compute_pipeline_resource.0; - let (bind_group_layout, maybe_err) = gfx_select!(compute_pipeline => instance.compute_pipeline_get_bind_group_layout(compute_pipeline, args.index, std::marker::PhantomData)); + let (bind_group_layout, maybe_err) = gfx_select!(compute_pipeline => instance.compute_pipeline_get_bind_group_layout(compute_pipeline, args.index, std::marker::PhantomData)); - let label = - gfx_select!(bind_group_layout => instance.bind_group_layout_label(bind_group_layout)); + let label = gfx_select!(bind_group_layout => instance.bind_group_layout_label(bind_group_layout)); - let rid = state - .resource_table - .add(super::binding::WebGpuBindGroupLayout(bind_group_layout)); + let rid = state + .resource_table + .add(super::binding::WebGpuBindGroupLayout(bind_group_layout)); - Ok(PipelineLayout { - rid, - label, - err: maybe_err.map(WebGpuError::from), - }) + Ok(PipelineLayout { + rid, + label, + err: maybe_err.map(WebGpuError::from), + }) } #[derive(Deserialize)] #[serde(rename_all = "kebab-case")] pub enum GpuCullMode { - None, - Front, - Back, + None, + Front, + Back, } impl From for Option { - fn from(value: GpuCullMode) -> Option { - match value { - GpuCullMode::None => None, - GpuCullMode::Front => Some(wgpu_types::Face::Front), - GpuCullMode::Back => Some(wgpu_types::Face::Back), - } + fn from(value: GpuCullMode) -> Option { + match value { + GpuCullMode::None => None, + GpuCullMode::Front => Some(wgpu_types::Face::Front), + GpuCullMode::Back => Some(wgpu_types::Face::Back), } + } } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct GpuPrimitiveState { - topology: wgpu_types::PrimitiveTopology, - strip_index_format: Option, - front_face: wgpu_types::FrontFace, - cull_mode: GpuCullMode, - unclipped_depth: bool, + topology: wgpu_types::PrimitiveTopology, + strip_index_format: Option, + front_face: wgpu_types::FrontFace, + cull_mode: GpuCullMode, + unclipped_depth: bool, } impl From for wgpu_types::PrimitiveState { - fn from(value: GpuPrimitiveState) -> wgpu_types::PrimitiveState { - wgpu_types::PrimitiveState { - topology: value.topology, - strip_index_format: value.strip_index_format, - front_face: value.front_face, - cull_mode: value.cull_mode.into(), - unclipped_depth: value.unclipped_depth, - polygon_mode: Default::default(), // native-only - conservative: false, // native-only - } + fn from(value: GpuPrimitiveState) -> wgpu_types::PrimitiveState { + wgpu_types::PrimitiveState { + topology: value.topology, + strip_index_format: value.strip_index_format, + front_face: value.front_face, + cull_mode: value.cull_mode.into(), + unclipped_depth: value.unclipped_depth, + polygon_mode: Default::default(), // native-only + conservative: false, // native-only } + } } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct GpuDepthStencilState { - format: wgpu_types::TextureFormat, - depth_write_enabled: bool, - depth_compare: wgpu_types::CompareFunction, - stencil_front: wgpu_types::StencilFaceState, - stencil_back: wgpu_types::StencilFaceState, - stencil_read_mask: u32, - stencil_write_mask: u32, - depth_bias: i32, - depth_bias_slope_scale: f32, - depth_bias_clamp: f32, + format: wgpu_types::TextureFormat, + depth_write_enabled: bool, + depth_compare: wgpu_types::CompareFunction, + stencil_front: wgpu_types::StencilFaceState, + stencil_back: wgpu_types::StencilFaceState, + stencil_read_mask: u32, + stencil_write_mask: u32, + depth_bias: i32, + depth_bias_slope_scale: f32, + depth_bias_clamp: f32, } impl TryFrom for wgpu_types::DepthStencilState { - type Error = AnyError; - fn try_from(state: GpuDepthStencilState) -> Result { - Ok(wgpu_types::DepthStencilState { - format: state.format, - depth_write_enabled: state.depth_write_enabled, - depth_compare: state.depth_compare.into(), - stencil: wgpu_types::StencilState { - front: state.stencil_front.into(), - back: state.stencil_back.into(), - read_mask: state.stencil_read_mask, - write_mask: state.stencil_write_mask, - }, - bias: wgpu_types::DepthBiasState { - constant: state.depth_bias, - slope_scale: state.depth_bias_slope_scale, - clamp: state.depth_bias_clamp, - }, - }) - } + type Error = AnyError; + fn try_from( + state: GpuDepthStencilState, + ) -> Result { + Ok(wgpu_types::DepthStencilState { + format: state.format, + depth_write_enabled: state.depth_write_enabled, + depth_compare: state.depth_compare.into(), + stencil: wgpu_types::StencilState { + front: state.stencil_front.into(), + back: state.stencil_back.into(), + read_mask: state.stencil_read_mask, + write_mask: state.stencil_write_mask, + }, + bias: wgpu_types::DepthBiasState { + constant: state.depth_bias, + slope_scale: state.depth_bias_slope_scale, + clamp: state.depth_bias_clamp, + }, + }) + } } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct GpuVertexBufferLayout { - array_stride: u64, - step_mode: wgpu_types::VertexStepMode, - attributes: Vec, + array_stride: u64, + step_mode: wgpu_types::VertexStepMode, + attributes: Vec, } -impl<'a> From for wgpu_core::pipeline::VertexBufferLayout<'a> { - fn from(layout: GpuVertexBufferLayout) -> wgpu_core::pipeline::VertexBufferLayout<'a> { - wgpu_core::pipeline::VertexBufferLayout { - array_stride: layout.array_stride, - step_mode: layout.step_mode, - attributes: Cow::Owned(layout.attributes), - } +impl<'a> From + for wgpu_core::pipeline::VertexBufferLayout<'a> +{ + fn from( + layout: GpuVertexBufferLayout, + ) -> wgpu_core::pipeline::VertexBufferLayout<'a> { + wgpu_core::pipeline::VertexBufferLayout { + array_stride: layout.array_stride, + step_mode: layout.step_mode, + attributes: Cow::Owned(layout.attributes), } + } } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct GpuVertexState { - module: ResourceId, - entry_point: String, - buffers: Vec>, + module: ResourceId, + entry_point: String, + buffers: Vec>, } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct GpuMultisampleState { - count: u32, - mask: u64, - alpha_to_coverage_enabled: bool, + count: u32, + mask: u64, + alpha_to_coverage_enabled: bool, } impl From for wgpu_types::MultisampleState { - fn from(gms: GpuMultisampleState) -> wgpu_types::MultisampleState { - wgpu_types::MultisampleState { - count: gms.count, - mask: gms.mask, - alpha_to_coverage_enabled: gms.alpha_to_coverage_enabled, - } + fn from(gms: GpuMultisampleState) -> wgpu_types::MultisampleState { + wgpu_types::MultisampleState { + count: gms.count, + mask: gms.mask, + alpha_to_coverage_enabled: gms.alpha_to_coverage_enabled, } + } } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct GpuFragmentState { - targets: Vec, - module: u32, - entry_point: String, - // TODO(lucacasonato): constants + targets: Vec, + module: u32, + entry_point: String, + // TODO(lucacasonato): constants } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct CreateRenderPipelineArgs { - device_rid: ResourceId, - label: Option, - layout: Option, - vertex: GpuVertexState, - primitive: GpuPrimitiveState, - depth_stencil: Option, - multisample: wgpu_types::MultisampleState, - fragment: Option, + device_rid: ResourceId, + label: Option, + layout: Option, + vertex: GpuVertexState, + primitive: GpuPrimitiveState, + depth_stencil: Option, + multisample: wgpu_types::MultisampleState, + fragment: Option, } pub fn op_webgpu_create_render_pipeline( - state: &mut OpState, - args: CreateRenderPipelineArgs, - _: (), + state: &mut OpState, + args: CreateRenderPipelineArgs, + _: (), ) -> Result { - let instance = state.borrow::(); - let device_resource = state + let instance = state.borrow::(); + let device_resource = state + .resource_table + .get::(args.device_rid)?; + let device = device_resource.0; + + let layout = if let Some(rid) = args.layout { + let pipeline_layout_resource = + state.resource_table.get::(rid)?; + Some(pipeline_layout_resource.0) + } else { + None + }; + + let vertex_shader_module_resource = + state + .resource_table + .get::(args.vertex.module)?; + + let fragment = if let Some(fragment) = args.fragment { + let fragment_shader_module_resource = + state .resource_table - .get::(args.device_rid)?; - let device = device_resource.0; + .get::(fragment.module)?; - let layout = if let Some(rid) = args.layout { - let pipeline_layout_resource = state.resource_table.get::(rid)?; - Some(pipeline_layout_resource.0) - } else { - None - }; + let mut targets = Vec::with_capacity(fragment.targets.len()); - let vertex_shader_module_resource = state - .resource_table - .get::(args.vertex.module)?; - - let fragment = if let Some(fragment) = args.fragment { - let fragment_shader_module_resource = - state - .resource_table - .get::(fragment.module)?; - - let mut targets = Vec::with_capacity(fragment.targets.len()); - - for target in fragment.targets { - targets.push(target.try_into()?); - } - - Some(wgpu_core::pipeline::FragmentState { - stage: wgpu_core::pipeline::ProgrammableStageDescriptor { - module: fragment_shader_module_resource.0, - entry_point: Cow::from(fragment.entry_point), - }, - targets: Cow::from(targets), - }) - } else { - None - }; - - let vertex_buffers = args - .vertex - .buffers - .into_iter() - .flatten() - .map(Into::into) - .collect(); - - let descriptor = wgpu_core::pipeline::RenderPipelineDescriptor { - label: args.label.map(Cow::Owned), - layout, - vertex: wgpu_core::pipeline::VertexState { - stage: wgpu_core::pipeline::ProgrammableStageDescriptor { - module: vertex_shader_module_resource.0, - entry_point: Cow::Owned(args.vertex.entry_point), - }, - buffers: Cow::Owned(vertex_buffers), - }, - primitive: args.primitive.into(), - depth_stencil: args.depth_stencil.map(TryInto::try_into).transpose()?, - multisample: args.multisample.into(), - fragment, - multiview: None, - }; - - let implicit_pipelines = match args.layout { - Some(_) => None, - None => Some(wgpu_core::device::ImplicitPipelineIds { - root_id: std::marker::PhantomData, - group_ids: &[std::marker::PhantomData; MAX_BIND_GROUPS], - }), - }; - - let (render_pipeline, maybe_err) = gfx_select!(device => instance.device_create_render_pipeline( - device, - &descriptor, - std::marker::PhantomData, - implicit_pipelines - )); - - let rid = state - .resource_table - .add(WebGpuRenderPipeline(render_pipeline)); + for target in fragment.targets { + targets.push(target.try_into()?); + } - Ok(WebGpuResult::rid_err(rid, maybe_err)) + Some(wgpu_core::pipeline::FragmentState { + stage: wgpu_core::pipeline::ProgrammableStageDescriptor { + module: fragment_shader_module_resource.0, + entry_point: Cow::from(fragment.entry_point), + }, + targets: Cow::from(targets), + }) + } else { + None + }; + + let vertex_buffers = args + .vertex + .buffers + .into_iter() + .flatten() + .map(Into::into) + .collect(); + + let descriptor = wgpu_core::pipeline::RenderPipelineDescriptor { + label: args.label.map(Cow::Owned), + layout, + vertex: wgpu_core::pipeline::VertexState { + stage: wgpu_core::pipeline::ProgrammableStageDescriptor { + module: vertex_shader_module_resource.0, + entry_point: Cow::Owned(args.vertex.entry_point), + }, + buffers: Cow::Owned(vertex_buffers), + }, + primitive: args.primitive.into(), + depth_stencil: args.depth_stencil.map(TryInto::try_into).transpose()?, + multisample: args.multisample.into(), + fragment, + multiview: None, + }; + + let implicit_pipelines = match args.layout { + Some(_) => None, + None => Some(wgpu_core::device::ImplicitPipelineIds { + root_id: std::marker::PhantomData, + group_ids: &[std::marker::PhantomData; MAX_BIND_GROUPS], + }), + }; + + let (render_pipeline, maybe_err) = gfx_select!(device => instance.device_create_render_pipeline( + device, + &descriptor, + std::marker::PhantomData, + implicit_pipelines + )); + + let rid = state + .resource_table + .add(WebGpuRenderPipeline(render_pipeline)); + + Ok(WebGpuResult::rid_err(rid, maybe_err)) } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct RenderPipelineGetBindGroupLayoutArgs { - render_pipeline_rid: ResourceId, - index: u32, + render_pipeline_rid: ResourceId, + index: u32, } pub fn op_webgpu_render_pipeline_get_bind_group_layout( - state: &mut OpState, - args: RenderPipelineGetBindGroupLayoutArgs, - _: (), + state: &mut OpState, + args: RenderPipelineGetBindGroupLayoutArgs, + _: (), ) -> Result { - let instance = state.borrow::(); - let render_pipeline_resource = state - .resource_table - .get::(args.render_pipeline_rid)?; - let render_pipeline = render_pipeline_resource.0; + let instance = state.borrow::(); + let render_pipeline_resource = state + .resource_table + .get::(args.render_pipeline_rid)?; + let render_pipeline = render_pipeline_resource.0; - let (bind_group_layout, maybe_err) = gfx_select!(render_pipeline => instance.render_pipeline_get_bind_group_layout(render_pipeline, args.index, std::marker::PhantomData)); + let (bind_group_layout, maybe_err) = gfx_select!(render_pipeline => instance.render_pipeline_get_bind_group_layout(render_pipeline, args.index, std::marker::PhantomData)); - let label = - gfx_select!(bind_group_layout => instance.bind_group_layout_label(bind_group_layout)); + let label = gfx_select!(bind_group_layout => instance.bind_group_layout_label(bind_group_layout)); - let rid = state - .resource_table - .add(super::binding::WebGpuBindGroupLayout(bind_group_layout)); + let rid = state + .resource_table + .add(super::binding::WebGpuBindGroupLayout(bind_group_layout)); - Ok(PipelineLayout { - rid, - label, - err: maybe_err.map(WebGpuError::from), - }) + Ok(PipelineLayout { + rid, + label, + err: maybe_err.map(WebGpuError::from), + }) } diff --git a/ext/webgpu/src/queue.rs b/ext/webgpu/src/queue.rs index c46f511b2d83a3..2668af9fae8e1c 100644 --- a/ext/webgpu/src/queue.rs +++ b/ext/webgpu/src/queue.rs @@ -15,123 +15,128 @@ type WebGpuQueue = super::WebGpuDevice; #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct QueueSubmitArgs { - queue_rid: ResourceId, - command_buffers: Vec, + queue_rid: ResourceId, + command_buffers: Vec, } pub fn op_webgpu_queue_submit( - state: &mut OpState, - args: QueueSubmitArgs, - _: (), + state: &mut OpState, + args: QueueSubmitArgs, + _: (), ) -> Result { - let instance = state.borrow::(); - let queue_resource = state.resource_table.get::(args.queue_rid)?; - let queue = queue_resource.0; + let instance = state.borrow::(); + let queue_resource = + state.resource_table.get::(args.queue_rid)?; + let queue = queue_resource.0; - let mut ids = vec![]; + let mut ids = vec![]; - for rid in args.command_buffers { - let buffer_resource = state - .resource_table - .get::(rid)?; - ids.push(buffer_resource.0); - } + for rid in args.command_buffers { + let buffer_resource = + state + .resource_table + .get::(rid)?; + ids.push(buffer_resource.0); + } - let maybe_err = gfx_select!(queue => instance.queue_submit(queue, &ids)).err(); + let maybe_err = + gfx_select!(queue => instance.queue_submit(queue, &ids)).err(); - Ok(WebGpuResult::maybe_err(maybe_err)) + Ok(WebGpuResult::maybe_err(maybe_err)) } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct GpuImageDataLayout { - offset: u64, - bytes_per_row: Option, - rows_per_image: Option, + offset: u64, + bytes_per_row: Option, + rows_per_image: Option, } impl From for wgpu_types::ImageDataLayout { - fn from(layout: GpuImageDataLayout) -> Self { - wgpu_types::ImageDataLayout { - offset: layout.offset, - bytes_per_row: NonZeroU32::new(layout.bytes_per_row.unwrap_or(0)), - rows_per_image: NonZeroU32::new(layout.rows_per_image.unwrap_or(0)), - } + fn from(layout: GpuImageDataLayout) -> Self { + wgpu_types::ImageDataLayout { + offset: layout.offset, + bytes_per_row: NonZeroU32::new(layout.bytes_per_row.unwrap_or(0)), + rows_per_image: NonZeroU32::new(layout.rows_per_image.unwrap_or(0)), } + } } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct QueueWriteBufferArgs { - queue_rid: ResourceId, - buffer: ResourceId, - buffer_offset: u64, - data_offset: usize, - size: Option, + queue_rid: ResourceId, + buffer: ResourceId, + buffer_offset: u64, + data_offset: usize, + size: Option, } pub fn op_webgpu_write_buffer( - state: &mut OpState, - args: QueueWriteBufferArgs, - zero_copy: ZeroCopyBuf, + state: &mut OpState, + args: QueueWriteBufferArgs, + zero_copy: ZeroCopyBuf, ) -> Result { - let instance = state.borrow::(); - let buffer_resource = state - .resource_table - .get::(args.buffer)?; - let buffer = buffer_resource.0; - let queue_resource = state.resource_table.get::(args.queue_rid)?; - let queue = queue_resource.0; - - let data = match args.size { - Some(size) => &zero_copy[args.data_offset..(args.data_offset + size)], - None => &zero_copy[args.data_offset..], - }; - let maybe_err = gfx_select!(queue => instance.queue_write_buffer( - queue, - buffer, - args.buffer_offset, - data - )) - .err(); - - Ok(WebGpuResult::maybe_err(maybe_err)) + let instance = state.borrow::(); + let buffer_resource = state + .resource_table + .get::(args.buffer)?; + let buffer = buffer_resource.0; + let queue_resource = + state.resource_table.get::(args.queue_rid)?; + let queue = queue_resource.0; + + let data = match args.size { + Some(size) => &zero_copy[args.data_offset..(args.data_offset + size)], + None => &zero_copy[args.data_offset..], + }; + let maybe_err = gfx_select!(queue => instance.queue_write_buffer( + queue, + buffer, + args.buffer_offset, + data + )) + .err(); + + Ok(WebGpuResult::maybe_err(maybe_err)) } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct QueueWriteTextureArgs { - queue_rid: ResourceId, - destination: super::command_encoder::GpuImageCopyTexture, - data_layout: GpuImageDataLayout, - size: wgpu_types::Extent3d, + queue_rid: ResourceId, + destination: super::command_encoder::GpuImageCopyTexture, + data_layout: GpuImageDataLayout, + size: wgpu_types::Extent3d, } pub fn op_webgpu_write_texture( - state: &mut OpState, - args: QueueWriteTextureArgs, - zero_copy: ZeroCopyBuf, + state: &mut OpState, + args: QueueWriteTextureArgs, + zero_copy: ZeroCopyBuf, ) -> Result { - let instance = state.borrow::(); - let texture_resource = state - .resource_table - .get::(args.destination.texture)?; - let queue_resource = state.resource_table.get::(args.queue_rid)?; - let queue = queue_resource.0; - - let destination = wgpu_core::command::ImageCopyTexture { - texture: texture_resource.0, - mip_level: args.destination.mip_level, - origin: args.destination.origin, - aspect: args.destination.aspect, - }; - let data_layout = args.data_layout.into(); - - gfx_ok!(queue => instance.queue_write_texture( - queue, - &destination, - &*zero_copy, - &data_layout, - &args.size - )) + let instance = state.borrow::(); + let texture_resource = state + .resource_table + .get::(args.destination.texture)?; + let queue_resource = + state.resource_table.get::(args.queue_rid)?; + let queue = queue_resource.0; + + let destination = wgpu_core::command::ImageCopyTexture { + texture: texture_resource.0, + mip_level: args.destination.mip_level, + origin: args.destination.origin, + aspect: args.destination.aspect, + }; + let data_layout = args.data_layout.into(); + + gfx_ok!(queue => instance.queue_write_texture( + queue, + &destination, + &*zero_copy, + &data_layout, + &args.size + )) } diff --git a/ext/webgpu/src/render_pass.rs b/ext/webgpu/src/render_pass.rs index 83a5ff0d0e515d..5883e154c70ef9 100644 --- a/ext/webgpu/src/render_pass.rs +++ b/ext/webgpu/src/render_pass.rs @@ -11,633 +11,639 @@ use std::cell::RefCell; use super::error::WebGpuResult; -pub(crate) struct WebGpuRenderPass(pub(crate) RefCell); +pub(crate) struct WebGpuRenderPass( + pub(crate) RefCell, +); impl Resource for WebGpuRenderPass { - fn name(&self) -> Cow { - "webGPURenderPass".into() - } + fn name(&self) -> Cow { + "webGPURenderPass".into() + } } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct RenderPassSetViewportArgs { - render_pass_rid: ResourceId, - x: f32, - y: f32, - width: f32, - height: f32, - min_depth: f32, - max_depth: f32, + render_pass_rid: ResourceId, + x: f32, + y: f32, + width: f32, + height: f32, + min_depth: f32, + max_depth: f32, } pub fn op_webgpu_render_pass_set_viewport( - state: &mut OpState, - args: RenderPassSetViewportArgs, - _: (), + state: &mut OpState, + args: RenderPassSetViewportArgs, + _: (), ) -> Result { - let render_pass_resource = state - .resource_table - .get::(args.render_pass_rid)?; + let render_pass_resource = state + .resource_table + .get::(args.render_pass_rid)?; - wgpu_core::command::render_ffi::wgpu_render_pass_set_viewport( - &mut render_pass_resource.0.borrow_mut(), - args.x, - args.y, - args.width, - args.height, - args.min_depth, - args.max_depth, - ); + wgpu_core::command::render_ffi::wgpu_render_pass_set_viewport( + &mut render_pass_resource.0.borrow_mut(), + args.x, + args.y, + args.width, + args.height, + args.min_depth, + args.max_depth, + ); - Ok(WebGpuResult::empty()) + Ok(WebGpuResult::empty()) } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct RenderPassSetScissorRectArgs { - render_pass_rid: ResourceId, - x: u32, - y: u32, - width: u32, - height: u32, + render_pass_rid: ResourceId, + x: u32, + y: u32, + width: u32, + height: u32, } pub fn op_webgpu_render_pass_set_scissor_rect( - state: &mut OpState, - args: RenderPassSetScissorRectArgs, - _: (), + state: &mut OpState, + args: RenderPassSetScissorRectArgs, + _: (), ) -> Result { - let render_pass_resource = state - .resource_table - .get::(args.render_pass_rid)?; + let render_pass_resource = state + .resource_table + .get::(args.render_pass_rid)?; - wgpu_core::command::render_ffi::wgpu_render_pass_set_scissor_rect( - &mut render_pass_resource.0.borrow_mut(), - args.x, - args.y, - args.width, - args.height, - ); + wgpu_core::command::render_ffi::wgpu_render_pass_set_scissor_rect( + &mut render_pass_resource.0.borrow_mut(), + args.x, + args.y, + args.width, + args.height, + ); - Ok(WebGpuResult::empty()) + Ok(WebGpuResult::empty()) } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct RenderPassSetBlendConstantArgs { - render_pass_rid: ResourceId, - color: wgpu_types::Color, + render_pass_rid: ResourceId, + color: wgpu_types::Color, } pub fn op_webgpu_render_pass_set_blend_constant( - state: &mut OpState, - args: RenderPassSetBlendConstantArgs, - _: (), + state: &mut OpState, + args: RenderPassSetBlendConstantArgs, + _: (), ) -> Result { - let render_pass_resource = state - .resource_table - .get::(args.render_pass_rid)?; + let render_pass_resource = state + .resource_table + .get::(args.render_pass_rid)?; - wgpu_core::command::render_ffi::wgpu_render_pass_set_blend_constant( - &mut render_pass_resource.0.borrow_mut(), - &args.color, - ); + wgpu_core::command::render_ffi::wgpu_render_pass_set_blend_constant( + &mut render_pass_resource.0.borrow_mut(), + &args.color, + ); - Ok(WebGpuResult::empty()) + Ok(WebGpuResult::empty()) } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct RenderPassSetStencilReferenceArgs { - render_pass_rid: ResourceId, - reference: u32, + render_pass_rid: ResourceId, + reference: u32, } pub fn op_webgpu_render_pass_set_stencil_reference( - state: &mut OpState, - args: RenderPassSetStencilReferenceArgs, - _: (), + state: &mut OpState, + args: RenderPassSetStencilReferenceArgs, + _: (), ) -> Result { - let render_pass_resource = state - .resource_table - .get::(args.render_pass_rid)?; + let render_pass_resource = state + .resource_table + .get::(args.render_pass_rid)?; - wgpu_core::command::render_ffi::wgpu_render_pass_set_stencil_reference( - &mut render_pass_resource.0.borrow_mut(), - args.reference, - ); + wgpu_core::command::render_ffi::wgpu_render_pass_set_stencil_reference( + &mut render_pass_resource.0.borrow_mut(), + args.reference, + ); - Ok(WebGpuResult::empty()) + Ok(WebGpuResult::empty()) } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct RenderPassBeginPipelineStatisticsQueryArgs { - render_pass_rid: ResourceId, - query_set: u32, - query_index: u32, + render_pass_rid: ResourceId, + query_set: u32, + query_index: u32, } pub fn op_webgpu_render_pass_begin_pipeline_statistics_query( - state: &mut OpState, - args: RenderPassBeginPipelineStatisticsQueryArgs, - _: (), + state: &mut OpState, + args: RenderPassBeginPipelineStatisticsQueryArgs, + _: (), ) -> Result { - let render_pass_resource = state - .resource_table - .get::(args.render_pass_rid)?; - let query_set_resource = state - .resource_table - .get::(args.query_set)?; - - wgpu_core::command::render_ffi::wgpu_render_pass_begin_pipeline_statistics_query( + let render_pass_resource = state + .resource_table + .get::(args.render_pass_rid)?; + let query_set_resource = state + .resource_table + .get::(args.query_set)?; + + wgpu_core::command::render_ffi::wgpu_render_pass_begin_pipeline_statistics_query( &mut render_pass_resource.0.borrow_mut(), query_set_resource.0, args.query_index, ); - Ok(WebGpuResult::empty()) + Ok(WebGpuResult::empty()) } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct RenderPassEndPipelineStatisticsQueryArgs { - render_pass_rid: ResourceId, + render_pass_rid: ResourceId, } pub fn op_webgpu_render_pass_end_pipeline_statistics_query( - state: &mut OpState, - args: RenderPassEndPipelineStatisticsQueryArgs, - _: (), + state: &mut OpState, + args: RenderPassEndPipelineStatisticsQueryArgs, + _: (), ) -> Result { - let render_pass_resource = state - .resource_table - .get::(args.render_pass_rid)?; + let render_pass_resource = state + .resource_table + .get::(args.render_pass_rid)?; - wgpu_core::command::render_ffi::wgpu_render_pass_end_pipeline_statistics_query( + wgpu_core::command::render_ffi::wgpu_render_pass_end_pipeline_statistics_query( &mut render_pass_resource.0.borrow_mut(), ); - Ok(WebGpuResult::empty()) + Ok(WebGpuResult::empty()) } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct RenderPassWriteTimestampArgs { - render_pass_rid: ResourceId, - query_set: u32, - query_index: u32, + render_pass_rid: ResourceId, + query_set: u32, + query_index: u32, } pub fn op_webgpu_render_pass_write_timestamp( - state: &mut OpState, - args: RenderPassWriteTimestampArgs, - _: (), + state: &mut OpState, + args: RenderPassWriteTimestampArgs, + _: (), ) -> Result { - let render_pass_resource = state - .resource_table - .get::(args.render_pass_rid)?; - let query_set_resource = state - .resource_table - .get::(args.query_set)?; + let render_pass_resource = state + .resource_table + .get::(args.render_pass_rid)?; + let query_set_resource = state + .resource_table + .get::(args.query_set)?; - wgpu_core::command::render_ffi::wgpu_render_pass_write_timestamp( - &mut render_pass_resource.0.borrow_mut(), - query_set_resource.0, - args.query_index, - ); + wgpu_core::command::render_ffi::wgpu_render_pass_write_timestamp( + &mut render_pass_resource.0.borrow_mut(), + query_set_resource.0, + args.query_index, + ); - Ok(WebGpuResult::empty()) + Ok(WebGpuResult::empty()) } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct RenderPassExecuteBundlesArgs { - render_pass_rid: ResourceId, - bundles: Vec, + render_pass_rid: ResourceId, + bundles: Vec, } pub fn op_webgpu_render_pass_execute_bundles( - state: &mut OpState, - args: RenderPassExecuteBundlesArgs, - _: (), + state: &mut OpState, + args: RenderPassExecuteBundlesArgs, + _: (), ) -> Result { - let mut render_bundle_ids = vec![]; - - for rid in &args.bundles { - let render_bundle_resource = state - .resource_table - .get::(*rid)?; - render_bundle_ids.push(render_bundle_resource.0); - } + let mut render_bundle_ids = vec![]; - let render_pass_resource = state + for rid in &args.bundles { + let render_bundle_resource = + state .resource_table - .get::(args.render_pass_rid)?; - - // SAFETY: the raw pointer and length are of the same slice, and that slice - // lives longer than the below function invocation. - unsafe { - wgpu_core::command::render_ffi::wgpu_render_pass_execute_bundles( - &mut render_pass_resource.0.borrow_mut(), - render_bundle_ids.as_ptr(), - render_bundle_ids.len(), - ); - } + .get::(*rid)?; + render_bundle_ids.push(render_bundle_resource.0); + } + + let render_pass_resource = state + .resource_table + .get::(args.render_pass_rid)?; + + // SAFETY: the raw pointer and length are of the same slice, and that slice + // lives longer than the below function invocation. + unsafe { + wgpu_core::command::render_ffi::wgpu_render_pass_execute_bundles( + &mut render_pass_resource.0.borrow_mut(), + render_bundle_ids.as_ptr(), + render_bundle_ids.len(), + ); + } - Ok(WebGpuResult::empty()) + Ok(WebGpuResult::empty()) } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct RenderPassEndPassArgs { - command_encoder_rid: ResourceId, - render_pass_rid: ResourceId, + command_encoder_rid: ResourceId, + render_pass_rid: ResourceId, } pub fn op_webgpu_render_pass_end_pass( - state: &mut OpState, - args: RenderPassEndPassArgs, - _: (), + state: &mut OpState, + args: RenderPassEndPassArgs, + _: (), ) -> Result { - let command_encoder_resource = - state - .resource_table - .get::(args.command_encoder_rid)?; - let command_encoder = command_encoder_resource.0; - let render_pass_resource = state - .resource_table - .take::(args.render_pass_rid)?; - let render_pass = &render_pass_resource.0.borrow(); - let instance = state.borrow::(); + let command_encoder_resource = state + .resource_table + .get::( + args.command_encoder_rid, + )?; + let command_encoder = command_encoder_resource.0; + let render_pass_resource = state + .resource_table + .take::(args.render_pass_rid)?; + let render_pass = &render_pass_resource.0.borrow(); + let instance = state.borrow::(); - gfx_ok!(command_encoder => instance.command_encoder_run_render_pass(command_encoder, render_pass)) + gfx_ok!(command_encoder => instance.command_encoder_run_render_pass(command_encoder, render_pass)) } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct RenderPassSetBindGroupArgs { - render_pass_rid: ResourceId, - index: u32, - bind_group: u32, - dynamic_offsets_data: ZeroCopyBuf, - dynamic_offsets_data_start: usize, - dynamic_offsets_data_length: usize, + render_pass_rid: ResourceId, + index: u32, + bind_group: u32, + dynamic_offsets_data: ZeroCopyBuf, + dynamic_offsets_data_start: usize, + dynamic_offsets_data_length: usize, } pub fn op_webgpu_render_pass_set_bind_group( - state: &mut OpState, - args: RenderPassSetBindGroupArgs, - _: (), + state: &mut OpState, + args: RenderPassSetBindGroupArgs, + _: (), ) -> Result { - let bind_group_resource = state - .resource_table - .get::(args.bind_group)?; - let render_pass_resource = state - .resource_table - .get::(args.render_pass_rid)?; - - // Align the data - assert!(args.dynamic_offsets_data_start % std::mem::size_of::() == 0); - // SAFETY: A u8 to u32 cast is safe because we asserted that the length is a - // multiple of 4. - let (prefix, dynamic_offsets_data, suffix) = - unsafe { args.dynamic_offsets_data.align_to::() }; - assert!(prefix.is_empty()); - assert!(suffix.is_empty()); - - let start = args.dynamic_offsets_data_start; - let len = args.dynamic_offsets_data_length; - - // Assert that length and start are both in bounds - assert!(start <= dynamic_offsets_data.len()); - assert!(len <= dynamic_offsets_data.len() - start); - - let dynamic_offsets_data: &[u32] = &dynamic_offsets_data[start..start + len]; - - // SAFETY: the raw pointer and length are of the same slice, and that slice - // lives longer than the below function invocation. - unsafe { - wgpu_core::command::render_ffi::wgpu_render_pass_set_bind_group( - &mut render_pass_resource.0.borrow_mut(), - args.index, - bind_group_resource.0, - dynamic_offsets_data.as_ptr(), - dynamic_offsets_data.len(), - ); - } + let bind_group_resource = + state + .resource_table + .get::(args.bind_group)?; + let render_pass_resource = state + .resource_table + .get::(args.render_pass_rid)?; + + // Align the data + assert!(args.dynamic_offsets_data_start % std::mem::size_of::() == 0); + // SAFETY: A u8 to u32 cast is safe because we asserted that the length is a + // multiple of 4. + let (prefix, dynamic_offsets_data, suffix) = + unsafe { args.dynamic_offsets_data.align_to::() }; + assert!(prefix.is_empty()); + assert!(suffix.is_empty()); + + let start = args.dynamic_offsets_data_start; + let len = args.dynamic_offsets_data_length; + + // Assert that length and start are both in bounds + assert!(start <= dynamic_offsets_data.len()); + assert!(len <= dynamic_offsets_data.len() - start); + + let dynamic_offsets_data: &[u32] = &dynamic_offsets_data[start..start + len]; + + // SAFETY: the raw pointer and length are of the same slice, and that slice + // lives longer than the below function invocation. + unsafe { + wgpu_core::command::render_ffi::wgpu_render_pass_set_bind_group( + &mut render_pass_resource.0.borrow_mut(), + args.index, + bind_group_resource.0, + dynamic_offsets_data.as_ptr(), + dynamic_offsets_data.len(), + ); + } - Ok(WebGpuResult::empty()) + Ok(WebGpuResult::empty()) } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct RenderPassPushDebugGroupArgs { - render_pass_rid: ResourceId, - group_label: String, + render_pass_rid: ResourceId, + group_label: String, } pub fn op_webgpu_render_pass_push_debug_group( - state: &mut OpState, - args: RenderPassPushDebugGroupArgs, - _: (), + state: &mut OpState, + args: RenderPassPushDebugGroupArgs, + _: (), ) -> Result { - let render_pass_resource = state - .resource_table - .get::(args.render_pass_rid)?; - - let label = std::ffi::CString::new(args.group_label).unwrap(); - // SAFETY: the string the raw pointer points to lives longer than the below - // function invocation. - unsafe { - wgpu_core::command::render_ffi::wgpu_render_pass_push_debug_group( - &mut render_pass_resource.0.borrow_mut(), - label.as_ptr(), - 0, // wgpu#975 - ); - } + let render_pass_resource = state + .resource_table + .get::(args.render_pass_rid)?; + + let label = std::ffi::CString::new(args.group_label).unwrap(); + // SAFETY: the string the raw pointer points to lives longer than the below + // function invocation. + unsafe { + wgpu_core::command::render_ffi::wgpu_render_pass_push_debug_group( + &mut render_pass_resource.0.borrow_mut(), + label.as_ptr(), + 0, // wgpu#975 + ); + } - Ok(WebGpuResult::empty()) + Ok(WebGpuResult::empty()) } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct RenderPassPopDebugGroupArgs { - render_pass_rid: ResourceId, + render_pass_rid: ResourceId, } pub fn op_webgpu_render_pass_pop_debug_group( - state: &mut OpState, - args: RenderPassPopDebugGroupArgs, - _: (), + state: &mut OpState, + args: RenderPassPopDebugGroupArgs, + _: (), ) -> Result { - let render_pass_resource = state - .resource_table - .get::(args.render_pass_rid)?; + let render_pass_resource = state + .resource_table + .get::(args.render_pass_rid)?; - wgpu_core::command::render_ffi::wgpu_render_pass_pop_debug_group( - &mut render_pass_resource.0.borrow_mut(), - ); + wgpu_core::command::render_ffi::wgpu_render_pass_pop_debug_group( + &mut render_pass_resource.0.borrow_mut(), + ); - Ok(WebGpuResult::empty()) + Ok(WebGpuResult::empty()) } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct RenderPassInsertDebugMarkerArgs { - render_pass_rid: ResourceId, - marker_label: String, + render_pass_rid: ResourceId, + marker_label: String, } pub fn op_webgpu_render_pass_insert_debug_marker( - state: &mut OpState, - args: RenderPassInsertDebugMarkerArgs, - _: (), + state: &mut OpState, + args: RenderPassInsertDebugMarkerArgs, + _: (), ) -> Result { - let render_pass_resource = state - .resource_table - .get::(args.render_pass_rid)?; - - let label = std::ffi::CString::new(args.marker_label).unwrap(); - // SAFETY: the string the raw pointer points to lives longer than the below - // function invocation. - unsafe { - wgpu_core::command::render_ffi::wgpu_render_pass_insert_debug_marker( - &mut render_pass_resource.0.borrow_mut(), - label.as_ptr(), - 0, // wgpu#975 - ); - } + let render_pass_resource = state + .resource_table + .get::(args.render_pass_rid)?; + + let label = std::ffi::CString::new(args.marker_label).unwrap(); + // SAFETY: the string the raw pointer points to lives longer than the below + // function invocation. + unsafe { + wgpu_core::command::render_ffi::wgpu_render_pass_insert_debug_marker( + &mut render_pass_resource.0.borrow_mut(), + label.as_ptr(), + 0, // wgpu#975 + ); + } - Ok(WebGpuResult::empty()) + Ok(WebGpuResult::empty()) } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct RenderPassSetPipelineArgs { - render_pass_rid: ResourceId, - pipeline: u32, + render_pass_rid: ResourceId, + pipeline: u32, } pub fn op_webgpu_render_pass_set_pipeline( - state: &mut OpState, - args: RenderPassSetPipelineArgs, - _: (), + state: &mut OpState, + args: RenderPassSetPipelineArgs, + _: (), ) -> Result { - let render_pipeline_resource = state - .resource_table - .get::(args.pipeline)?; - let render_pass_resource = state - .resource_table - .get::(args.render_pass_rid)?; + let render_pipeline_resource = + state + .resource_table + .get::(args.pipeline)?; + let render_pass_resource = state + .resource_table + .get::(args.render_pass_rid)?; - wgpu_core::command::render_ffi::wgpu_render_pass_set_pipeline( - &mut render_pass_resource.0.borrow_mut(), - render_pipeline_resource.0, - ); + wgpu_core::command::render_ffi::wgpu_render_pass_set_pipeline( + &mut render_pass_resource.0.borrow_mut(), + render_pipeline_resource.0, + ); - Ok(WebGpuResult::empty()) + Ok(WebGpuResult::empty()) } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct RenderPassSetIndexBufferArgs { - render_pass_rid: ResourceId, - buffer: u32, - index_format: wgpu_types::IndexFormat, - offset: u64, - size: Option, + render_pass_rid: ResourceId, + buffer: u32, + index_format: wgpu_types::IndexFormat, + offset: u64, + size: Option, } pub fn op_webgpu_render_pass_set_index_buffer( - state: &mut OpState, - args: RenderPassSetIndexBufferArgs, - _: (), + state: &mut OpState, + args: RenderPassSetIndexBufferArgs, + _: (), ) -> Result { - let buffer_resource = state - .resource_table - .get::(args.buffer)?; - let render_pass_resource = state - .resource_table - .get::(args.render_pass_rid)?; - - let size = if let Some(size) = args.size { - Some( - std::num::NonZeroU64::new(size) - .ok_or_else(|| type_error("size must be larger than 0"))?, - ) - } else { - None - }; - - render_pass_resource.0.borrow_mut().set_index_buffer( - buffer_resource.0, - args.index_format, - args.offset, - size, - ); - - Ok(WebGpuResult::empty()) + let buffer_resource = state + .resource_table + .get::(args.buffer)?; + let render_pass_resource = state + .resource_table + .get::(args.render_pass_rid)?; + + let size = if let Some(size) = args.size { + Some( + std::num::NonZeroU64::new(size) + .ok_or_else(|| type_error("size must be larger than 0"))?, + ) + } else { + None + }; + + render_pass_resource.0.borrow_mut().set_index_buffer( + buffer_resource.0, + args.index_format, + args.offset, + size, + ); + + Ok(WebGpuResult::empty()) } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct RenderPassSetVertexBufferArgs { - render_pass_rid: ResourceId, - slot: u32, - buffer: u32, - offset: u64, - size: Option, + render_pass_rid: ResourceId, + slot: u32, + buffer: u32, + offset: u64, + size: Option, } pub fn op_webgpu_render_pass_set_vertex_buffer( - state: &mut OpState, - args: RenderPassSetVertexBufferArgs, - _: (), + state: &mut OpState, + args: RenderPassSetVertexBufferArgs, + _: (), ) -> Result { - let buffer_resource = state - .resource_table - .get::(args.buffer)?; - let render_pass_resource = state - .resource_table - .get::(args.render_pass_rid)?; - - let size = if let Some(size) = args.size { - Some( - std::num::NonZeroU64::new(size) - .ok_or_else(|| type_error("size must be larger than 0"))?, - ) - } else { - None - }; - - wgpu_core::command::render_ffi::wgpu_render_pass_set_vertex_buffer( - &mut render_pass_resource.0.borrow_mut(), - args.slot, - buffer_resource.0, - args.offset, - size, - ); - - Ok(WebGpuResult::empty()) + let buffer_resource = state + .resource_table + .get::(args.buffer)?; + let render_pass_resource = state + .resource_table + .get::(args.render_pass_rid)?; + + let size = if let Some(size) = args.size { + Some( + std::num::NonZeroU64::new(size) + .ok_or_else(|| type_error("size must be larger than 0"))?, + ) + } else { + None + }; + + wgpu_core::command::render_ffi::wgpu_render_pass_set_vertex_buffer( + &mut render_pass_resource.0.borrow_mut(), + args.slot, + buffer_resource.0, + args.offset, + size, + ); + + Ok(WebGpuResult::empty()) } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct RenderPassDrawArgs { - render_pass_rid: ResourceId, - vertex_count: u32, - instance_count: u32, - first_vertex: u32, - first_instance: u32, + render_pass_rid: ResourceId, + vertex_count: u32, + instance_count: u32, + first_vertex: u32, + first_instance: u32, } pub fn op_webgpu_render_pass_draw( - state: &mut OpState, - args: RenderPassDrawArgs, - _: (), + state: &mut OpState, + args: RenderPassDrawArgs, + _: (), ) -> Result { - let render_pass_resource = state - .resource_table - .get::(args.render_pass_rid)?; + let render_pass_resource = state + .resource_table + .get::(args.render_pass_rid)?; - wgpu_core::command::render_ffi::wgpu_render_pass_draw( - &mut render_pass_resource.0.borrow_mut(), - args.vertex_count, - args.instance_count, - args.first_vertex, - args.first_instance, - ); + wgpu_core::command::render_ffi::wgpu_render_pass_draw( + &mut render_pass_resource.0.borrow_mut(), + args.vertex_count, + args.instance_count, + args.first_vertex, + args.first_instance, + ); - Ok(WebGpuResult::empty()) + Ok(WebGpuResult::empty()) } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct RenderPassDrawIndexedArgs { - render_pass_rid: ResourceId, - index_count: u32, - instance_count: u32, - first_index: u32, - base_vertex: i32, - first_instance: u32, + render_pass_rid: ResourceId, + index_count: u32, + instance_count: u32, + first_index: u32, + base_vertex: i32, + first_instance: u32, } pub fn op_webgpu_render_pass_draw_indexed( - state: &mut OpState, - args: RenderPassDrawIndexedArgs, - _: (), + state: &mut OpState, + args: RenderPassDrawIndexedArgs, + _: (), ) -> Result { - let render_pass_resource = state - .resource_table - .get::(args.render_pass_rid)?; + let render_pass_resource = state + .resource_table + .get::(args.render_pass_rid)?; - wgpu_core::command::render_ffi::wgpu_render_pass_draw_indexed( - &mut render_pass_resource.0.borrow_mut(), - args.index_count, - args.instance_count, - args.first_index, - args.base_vertex, - args.first_instance, - ); + wgpu_core::command::render_ffi::wgpu_render_pass_draw_indexed( + &mut render_pass_resource.0.borrow_mut(), + args.index_count, + args.instance_count, + args.first_index, + args.base_vertex, + args.first_instance, + ); - Ok(WebGpuResult::empty()) + Ok(WebGpuResult::empty()) } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct RenderPassDrawIndirectArgs { - render_pass_rid: ResourceId, - indirect_buffer: u32, - indirect_offset: u64, + render_pass_rid: ResourceId, + indirect_buffer: u32, + indirect_offset: u64, } pub fn op_webgpu_render_pass_draw_indirect( - state: &mut OpState, - args: RenderPassDrawIndirectArgs, - _: (), + state: &mut OpState, + args: RenderPassDrawIndirectArgs, + _: (), ) -> Result { - let buffer_resource = state - .resource_table - .get::(args.indirect_buffer)?; - let render_pass_resource = state - .resource_table - .get::(args.render_pass_rid)?; + let buffer_resource = state + .resource_table + .get::(args.indirect_buffer)?; + let render_pass_resource = state + .resource_table + .get::(args.render_pass_rid)?; - wgpu_core::command::render_ffi::wgpu_render_pass_draw_indirect( - &mut render_pass_resource.0.borrow_mut(), - buffer_resource.0, - args.indirect_offset, - ); + wgpu_core::command::render_ffi::wgpu_render_pass_draw_indirect( + &mut render_pass_resource.0.borrow_mut(), + buffer_resource.0, + args.indirect_offset, + ); - Ok(WebGpuResult::empty()) + Ok(WebGpuResult::empty()) } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct RenderPassDrawIndexedIndirectArgs { - render_pass_rid: ResourceId, - indirect_buffer: u32, - indirect_offset: u64, + render_pass_rid: ResourceId, + indirect_buffer: u32, + indirect_offset: u64, } pub fn op_webgpu_render_pass_draw_indexed_indirect( - state: &mut OpState, - args: RenderPassDrawIndexedIndirectArgs, - _: (), + state: &mut OpState, + args: RenderPassDrawIndexedIndirectArgs, + _: (), ) -> Result { - let buffer_resource = state - .resource_table - .get::(args.indirect_buffer)?; - let render_pass_resource = state - .resource_table - .get::(args.render_pass_rid)?; - - wgpu_core::command::render_ffi::wgpu_render_pass_draw_indexed_indirect( - &mut render_pass_resource.0.borrow_mut(), - buffer_resource.0, - args.indirect_offset, - ); - - Ok(WebGpuResult::empty()) + let buffer_resource = state + .resource_table + .get::(args.indirect_buffer)?; + let render_pass_resource = state + .resource_table + .get::(args.render_pass_rid)?; + + wgpu_core::command::render_ffi::wgpu_render_pass_draw_indexed_indirect( + &mut render_pass_resource.0.borrow_mut(), + buffer_resource.0, + args.indirect_offset, + ); + + Ok(WebGpuResult::empty()) } diff --git a/ext/webgpu/src/sampler.rs b/ext/webgpu/src/sampler.rs index 5e49d14c9bb0a0..54a324a67700c1 100644 --- a/ext/webgpu/src/sampler.rs +++ b/ext/webgpu/src/sampler.rs @@ -10,57 +10,57 @@ use super::error::WebGpuResult; pub(crate) struct WebGpuSampler(pub(crate) wgpu_core::id::SamplerId); impl Resource for WebGpuSampler { - fn name(&self) -> Cow { - "webGPUSampler".into() - } + fn name(&self) -> Cow { + "webGPUSampler".into() + } } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct CreateSamplerArgs { - device_rid: ResourceId, - label: Option, - address_mode_u: wgpu_types::AddressMode, - address_mode_v: wgpu_types::AddressMode, - address_mode_w: wgpu_types::AddressMode, - mag_filter: wgpu_types::FilterMode, - min_filter: wgpu_types::FilterMode, - mipmap_filter: wgpu_types::FilterMode, - lod_min_clamp: f32, - lod_max_clamp: f32, - compare: Option, - max_anisotropy: u8, + device_rid: ResourceId, + label: Option, + address_mode_u: wgpu_types::AddressMode, + address_mode_v: wgpu_types::AddressMode, + address_mode_w: wgpu_types::AddressMode, + mag_filter: wgpu_types::FilterMode, + min_filter: wgpu_types::FilterMode, + mipmap_filter: wgpu_types::FilterMode, + lod_min_clamp: f32, + lod_max_clamp: f32, + compare: Option, + max_anisotropy: u8, } pub fn op_webgpu_create_sampler( - state: &mut OpState, - args: CreateSamplerArgs, - _: (), + state: &mut OpState, + args: CreateSamplerArgs, + _: (), ) -> Result { - let instance = state.borrow::(); - let device_resource = state - .resource_table - .get::(args.device_rid)?; - let device = device_resource.0; + let instance = state.borrow::(); + let device_resource = state + .resource_table + .get::(args.device_rid)?; + let device = device_resource.0; - let descriptor = wgpu_core::resource::SamplerDescriptor { - label: args.label.map(Cow::from), - address_modes: [ - args.address_mode_u, - args.address_mode_v, - args.address_mode_w, - ], - mag_filter: args.mag_filter, - min_filter: args.min_filter, - mipmap_filter: args.mipmap_filter, - lod_min_clamp: args.lod_min_clamp, - lod_max_clamp: args.lod_max_clamp, - compare: args.compare, - anisotropy_clamp: std::num::NonZeroU8::new(args.max_anisotropy), - border_color: None, // native-only - }; + let descriptor = wgpu_core::resource::SamplerDescriptor { + label: args.label.map(Cow::from), + address_modes: [ + args.address_mode_u, + args.address_mode_v, + args.address_mode_w, + ], + mag_filter: args.mag_filter, + min_filter: args.min_filter, + mipmap_filter: args.mipmap_filter, + lod_min_clamp: args.lod_min_clamp, + lod_max_clamp: args.lod_max_clamp, + compare: args.compare, + anisotropy_clamp: std::num::NonZeroU8::new(args.max_anisotropy), + border_color: None, // native-only + }; - gfx_put!(device => instance.device_create_sampler( + gfx_put!(device => instance.device_create_sampler( device, &descriptor, std::marker::PhantomData diff --git a/ext/webgpu/src/shader.rs b/ext/webgpu/src/shader.rs index 55fdf7021e78c0..e39c16b6bec95b 100644 --- a/ext/webgpu/src/shader.rs +++ b/ext/webgpu/src/shader.rs @@ -10,39 +10,40 @@ use super::error::WebGpuResult; pub(crate) struct WebGpuShaderModule(pub(crate) wgpu_core::id::ShaderModuleId); impl Resource for WebGpuShaderModule { - fn name(&self) -> Cow { - "webGPUShaderModule".into() - } + fn name(&self) -> Cow { + "webGPUShaderModule".into() + } } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct CreateShaderModuleArgs { - device_rid: ResourceId, - label: Option, - code: String, - _source_map: Option<()>, // not yet implemented + device_rid: ResourceId, + label: Option, + code: String, + _source_map: Option<()>, // not yet implemented } pub fn op_webgpu_create_shader_module( - state: &mut OpState, - args: CreateShaderModuleArgs, - _: (), + state: &mut OpState, + args: CreateShaderModuleArgs, + _: (), ) -> Result { - let instance = state.borrow::(); - let device_resource = state - .resource_table - .get::(args.device_rid)?; - let device = device_resource.0; + let instance = state.borrow::(); + let device_resource = state + .resource_table + .get::(args.device_rid)?; + let device = device_resource.0; - let source = wgpu_core::pipeline::ShaderModuleSource::Wgsl(Cow::from(args.code)); + let source = + wgpu_core::pipeline::ShaderModuleSource::Wgsl(Cow::from(args.code)); - let descriptor = wgpu_core::pipeline::ShaderModuleDescriptor { - label: args.label.map(Cow::from), - shader_bound_checks: wgpu_types::ShaderBoundChecks::default(), - }; + let descriptor = wgpu_core::pipeline::ShaderModuleDescriptor { + label: args.label.map(Cow::from), + shader_bound_checks: wgpu_types::ShaderBoundChecks::default(), + }; - gfx_put!(device => instance.device_create_shader_module( + gfx_put!(device => instance.device_create_shader_module( device, &descriptor, source, diff --git a/ext/webgpu/src/texture.rs b/ext/webgpu/src/texture.rs index a3b2b79c7f66db..aa52529e1bf705 100644 --- a/ext/webgpu/src/texture.rs +++ b/ext/webgpu/src/texture.rs @@ -9,53 +9,53 @@ use std::borrow::Cow; use super::error::WebGpuResult; pub(crate) struct WebGpuTexture(pub(crate) wgpu_core::id::TextureId); impl Resource for WebGpuTexture { - fn name(&self) -> Cow { - "webGPUTexture".into() - } + fn name(&self) -> Cow { + "webGPUTexture".into() + } } pub(crate) struct WebGpuTextureView(pub(crate) wgpu_core::id::TextureViewId); impl Resource for WebGpuTextureView { - fn name(&self) -> Cow { - "webGPUTextureView".into() - } + fn name(&self) -> Cow { + "webGPUTextureView".into() + } } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct CreateTextureArgs { - device_rid: ResourceId, - label: Option, - size: wgpu_types::Extent3d, - mip_level_count: u32, - sample_count: u32, - dimension: wgpu_types::TextureDimension, - format: wgpu_types::TextureFormat, - usage: u32, + device_rid: ResourceId, + label: Option, + size: wgpu_types::Extent3d, + mip_level_count: u32, + sample_count: u32, + dimension: wgpu_types::TextureDimension, + format: wgpu_types::TextureFormat, + usage: u32, } pub fn op_webgpu_create_texture( - state: &mut OpState, - args: CreateTextureArgs, - _: (), + state: &mut OpState, + args: CreateTextureArgs, + _: (), ) -> Result { - let instance = state.borrow::(); - let device_resource = state - .resource_table - .get::(args.device_rid)?; - let device = device_resource.0; + let instance = state.borrow::(); + let device_resource = state + .resource_table + .get::(args.device_rid)?; + let device = device_resource.0; - let descriptor = wgpu_core::resource::TextureDescriptor { - label: args.label.map(Cow::from), - size: args.size, - mip_level_count: args.mip_level_count, - sample_count: args.sample_count, - dimension: args.dimension, - format: args.format, - usage: wgpu_types::TextureUsages::from_bits_truncate(args.usage), - }; + let descriptor = wgpu_core::resource::TextureDescriptor { + label: args.label.map(Cow::from), + size: args.size, + mip_level_count: args.mip_level_count, + sample_count: args.sample_count, + dimension: args.dimension, + format: args.format, + usage: wgpu_types::TextureUsages::from_bits_truncate(args.usage), + }; - gfx_put!(device => instance.device_create_texture( + gfx_put!(device => instance.device_create_texture( device, &descriptor, std::marker::PhantomData @@ -65,42 +65,46 @@ pub fn op_webgpu_create_texture( #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct CreateTextureViewArgs { - texture_rid: ResourceId, - label: Option, - format: Option, - dimension: Option, - aspect: wgpu_types::TextureAspect, - base_mip_level: u32, - mip_level_count: Option, - base_array_layer: u32, - array_layer_count: Option, + texture_rid: ResourceId, + label: Option, + format: Option, + dimension: Option, + aspect: wgpu_types::TextureAspect, + base_mip_level: u32, + mip_level_count: Option, + base_array_layer: u32, + array_layer_count: Option, } pub fn op_webgpu_create_texture_view( - state: &mut OpState, - args: CreateTextureViewArgs, - _: (), + state: &mut OpState, + args: CreateTextureViewArgs, + _: (), ) -> Result { - let instance = state.borrow::(); - let texture_resource = state - .resource_table - .get::(args.texture_rid)?; - let texture = texture_resource.0; + let instance = state.borrow::(); + let texture_resource = state + .resource_table + .get::(args.texture_rid)?; + let texture = texture_resource.0; - let descriptor = wgpu_core::resource::TextureViewDescriptor { - label: args.label.map(Cow::from), - format: args.format, - dimension: args.dimension, - range: wgpu_types::ImageSubresourceRange { - aspect: args.aspect, - base_mip_level: args.base_mip_level, - mip_level_count: std::num::NonZeroU32::new(args.mip_level_count.unwrap_or(0)), - base_array_layer: args.base_array_layer, - array_layer_count: std::num::NonZeroU32::new(args.array_layer_count.unwrap_or(0)), - }, - }; + let descriptor = wgpu_core::resource::TextureViewDescriptor { + label: args.label.map(Cow::from), + format: args.format, + dimension: args.dimension, + range: wgpu_types::ImageSubresourceRange { + aspect: args.aspect, + base_mip_level: args.base_mip_level, + mip_level_count: std::num::NonZeroU32::new( + args.mip_level_count.unwrap_or(0), + ), + base_array_layer: args.base_array_layer, + array_layer_count: std::num::NonZeroU32::new( + args.array_layer_count.unwrap_or(0), + ), + }, + }; - gfx_put!(texture => instance.texture_create_view( + gfx_put!(texture => instance.texture_create_view( texture, &descriptor, std::marker::PhantomData From 6c80672d3356f285cdd205d4a9a69665caea732f Mon Sep 17 00:00:00 2001 From: Aaron O'Mullan Date: Mon, 17 Jan 2022 22:14:26 +0100 Subject: [PATCH 04/16] call format.js in wgpu_sync.js --- tools/wgpu_sync.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tools/wgpu_sync.js b/tools/wgpu_sync.js index 49b939fc55cdf7..1887e0d3253e1f 100755 --- a/tools/wgpu_sync.js +++ b/tools/wgpu_sync.js @@ -10,7 +10,7 @@ const V_WGPU = "0.12.0"; const V_DENO_CORE = "0.114.0"; const TARGET_DIR = join(ROOT_PATH, "ext", "webgpu"); -async function bashThrough(subcmd, opts = {}) { +async function bash(subcmd, opts = {}) { const p = Deno.run({ ...opts, cmd: ["bash", "-c", subcmd] }); // Exit process on failure @@ -23,7 +23,7 @@ async function bashThrough(subcmd, opts = {}) { } async function clearTargetDir() { - await bashThrough(`rm -r ${TARGET_DIR}/*`); + await bash(`rm -r ${TARGET_DIR}/*`); } async function checkoutUpstream() { @@ -32,7 +32,7 @@ async function checkoutUpstream() { const cmd = `curl -L https://api.github.com/repos/${REPO}/tarball/${COMMIT} | tar -C '${TARGET_DIR}' -xzvf - --strip=2 '${tarPrefix}'`; // console.log(cmd); - await bashThrough(cmd); + await bash(cmd); } async function patchCargo() { @@ -65,6 +65,7 @@ async function main() { await clearTargetDir(); await checkoutUpstream(); await patchCargo(); + await bash(join(ROOT_PATH, "tools", "format.js")); } await main(); From d336d42e751478b5b4f1967f84d212a2128e882d Mon Sep 17 00:00:00 2001 From: Aaron O'Mullan Date: Mon, 17 Jan 2022 22:32:46 +0100 Subject: [PATCH 05/16] lint --- tools/wgpu_sync.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/wgpu_sync.js b/tools/wgpu_sync.js index 1887e0d3253e1f..0493f222cfc256 100755 --- a/tools/wgpu_sync.js +++ b/tools/wgpu_sync.js @@ -6,7 +6,7 @@ import { join, ROOT_PATH } from "./util.js"; // const COMMIT = "c00e471274b6c21acda89b4b13d41742c0285d71"; // Release 12 const COMMIT = "0183e7d1e85ac95f2461426a910b2f86f5373119"; // tip const REPO = "gfx-rs/wgpu"; -const V_WGPU = "0.12.0"; +// const V_WGPU = "0.12.0"; const V_DENO_CORE = "0.114.0"; const TARGET_DIR = join(ROOT_PATH, "ext", "webgpu"); From a99ff4c49540019a54de3b50f268482755dafdba Mon Sep 17 00:00:00 2001 From: Aaron O'Mullan Date: Tue, 18 Jan 2022 01:34:27 +0100 Subject: [PATCH 06/16] move lib.deno_webgpu.d.ts to cli/ --- cli/build.rs | 7 +- cli/dts/lib.deno_webgpu.d.ts | 1132 ++++++++++++++++++++++++++++++++++ cli/tsc.rs | 2 +- 3 files changed, 1135 insertions(+), 6 deletions(-) create mode 100644 cli/dts/lib.deno_webgpu.d.ts diff --git a/cli/build.rs b/cli/build.rs index 87c68848044150..8ef93c6bdf15a8 100644 --- a/cli/build.rs +++ b/cli/build.rs @@ -82,7 +82,6 @@ fn create_compiler_snapshot( op_crate_libs.insert("deno.url", deno_url::get_declaration()); op_crate_libs.insert("deno.web", deno_web::get_declaration()); op_crate_libs.insert("deno.fetch", deno_fetch::get_declaration()); - op_crate_libs.insert("deno.webgpu", deno_webgpu::get_declaration()); op_crate_libs.insert("deno.websocket", deno_websocket::get_declaration()); op_crate_libs.insert("deno.webstorage", deno_webstorage::get_declaration()); op_crate_libs.insert("deno.crypto", deno_crypto::get_declaration()); @@ -153,6 +152,8 @@ fn create_compiler_snapshot( "esnext.intl", "esnext.object", "esnext.string", + // WebGPU + "deno_webgpu", ]; let path_dts = cwd.join("dts"); @@ -320,10 +321,6 @@ fn main() { "cargo:rustc-env=DENO_FETCH_LIB_PATH={}", deno_fetch::get_declaration().display() ); - println!( - "cargo:rustc-env=DENO_WEBGPU_LIB_PATH={}", - deno_webgpu::get_declaration().display() - ); println!( "cargo:rustc-env=DENO_WEBSOCKET_LIB_PATH={}", deno_websocket::get_declaration().display() diff --git a/cli/dts/lib.deno_webgpu.d.ts b/cli/dts/lib.deno_webgpu.d.ts new file mode 100644 index 00000000000000..001b3c1f003a19 --- /dev/null +++ b/cli/dts/lib.deno_webgpu.d.ts @@ -0,0 +1,1132 @@ +// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. + +// deno-lint-ignore-file no-explicit-any no-empty-interface + +/// +/// + +// 8cc98b6f10b7f354473a08c3773bb1de839845b9 + +interface GPUObjectBase { + label: string | null; +} + +declare interface GPUObjectDescriptorBase { + label?: string; +} + +declare class GPUSupportedLimits { + maxTextureDimension1D?: number; + maxTextureDimension2D?: number; + maxTextureDimension3D?: number; + maxTextureArrayLayers?: number; + maxBindGroups?: number; + maxDynamicUniformBuffersPerPipelineLayout?: number; + maxDynamicStorageBuffersPerPipelineLayout?: number; + maxSampledTexturesPerShaderStage?: number; + maxSamplersPerShaderStage?: number; + maxStorageBuffersPerShaderStage?: number; + maxStorageTexturesPerShaderStage?: number; + maxUniformBuffersPerShaderStage?: number; + maxUniformBufferBindingSize?: number; + maxStorageBufferBindingSize?: number; + minUniformBufferOffsetAlignment?: number; + minStorageBufferOffsetAlignment?: number; + maxVertexBuffers?: number; + maxVertexAttributes?: number; + maxVertexBufferArrayStride?: number; + maxInterStageShaderComponents?: number; + maxComputeWorkgroupStorageSize?: number; + maxComputeInvocationsPerWorkgroup?: number; + maxComputeWorkgroupSizeX?: number; + maxComputeWorkgroupSizeY?: number; + maxComputeWorkgroupSizeZ?: number; + maxComputeWorkgroupsPerDimension?: number; +} + +declare class GPUSupportedFeatures { + forEach( + callbackfn: ( + value: GPUFeatureName, + value2: GPUFeatureName, + set: Set, + ) => void, + thisArg?: any, + ): void; + has(value: GPUFeatureName): boolean; + size: number; + [ + Symbol + .iterator + ](): IterableIterator; + entries(): IterableIterator<[GPUFeatureName, GPUFeatureName]>; + keys(): IterableIterator; + values(): IterableIterator; +} + +declare class GPU { + requestAdapter( + options?: GPURequestAdapterOptions, + ): Promise; +} + +declare interface GPURequestAdapterOptions { + powerPreference?: GPUPowerPreference; + forceFallbackAdapter?: boolean; +} + +declare type GPUPowerPreference = "low-power" | "high-performance"; + +declare class GPUAdapter { + readonly name: string; + readonly features: GPUSupportedFeatures; + readonly limits: GPUSupportedLimits; + readonly isFallbackAdapter: boolean; + + requestDevice(descriptor?: GPUDeviceDescriptor): Promise; +} + +declare interface GPUDeviceDescriptor extends GPUObjectDescriptorBase { + requiredFeatures?: GPUFeatureName[]; + requiredLimits?: Record; +} + +declare type GPUFeatureName = + | "depth-clamping" + | "depth24unorm-stencil8" + | "depth32float-stencil8" + | "pipeline-statistics-query" + | "texture-compression-bc" + | "timestamp-query" + // extended from spec + | "mappable-primary-buffers" + | "sampled-texture-binding-array" + | "sampled-texture-array-dynamic-indexing" + | "sampled-texture-array-non-uniform-indexing" + | "unsized-binding-array" + | "multi-draw-indirect" + | "multi-draw-indirect-count" + | "push-constants" + | "address-mode-clamp-to-border" + | "non-fill-polygon-mode" + | "texture-compression-etc2" + | "texture-compression-astc-ldr" + | "texture-adapter-specific-format-features" + | "shader-float64" + | "vertex-attribute-64bit"; + +declare class GPUDevice extends EventTarget implements GPUObjectBase { + label: string | null; + + readonly lost: Promise; + pushErrorScope(filter: GPUErrorFilter): undefined; + popErrorScope(): Promise; + onuncapturederror: + | ((this: GPUDevice, ev: GPUUncapturedErrorEvent) => any) + | null; + + readonly features: ReadonlyArray; + readonly limits: Record; + readonly queue: GPUQueue; + + destroy(): undefined; + + createBuffer(descriptor: GPUBufferDescriptor): GPUBuffer; + createTexture(descriptor: GPUTextureDescriptor): GPUTexture; + createSampler(descriptor?: GPUSamplerDescriptor): GPUSampler; + + createBindGroupLayout( + descriptor: GPUBindGroupLayoutDescriptor, + ): GPUBindGroupLayout; + createPipelineLayout( + descriptor: GPUPipelineLayoutDescriptor, + ): GPUPipelineLayout; + createBindGroup(descriptor: GPUBindGroupDescriptor): GPUBindGroup; + + createShaderModule(descriptor: GPUShaderModuleDescriptor): GPUShaderModule; + createComputePipeline( + descriptor: GPUComputePipelineDescriptor, + ): GPUComputePipeline; + createRenderPipeline( + descriptor: GPURenderPipelineDescriptor, + ): GPURenderPipeline; + createComputePipelineAsync( + descriptor: GPUComputePipelineDescriptor, + ): Promise; + createRenderPipelineAsync( + descriptor: GPURenderPipelineDescriptor, + ): Promise; + + createCommandEncoder( + descriptor?: GPUCommandEncoderDescriptor, + ): GPUCommandEncoder; + createRenderBundleEncoder( + descriptor: GPURenderBundleEncoderDescriptor, + ): GPURenderBundleEncoder; + + createQuerySet(descriptor: GPUQuerySetDescriptor): GPUQuerySet; +} + +declare class GPUBuffer implements GPUObjectBase { + label: string | null; + + mapAsync( + mode: GPUMapModeFlags, + offset?: number, + size?: number, + ): Promise; + getMappedRange(offset?: number, size?: number): ArrayBuffer; + unmap(): undefined; + + destroy(): undefined; +} + +declare interface GPUBufferDescriptor extends GPUObjectDescriptorBase { + size: number; + usage: GPUBufferUsageFlags; + mappedAtCreation?: boolean; +} + +declare type GPUBufferUsageFlags = number; +declare class GPUBufferUsage { + static MAP_READ: 0x0001; + static MAP_WRITE: 0x0002; + static COPY_SRC: 0x0004; + static COPY_DST: 0x0008; + static INDEX: 0x0010; + static VERTEX: 0x0020; + static UNIFORM: 0x0040; + static STORAGE: 0x0080; + static INDIRECT: 0x0100; + static QUERY_RESOLVE: 0x0200; +} + +declare type GPUMapModeFlags = number; +declare class GPUMapMode { + static READ: 0x0001; + static WRITE: 0x0002; +} + +declare class GPUTexture implements GPUObjectBase { + label: string | null; + + createView(descriptor?: GPUTextureViewDescriptor): GPUTextureView; + destroy(): undefined; +} + +declare interface GPUTextureDescriptor extends GPUObjectDescriptorBase { + size: GPUExtent3D; + mipLevelCount?: number; + sampleCount?: number; + dimension?: GPUTextureDimension; + format: GPUTextureFormat; + usage: GPUTextureUsageFlags; +} + +declare type GPUTextureDimension = "1d" | "2d" | "3d"; + +declare type GPUTextureUsageFlags = number; +declare class GPUTextureUsage { + static COPY_SRC: 0x01; + static COPY_DST: 0x02; + static TEXTURE_BINDING: 0x04; + static STORAGE_BINDING: 0x08; + static RENDER_ATTACHMENT: 0x10; +} + +declare class GPUTextureView implements GPUObjectBase { + label: string | null; +} + +declare interface GPUTextureViewDescriptor extends GPUObjectDescriptorBase { + format?: GPUTextureFormat; + dimension?: GPUTextureViewDimension; + aspect?: GPUTextureAspect; + baseMipLevel?: number; + mipLevelCount?: number; + baseArrayLayer?: number; + arrayLayerCount?: number; +} + +declare type GPUTextureViewDimension = + | "1d" + | "2d" + | "2d-array" + | "cube" + | "cube-array" + | "3d"; + +declare type GPUTextureAspect = "all" | "stencil-only" | "depth-only"; + +declare type GPUTextureFormat = + | "r8unorm" + | "r8snorm" + | "r8uint" + | "r8sint" + | "r16uint" + | "r16sint" + | "r16float" + | "rg8unorm" + | "rg8snorm" + | "rg8uint" + | "rg8sint" + | "r32uint" + | "r32sint" + | "r32float" + | "rg16uint" + | "rg16sint" + | "rg16float" + | "rgba8unorm" + | "rgba8unorm-srgb" + | "rgba8snorm" + | "rgba8uint" + | "rgba8sint" + | "bgra8unorm" + | "bgra8unorm-srgb" + | "rgb9e5ufloat" + | "rgb10a2unorm" + | "rg11b10ufloat" + | "rg32uint" + | "rg32sint" + | "rg32float" + | "rgba16uint" + | "rgba16sint" + | "rgba16float" + | "rgba32uint" + | "rgba32sint" + | "rgba32float" + | "stencil8" + | "depth16unorm" + | "depth24plus" + | "depth24plus-stencil8" + | "depth32float" + | "bc1-rgba-unorm" + | "bc1-rgba-unorm-srgb" + | "bc2-rgba-unorm" + | "bc2-rgba-unorm-srgb" + | "bc3-rgba-unorm" + | "bc3-rgba-unorm-srgb" + | "bc4-r-unorm" + | "bc4-r-snorm" + | "bc5-rg-unorm" + | "bc5-rg-snorm" + | "bc6h-rgb-ufloat" + | "bc6h-rgb-float" + | "bc7-rgba-unorm" + | "bc7-rgba-unorm-srgb" + | "depth24unorm-stencil8" + | "depth32float-stencil8"; + +declare class GPUSampler implements GPUObjectBase { + label: string | null; +} + +declare interface GPUSamplerDescriptor extends GPUObjectDescriptorBase { + addressModeU?: GPUAddressMode; + addressModeV?: GPUAddressMode; + addressModeW?: GPUAddressMode; + magFilter?: GPUFilterMode; + minFilter?: GPUFilterMode; + mipmapFilter?: GPUFilterMode; + lodMinClamp?: number; + lodMaxClamp?: number; + compare?: GPUCompareFunction; + maxAnisotropy?: number; +} + +declare type GPUAddressMode = "clamp-to-edge" | "repeat" | "mirror-repeat"; + +declare type GPUFilterMode = "nearest" | "linear"; + +declare type GPUCompareFunction = + | "never" + | "less" + | "equal" + | "less-equal" + | "greater" + | "not-equal" + | "greater-equal" + | "always"; + +declare class GPUBindGroupLayout implements GPUObjectBase { + label: string | null; +} + +declare interface GPUBindGroupLayoutDescriptor extends GPUObjectDescriptorBase { + entries: GPUBindGroupLayoutEntry[]; +} + +declare interface GPUBindGroupLayoutEntry { + binding: number; + visibility: GPUShaderStageFlags; + + buffer?: GPUBufferBindingLayout; + sampler?: GPUSamplerBindingLayout; + texture?: GPUTextureBindingLayout; + storageTexture?: GPUStorageTextureBindingLayout; +} + +declare type GPUShaderStageFlags = number; +declare class GPUShaderStage { + static VERTEX: 0x1; + static FRAGMENT: 0x2; + static COMPUTE: 0x4; +} + +declare interface GPUBufferBindingLayout { + type?: GPUBufferBindingType; + hasDynamicOffset?: boolean; + minBindingSize?: number; +} + +declare type GPUBufferBindingType = "uniform" | "storage" | "read-only-storage"; + +declare interface GPUSamplerBindingLayout { + type?: GPUSamplerBindingType; +} + +declare type GPUSamplerBindingType = + | "filtering" + | "non-filtering" + | "comparison"; + +declare interface GPUTextureBindingLayout { + sampleType?: GPUTextureSampleType; + viewDimension?: GPUTextureViewDimension; + multisampled?: boolean; +} + +declare type GPUTextureSampleType = + | "float" + | "unfilterable-float" + | "depth" + | "sint" + | "uint"; + +declare type GPUStorageTextureAccess = "write-only"; + +declare interface GPUStorageTextureBindingLayout { + access: GPUStorageTextureAccess; + format: GPUTextureFormat; + viewDimension?: GPUTextureViewDimension; +} + +declare class GPUBindGroup implements GPUObjectBase { + label: string | null; +} + +declare interface GPUBindGroupDescriptor extends GPUObjectDescriptorBase { + layout: GPUBindGroupLayout; + entries: GPUBindGroupEntry[]; +} + +declare type GPUBindingResource = + | GPUSampler + | GPUTextureView + | GPUBufferBinding; + +declare interface GPUBindGroupEntry { + binding: number; + resource: GPUBindingResource; +} + +declare interface GPUBufferBinding { + buffer: GPUBuffer; + offset?: number; + size?: number; +} + +declare class GPUPipelineLayout implements GPUObjectBase { + label: string | null; +} + +declare interface GPUPipelineLayoutDescriptor extends GPUObjectDescriptorBase { + bindGroupLayouts: GPUBindGroupLayout[]; +} + +declare type GPUCompilationMessageType = "error" | "warning" | "info"; + +declare interface GPUCompilationMessage { + readonly message: string; + readonly type: GPUCompilationMessageType; + readonly lineNum: number; + readonly linePos: number; +} + +declare interface GPUCompilationInfo { + readonly messages: ReadonlyArray; +} + +declare class GPUShaderModule implements GPUObjectBase { + label: string | null; + + compilationInfo(): Promise; +} + +declare interface GPUShaderModuleDescriptor extends GPUObjectDescriptorBase { + code: string; + sourceMap?: any; +} + +declare interface GPUPipelineDescriptorBase extends GPUObjectDescriptorBase { + layout?: GPUPipelineLayout; +} + +declare interface GPUPipelineBase { + getBindGroupLayout(index: number): GPUBindGroupLayout; +} + +declare interface GPUProgrammableStage { + module: GPUShaderModule; + entryPoint: string; +} + +declare class GPUComputePipeline implements GPUObjectBase, GPUPipelineBase { + label: string | null; + + getBindGroupLayout(index: number): GPUBindGroupLayout; +} + +declare interface GPUComputePipelineDescriptor + extends GPUPipelineDescriptorBase { + compute: GPUProgrammableStage; +} + +declare class GPURenderPipeline implements GPUObjectBase, GPUPipelineBase { + label: string | null; + + getBindGroupLayout(index: number): GPUBindGroupLayout; +} + +declare interface GPURenderPipelineDescriptor + extends GPUPipelineDescriptorBase { + vertex: GPUVertexState; + primitive?: GPUPrimitiveState; + depthStencil?: GPUDepthStencilState; + multisample?: GPUMultisampleState; + fragment?: GPUFragmentState; +} + +declare type GPUPrimitiveTopology = + | "point-list" + | "line-list" + | "line-strip" + | "triangle-list" + | "triangle-strip"; + +declare interface GPUPrimitiveState { + topology?: GPUPrimitiveTopology; + stripIndexFormat?: GPUIndexFormat; + frontFace?: GPUFrontFace; + cullMode?: GPUCullMode; + clampDepth?: boolean; +} + +declare type GPUFrontFace = "ccw" | "cw"; + +declare type GPUCullMode = "none" | "front" | "back"; + +declare interface GPUMultisampleState { + count?: number; + mask?: number; + alphaToCoverageEnabled?: boolean; +} + +declare interface GPUFragmentState extends GPUProgrammableStage { + targets: GPUColorTargetState[]; +} + +declare interface GPUColorTargetState { + format: GPUTextureFormat; + + blend?: GPUBlendState; + writeMask?: GPUColorWriteFlags; +} + +declare interface GPUBlendState { + color: GPUBlendComponent; + alpha: GPUBlendComponent; +} + +declare type GPUColorWriteFlags = number; +declare class GPUColorWrite { + static RED: 0x1; + static GREEN: 0x2; + static BLUE: 0x4; + static ALPHA: 0x8; + static ALL: 0xF; +} + +declare interface GPUBlendComponent { + srcFactor: GPUBlendFactor; + dstFactor: GPUBlendFactor; + operation: GPUBlendOperation; +} + +declare type GPUBlendFactor = + | "zero" + | "one" + | "src" + | "one-minus-src" + | "src-alpha" + | "one-minus-src-alpha" + | "dst" + | "one-minus-dst" + | "dst-alpha" + | "one-minus-dst-alpha" + | "src-alpha-saturated" + | "constant" + | "one-minus-constant"; + +declare type GPUBlendOperation = + | "add" + | "subtract" + | "reverse-subtract" + | "min" + | "max"; + +declare interface GPUDepthStencilState { + format: GPUTextureFormat; + + depthWriteEnabled?: boolean; + depthCompare?: GPUCompareFunction; + + stencilFront?: GPUStencilFaceState; + stencilBack?: GPUStencilFaceState; + + stencilReadMask?: number; + stencilWriteMask?: number; + + depthBias?: number; + depthBiasSlopeScale?: number; + depthBiasClamp?: number; +} + +declare interface GPUStencilFaceState { + compare?: GPUCompareFunction; + failOp?: GPUStencilOperation; + depthFailOp?: GPUStencilOperation; + passOp?: GPUStencilOperation; +} + +declare type GPUStencilOperation = + | "keep" + | "zero" + | "replace" + | "invert" + | "increment-clamp" + | "decrement-clamp" + | "increment-wrap" + | "decrement-wrap"; + +declare type GPUIndexFormat = "uint16" | "uint32"; + +declare type GPUVertexFormat = + | "uint8x2" + | "uint8x4" + | "sint8x2" + | "sint8x4" + | "unorm8x2" + | "unorm8x4" + | "snorm8x2" + | "snorm8x4" + | "uint16x2" + | "uint16x4" + | "sint16x2" + | "sint16x4" + | "unorm16x2" + | "unorm16x4" + | "snorm16x2" + | "snorm16x4" + | "float16x2" + | "float16x4" + | "float32" + | "float32x2" + | "float32x3" + | "float32x4" + | "uint32" + | "uint32x2" + | "uint32x3" + | "uint32x4" + | "sint32" + | "sint32x2" + | "sint32x3" + | "sint32x4"; +declare type GPUVertexStepMode = "vertex" | "instance"; + +declare interface GPUVertexState extends GPUProgrammableStage { + buffers?: (GPUVertexBufferLayout | null)[]; +} + +declare interface GPUVertexBufferLayout { + arrayStride: number; + stepMode?: GPUVertexStepMode; + attributes: GPUVertexAttribute[]; +} + +declare interface GPUVertexAttribute { + format: GPUVertexFormat; + offset: number; + + shaderLocation: number; +} + +declare class GPUCommandBuffer implements GPUObjectBase { + label: string | null; + + readonly executionTime: Promise; +} + +declare interface GPUCommandBufferDescriptor extends GPUObjectDescriptorBase {} + +declare class GPUCommandEncoder implements GPUObjectBase { + label: string | null; + + beginRenderPass(descriptor: GPURenderPassDescriptor): GPURenderPassEncoder; + beginComputePass( + descriptor?: GPUComputePassDescriptor, + ): GPUComputePassEncoder; + + copyBufferToBuffer( + source: GPUBuffer, + sourceOffset: number, + destination: GPUBuffer, + destinationOffset: number, + size: number, + ): undefined; + + copyBufferToTexture( + source: GPUImageCopyBuffer, + destination: GPUImageCopyTexture, + copySize: GPUExtent3D, + ): undefined; + + copyTextureToBuffer( + source: GPUImageCopyTexture, + destination: GPUImageCopyBuffer, + copySize: GPUExtent3D, + ): undefined; + + copyTextureToTexture( + source: GPUImageCopyTexture, + destination: GPUImageCopyTexture, + copySize: GPUExtent3D, + ): undefined; + + pushDebugGroup(groupLabel: string): undefined; + popDebugGroup(): undefined; + insertDebugMarker(markerLabel: string): undefined; + + writeTimestamp(querySet: GPUQuerySet, queryIndex: number): undefined; + + resolveQuerySet( + querySet: GPUQuerySet, + firstQuery: number, + queryCount: number, + destination: GPUBuffer, + destinationOffset: number, + ): undefined; + + finish(descriptor?: GPUCommandBufferDescriptor): GPUCommandBuffer; +} + +declare interface GPUCommandEncoderDescriptor extends GPUObjectDescriptorBase { + measureExecutionTime?: boolean; +} + +declare interface GPUImageDataLayout { + offset?: number; + bytesPerRow?: number; + rowsPerImage?: number; +} + +declare interface GPUImageCopyBuffer extends GPUImageDataLayout { + buffer: GPUBuffer; +} + +declare interface GPUImageCopyTexture { + texture: GPUTexture; + mipLevel?: number; + origin?: GPUOrigin3D; + aspect?: GPUTextureAspect; +} + +interface GPUProgrammablePassEncoder { + setBindGroup( + index: number, + bindGroup: GPUBindGroup, + dynamicOffsets?: number[], + ): undefined; + + setBindGroup( + index: number, + bindGroup: GPUBindGroup, + dynamicOffsetsData: Uint32Array, + dynamicOffsetsDataStart: number, + dynamicOffsetsDataLength: number, + ): undefined; + + pushDebugGroup(groupLabel: string): undefined; + popDebugGroup(): undefined; + insertDebugMarker(markerLabel: string): undefined; +} + +declare class GPUComputePassEncoder + implements GPUObjectBase, GPUProgrammablePassEncoder { + label: string | null; + setBindGroup( + index: number, + bindGroup: GPUBindGroup, + dynamicOffsets?: number[], + ): undefined; + setBindGroup( + index: number, + bindGroup: GPUBindGroup, + dynamicOffsetsData: Uint32Array, + dynamicOffsetsDataStart: number, + dynamicOffsetsDataLength: number, + ): undefined; + pushDebugGroup(groupLabel: string): undefined; + popDebugGroup(): undefined; + insertDebugMarker(markerLabel: string): undefined; + setPipeline(pipeline: GPUComputePipeline): undefined; + dispatch(x: number, y?: number, z?: number): undefined; + dispatchIndirect( + indirectBuffer: GPUBuffer, + indirectOffset: number, + ): undefined; + + beginPipelineStatisticsQuery( + querySet: GPUQuerySet, + queryIndex: number, + ): undefined; + endPipelineStatisticsQuery(): undefined; + + writeTimestamp(querySet: GPUQuerySet, queryIndex: number): undefined; + + endPass(): undefined; +} + +declare interface GPUComputePassDescriptor extends GPUObjectDescriptorBase {} + +interface GPURenderEncoderBase { + setPipeline(pipeline: GPURenderPipeline): undefined; + + setIndexBuffer( + buffer: GPUBuffer, + indexFormat: GPUIndexFormat, + offset?: number, + size?: number, + ): undefined; + setVertexBuffer( + slot: number, + buffer: GPUBuffer, + offset?: number, + size?: number, + ): undefined; + + draw( + vertexCount: number, + instanceCount?: number, + firstVertex?: number, + firstInstance?: number, + ): undefined; + drawIndexed( + indexCount: number, + instanceCount?: number, + firstIndex?: number, + baseVertex?: number, + firstInstance?: number, + ): undefined; + + drawIndirect(indirectBuffer: GPUBuffer, indirectOffset: number): undefined; + drawIndexedIndirect( + indirectBuffer: GPUBuffer, + indirectOffset: number, + ): undefined; +} + +declare class GPURenderPassEncoder + implements GPUObjectBase, GPUProgrammablePassEncoder, GPURenderEncoderBase { + label: string | null; + setBindGroup( + index: number, + bindGroup: GPUBindGroup, + dynamicOffsets?: number[], + ): undefined; + setBindGroup( + index: number, + bindGroup: GPUBindGroup, + dynamicOffsetsData: Uint32Array, + dynamicOffsetsDataStart: number, + dynamicOffsetsDataLength: number, + ): undefined; + pushDebugGroup(groupLabel: string): undefined; + popDebugGroup(): undefined; + insertDebugMarker(markerLabel: string): undefined; + setPipeline(pipeline: GPURenderPipeline): undefined; + setIndexBuffer( + buffer: GPUBuffer, + indexFormat: GPUIndexFormat, + offset?: number, + size?: number, + ): undefined; + setVertexBuffer( + slot: number, + buffer: GPUBuffer, + offset?: number, + size?: number, + ): undefined; + draw( + vertexCount: number, + instanceCount?: number, + firstVertex?: number, + firstInstance?: number, + ): undefined; + drawIndexed( + indexCount: number, + instanceCount?: number, + firstIndex?: number, + baseVertex?: number, + firstInstance?: number, + ): undefined; + drawIndirect(indirectBuffer: GPUBuffer, indirectOffset: number): undefined; + drawIndexedIndirect( + indirectBuffer: GPUBuffer, + indirectOffset: number, + ): undefined; + + setViewport( + x: number, + y: number, + width: number, + height: number, + minDepth: number, + maxDepth: number, + ): undefined; + + setScissorRect( + x: number, + y: number, + width: number, + height: number, + ): undefined; + + setBlendConstant(color: GPUColor): undefined; + setStencilReference(reference: number): undefined; + + beginOcclusionQuery(queryIndex: number): undefined; + endOcclusionQuery(): undefined; + + beginPipelineStatisticsQuery( + querySet: GPUQuerySet, + queryIndex: number, + ): undefined; + endPipelineStatisticsQuery(): undefined; + + writeTimestamp(querySet: GPUQuerySet, queryIndex: number): undefined; + + executeBundles(bundles: GPURenderBundle[]): undefined; + endPass(): undefined; +} + +declare interface GPURenderPassDescriptor extends GPUObjectDescriptorBase { + colorAttachments: GPURenderPassColorAttachment[]; + depthStencilAttachment?: GPURenderPassDepthStencilAttachment; + occlusionQuerySet?: GPUQuerySet; +} + +declare interface GPURenderPassColorAttachment { + view: GPUTextureView; + resolveTarget?: GPUTextureView; + + loadValue: GPULoadOp | GPUColor; + storeOp?: GPUStoreOp; +} + +declare interface GPURenderPassDepthStencilAttachment { + view: GPUTextureView; + + depthLoadValue: GPULoadOp | number; + depthStoreOp: GPUStoreOp; + depthReadOnly?: boolean; + + stencilLoadValue: GPULoadOp | number; + stencilStoreOp: GPUStoreOp; + stencilReadOnly?: boolean; +} + +declare type GPULoadOp = "load"; + +declare type GPUStoreOp = "store" | "discard"; + +declare class GPURenderBundle implements GPUObjectBase { + label: string | null; +} + +declare interface GPURenderBundleDescriptor extends GPUObjectDescriptorBase {} + +declare class GPURenderBundleEncoder + implements GPUObjectBase, GPUProgrammablePassEncoder, GPURenderEncoderBase { + label: string | null; + draw( + vertexCount: number, + instanceCount?: number, + firstVertex?: number, + firstInstance?: number, + ): undefined; + drawIndexed( + indexCount: number, + instanceCount?: number, + firstIndex?: number, + baseVertex?: number, + firstInstance?: number, + ): undefined; + drawIndexedIndirect( + indirectBuffer: GPUBuffer, + indirectOffset: number, + ): undefined; + drawIndirect(indirectBuffer: GPUBuffer, indirectOffset: number): undefined; + insertDebugMarker(markerLabel: string): undefined; + popDebugGroup(): undefined; + pushDebugGroup(groupLabel: string): undefined; + setBindGroup( + index: number, + bindGroup: GPUBindGroup, + dynamicOffsets?: number[], + ): undefined; + setBindGroup( + index: number, + bindGroup: GPUBindGroup, + dynamicOffsetsData: Uint32Array, + dynamicOffsetsDataStart: number, + dynamicOffsetsDataLength: number, + ): undefined; + setIndexBuffer( + buffer: GPUBuffer, + indexFormat: GPUIndexFormat, + offset?: number, + size?: number, + ): undefined; + setPipeline(pipeline: GPURenderPipeline): undefined; + setVertexBuffer( + slot: number, + buffer: GPUBuffer, + offset?: number, + size?: number, + ): undefined; + + finish(descriptor?: GPURenderBundleDescriptor): GPURenderBundle; +} + +declare interface GPURenderPassLayout extends GPUObjectDescriptorBase { + colorFormats: GPUTextureFormat[]; + depthStencilFormat?: GPUTextureFormat; + sampleCount?: number; +} + +declare interface GPURenderBundleEncoderDescriptor extends GPURenderPassLayout { + depthReadOnly?: boolean; + stencilReadOnly?: boolean; +} + +declare class GPUQueue implements GPUObjectBase { + label: string | null; + + submit(commandBuffers: GPUCommandBuffer[]): undefined; + + onSubmittedWorkDone(): Promise; + + writeBuffer( + buffer: GPUBuffer, + bufferOffset: number, + data: BufferSource, + dataOffset?: number, + size?: number, + ): undefined; + + writeTexture( + destination: GPUImageCopyTexture, + data: BufferSource, + dataLayout: GPUImageDataLayout, + size: GPUExtent3D, + ): undefined; +} + +declare class GPUQuerySet implements GPUObjectBase { + label: string | null; + + destroy(): undefined; +} + +declare interface GPUQuerySetDescriptor extends GPUObjectDescriptorBase { + type: GPUQueryType; + count: number; + pipelineStatistics?: GPUPipelineStatisticName[]; +} + +declare type GPUQueryType = "occlusion" | "pipeline-statistics" | "timestamp"; + +declare type GPUPipelineStatisticName = + | "vertex-shader-invocations" + | "clipper-invocations" + | "clipper-primitives-out" + | "fragment-shader-invocations" + | "compute-shader-invocations"; + +declare type GPUDeviceLostReason = "destroyed"; + +declare interface GPUDeviceLostInfo { + readonly reason: GPUDeviceLostReason | undefined; + readonly message: string; +} + +declare type GPUErrorFilter = "out-of-memory" | "validation"; + +declare class GPUOutOfMemoryError { + constructor(); +} + +declare class GPUValidationError { + constructor(message: string); + readonly message: string; +} + +declare type GPUError = GPUOutOfMemoryError | GPUValidationError; + +declare class GPUUncapturedErrorEvent extends Event { + constructor( + type: string, + gpuUncapturedErrorEventInitDict: GPUUncapturedErrorEventInit, + ); + readonly error: GPUError; +} + +declare interface GPUUncapturedErrorEventInit extends EventInit { + error?: GPUError; +} + +declare interface GPUColorDict { + r: number; + g: number; + b: number; + a: number; +} + +declare type GPUColor = number[] | GPUColorDict; + +declare interface GPUOrigin3DDict { + x?: number; + y?: number; + z?: number; +} + +declare type GPUOrigin3D = number[] | GPUOrigin3DDict; + +declare interface GPUExtent3DDict { + width: number; + height?: number; + depthOrArrayLayers?: number; +} + +declare type GPUExtent3D = number[] | GPUExtent3DDict; diff --git a/cli/tsc.rs b/cli/tsc.rs index 001cfaf5dd9bb5..e00d7ac3816018 100644 --- a/cli/tsc.rs +++ b/cli/tsc.rs @@ -37,7 +37,7 @@ pub static DENO_CONSOLE_LIB: &str = include_str!(env!("DENO_CONSOLE_LIB_PATH")); pub static DENO_URL_LIB: &str = include_str!(env!("DENO_URL_LIB_PATH")); pub static DENO_WEB_LIB: &str = include_str!(env!("DENO_WEB_LIB_PATH")); pub static DENO_FETCH_LIB: &str = include_str!(env!("DENO_FETCH_LIB_PATH")); -pub static DENO_WEBGPU_LIB: &str = include_str!(env!("DENO_WEBGPU_LIB_PATH")); +pub static DENO_WEBGPU_LIB: &str = include_str!("dts/lib.deno_webgpu.d.ts"); pub static DENO_WEBSOCKET_LIB: &str = include_str!(env!("DENO_WEBSOCKET_LIB_PATH")); pub static DENO_WEBSTORAGE_LIB: &str = From e7dbdd09e3c4a3e8e8feffed598839613465202b Mon Sep 17 00:00:00 2001 From: Aaron O'Mullan Date: Tue, 18 Jan 2022 01:36:24 +0100 Subject: [PATCH 07/16] wgpu sync to 58771175290bca7b9db546b3451d32fab2dc5d7b --- Cargo.lock | 18 ++++++++---------- ext/webgpu/Cargo.toml | 4 ++-- tools/wgpu_sync.js | 2 +- 3 files changed, 11 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 861275b1b1999e..6dc565a1f70893 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -136,9 +136,9 @@ dependencies = [ [[package]] name = "ash" -version = "0.33.3+1.2.191" +version = "0.35.0+1.2.203" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc4f1d82f164f838ae413296d1131aa6fa79b917d25bebaa7033d25620c09219" +checksum = "5a7638ce84f8c84d6fd6faa63aa267574d345181ba591c0eeb5550d4c30cd600" dependencies = [ "libloading", ] @@ -2316,8 +2316,7 @@ dependencies = [ [[package]] name = "metal" version = "0.23.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0514f491f4cc03632ab399ee01e2c1c1b12d3e1cf2d667c1ff5f87d6dcd2084" +source = "git+https://github.com/gfx-rs/metal-rs?rev=140c8f4#140c8f4e39001ae154f153ffc767da6c0c9d7f06" dependencies = [ "bitflags", "block", @@ -2367,9 +2366,8 @@ dependencies = [ [[package]] name = "naga" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4419062f8aa39fb25938169486341945758679e260ddbc1f94bfd1f33924dc2" +version = "0.8.0" +source = "git+https://github.com/gfx-rs/naga?rev=a1840be#a1840beb1a96c9a49980fe3efa8e2f3dcd88abe6" dependencies = [ "bit-set", "bitflags", @@ -4894,7 +4892,7 @@ dependencies = [ [[package]] name = "wgpu-core" version = "0.12.0" -source = "git+https://github.com/gfx-rs/wgpu?rev=c00e471274b6c21acda89b4b13d41742c0285d71#c00e471274b6c21acda89b4b13d41742c0285d71" +source = "git+https://github.com/gfx-rs/wgpu?rev=58771175290bca7b9db546b3451d32fab2dc5d7b#58771175290bca7b9db546b3451d32fab2dc5d7b" dependencies = [ "arrayvec 0.7.2", "bitflags", @@ -4917,7 +4915,7 @@ dependencies = [ [[package]] name = "wgpu-hal" version = "0.12.0" -source = "git+https://github.com/gfx-rs/wgpu?rev=c00e471274b6c21acda89b4b13d41742c0285d71#c00e471274b6c21acda89b4b13d41742c0285d71" +source = "git+https://github.com/gfx-rs/wgpu?rev=58771175290bca7b9db546b3451d32fab2dc5d7b#58771175290bca7b9db546b3451d32fab2dc5d7b" dependencies = [ "arrayvec 0.7.2", "ash", @@ -4954,7 +4952,7 @@ dependencies = [ [[package]] name = "wgpu-types" version = "0.12.0" -source = "git+https://github.com/gfx-rs/wgpu?rev=c00e471274b6c21acda89b4b13d41742c0285d71#c00e471274b6c21acda89b4b13d41742c0285d71" +source = "git+https://github.com/gfx-rs/wgpu?rev=58771175290bca7b9db546b3451d32fab2dc5d7b#58771175290bca7b9db546b3451d32fab2dc5d7b" dependencies = [ "bitflags", "bitflags_serde_shim", diff --git a/ext/webgpu/Cargo.toml b/ext/webgpu/Cargo.toml index 741027e292780b..c94484b06a005e 100644 --- a/ext/webgpu/Cargo.toml +++ b/ext/webgpu/Cargo.toml @@ -14,5 +14,5 @@ description = "WebGPU implementation for Deno" deno_core = { version = "0.114.0", path = "../../core" } serde = { version = "1.0", features = ["derive"] } tokio = { version = "1.10", features = ["full"] } -wgpu-core = { git = "https://github.com/gfx-rs/wgpu", rev = "0183e7d1e85ac95f2461426a910b2f86f5373119", features = ["trace", "replay", "serde"] } -wgpu-types = { git = "https://github.com/gfx-rs/wgpu", rev = "0183e7d1e85ac95f2461426a910b2f86f5373119", features = ["trace", "replay", "serde"] } +wgpu-core = { git = "https://github.com/gfx-rs/wgpu", rev = "58771175290bca7b9db546b3451d32fab2dc5d7b", features = ["trace", "replay", "serde"] } +wgpu-types = { git = "https://github.com/gfx-rs/wgpu", rev = "58771175290bca7b9db546b3451d32fab2dc5d7b", features = ["trace", "replay", "serde"] } diff --git a/tools/wgpu_sync.js b/tools/wgpu_sync.js index 0493f222cfc256..1301a84b44e86d 100755 --- a/tools/wgpu_sync.js +++ b/tools/wgpu_sync.js @@ -4,7 +4,7 @@ import { join, ROOT_PATH } from "./util.js"; // const COMMIT = "c00e471274b6c21acda89b4b13d41742c0285d71"; // Release 12 -const COMMIT = "0183e7d1e85ac95f2461426a910b2f86f5373119"; // tip +const COMMIT = "58771175290bca7b9db546b3451d32fab2dc5d7b"; // tip const REPO = "gfx-rs/wgpu"; // const V_WGPU = "0.12.0"; const V_DENO_CORE = "0.114.0"; From 86fc407bb698d94ed6e042ae6089e1b449c05dac Mon Sep 17 00:00:00 2001 From: Aaron O'Mullan Date: Tue, 18 Jan 2022 15:37:04 +0100 Subject: [PATCH 08/16] bump wgpu --- ext/webgpu/Cargo.toml | 4 ++-- ext/webgpu/src/lib.rs | 2 +- ext/webgpu/src/pipeline.rs | 10 +++++----- tools/wgpu_sync.js | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/ext/webgpu/Cargo.toml b/ext/webgpu/Cargo.toml index c94484b06a005e..452d0e8154d21b 100644 --- a/ext/webgpu/Cargo.toml +++ b/ext/webgpu/Cargo.toml @@ -14,5 +14,5 @@ description = "WebGPU implementation for Deno" deno_core = { version = "0.114.0", path = "../../core" } serde = { version = "1.0", features = ["derive"] } tokio = { version = "1.10", features = ["full"] } -wgpu-core = { git = "https://github.com/gfx-rs/wgpu", rev = "58771175290bca7b9db546b3451d32fab2dc5d7b", features = ["trace", "replay", "serde"] } -wgpu-types = { git = "https://github.com/gfx-rs/wgpu", rev = "58771175290bca7b9db546b3451d32fab2dc5d7b", features = ["trace", "replay", "serde"] } +wgpu-core = { git = "https://github.com/gfx-rs/wgpu", rev = "cdd480a89c9e3b681d9d174e65082d2bdbc903ef", features = ["trace", "replay", "serde"] } +wgpu-types = { git = "https://github.com/gfx-rs/wgpu", rev = "cdd480a89c9e3b681d9d174e65082d2bdbc903ef", features = ["trace", "replay", "serde"] } diff --git a/ext/webgpu/src/lib.rs b/ext/webgpu/src/lib.rs index 87c515b25f1b5e..2f7fb31d04350b 100644 --- a/ext/webgpu/src/lib.rs +++ b/ext/webgpu/src/lib.rs @@ -266,7 +266,7 @@ pub async fn op_webgpu_request_adapter( let descriptor = wgpu_core::instance::RequestAdapterOptions { power_preference: match args.power_preference { - Some(power_preference) => power_preference.into(), + Some(power_preference) => power_preference, None => PowerPreference::default(), }, force_fallback_adapter: args.force_fallback_adapter, diff --git a/ext/webgpu/src/pipeline.rs b/ext/webgpu/src/pipeline.rs index fd45d66b14eff7..0c1bc444fcb640 100644 --- a/ext/webgpu/src/pipeline.rs +++ b/ext/webgpu/src/pipeline.rs @@ -217,10 +217,10 @@ impl TryFrom for wgpu_types::DepthStencilState { Ok(wgpu_types::DepthStencilState { format: state.format, depth_write_enabled: state.depth_write_enabled, - depth_compare: state.depth_compare.into(), + depth_compare: state.depth_compare, stencil: wgpu_types::StencilState { - front: state.stencil_front.into(), - back: state.stencil_back.into(), + front: state.stencil_front, + back: state.stencil_back, read_mask: state.stencil_read_mask, write_mask: state.stencil_write_mask, }, @@ -336,7 +336,7 @@ pub fn op_webgpu_create_render_pipeline( let mut targets = Vec::with_capacity(fragment.targets.len()); for target in fragment.targets { - targets.push(target.try_into()?); + targets.push(target); } Some(wgpu_core::pipeline::FragmentState { @@ -370,7 +370,7 @@ pub fn op_webgpu_create_render_pipeline( }, primitive: args.primitive.into(), depth_stencil: args.depth_stencil.map(TryInto::try_into).transpose()?, - multisample: args.multisample.into(), + multisample: args.multisample, fragment, multiview: None, }; diff --git a/tools/wgpu_sync.js b/tools/wgpu_sync.js index 1301a84b44e86d..addf1198794f33 100755 --- a/tools/wgpu_sync.js +++ b/tools/wgpu_sync.js @@ -4,7 +4,7 @@ import { join, ROOT_PATH } from "./util.js"; // const COMMIT = "c00e471274b6c21acda89b4b13d41742c0285d71"; // Release 12 -const COMMIT = "58771175290bca7b9db546b3451d32fab2dc5d7b"; // tip +const COMMIT = "cdd480a89c9e3b681d9d174e65082d2bdbc903ef"; // tip const REPO = "gfx-rs/wgpu"; // const V_WGPU = "0.12.0"; const V_DENO_CORE = "0.114.0"; From f20030cd15833e97f02030f6d7603f14dde782fe Mon Sep 17 00:00:00 2001 From: Aaron O'Mullan Date: Tue, 18 Jan 2022 15:37:21 +0100 Subject: [PATCH 09/16] Cargo.lock update --- Cargo.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6dc565a1f70893..d23808e60480bf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4892,7 +4892,7 @@ dependencies = [ [[package]] name = "wgpu-core" version = "0.12.0" -source = "git+https://github.com/gfx-rs/wgpu?rev=58771175290bca7b9db546b3451d32fab2dc5d7b#58771175290bca7b9db546b3451d32fab2dc5d7b" +source = "git+https://github.com/gfx-rs/wgpu?rev=cdd480a89c9e3b681d9d174e65082d2bdbc903ef#cdd480a89c9e3b681d9d174e65082d2bdbc903ef" dependencies = [ "arrayvec 0.7.2", "bitflags", @@ -4915,7 +4915,7 @@ dependencies = [ [[package]] name = "wgpu-hal" version = "0.12.0" -source = "git+https://github.com/gfx-rs/wgpu?rev=58771175290bca7b9db546b3451d32fab2dc5d7b#58771175290bca7b9db546b3451d32fab2dc5d7b" +source = "git+https://github.com/gfx-rs/wgpu?rev=cdd480a89c9e3b681d9d174e65082d2bdbc903ef#cdd480a89c9e3b681d9d174e65082d2bdbc903ef" dependencies = [ "arrayvec 0.7.2", "ash", @@ -4952,7 +4952,7 @@ dependencies = [ [[package]] name = "wgpu-types" version = "0.12.0" -source = "git+https://github.com/gfx-rs/wgpu?rev=58771175290bca7b9db546b3451d32fab2dc5d7b#58771175290bca7b9db546b3451d32fab2dc5d7b" +source = "git+https://github.com/gfx-rs/wgpu?rev=cdd480a89c9e3b681d9d174e65082d2bdbc903ef#cdd480a89c9e3b681d9d174e65082d2bdbc903ef" dependencies = [ "bitflags", "bitflags_serde_shim", From 437118ffb1c5f3adfcf202e1937bb99e569d0776 Mon Sep 17 00:00:00 2001 From: Aaron O'Mullan Date: Tue, 18 Jan 2022 15:59:49 +0100 Subject: [PATCH 10/16] fix cli tsc --- cli/build.rs | 12 ++++++++++-- cli/tsc.rs | 2 +- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/cli/build.rs b/cli/build.rs index 8ef93c6bdf15a8..2daeffa0d780de 100644 --- a/cli/build.rs +++ b/cli/build.rs @@ -82,6 +82,7 @@ fn create_compiler_snapshot( op_crate_libs.insert("deno.url", deno_url::get_declaration()); op_crate_libs.insert("deno.web", deno_web::get_declaration()); op_crate_libs.insert("deno.fetch", deno_fetch::get_declaration()); + op_crate_libs.insert("deno.webgpu", deno_webgpu_get_declaration()); op_crate_libs.insert("deno.websocket", deno_websocket::get_declaration()); op_crate_libs.insert("deno.webstorage", deno_webstorage::get_declaration()); op_crate_libs.insert("deno.crypto", deno_crypto::get_declaration()); @@ -152,8 +153,6 @@ fn create_compiler_snapshot( "esnext.intl", "esnext.object", "esnext.string", - // WebGPU - "deno_webgpu", ]; let path_dts = cwd.join("dts"); @@ -321,6 +320,10 @@ fn main() { "cargo:rustc-env=DENO_FETCH_LIB_PATH={}", deno_fetch::get_declaration().display() ); + println!( + "cargo:rustc-env=DENO_WEBGPU_LIB_PATH={}", + deno_webgpu_get_declaration().display() + ); println!( "cargo:rustc-env=DENO_WEBSOCKET_LIB_PATH={}", deno_websocket::get_declaration().display() @@ -366,6 +369,11 @@ fn main() { } } +fn deno_webgpu_get_declaration() -> PathBuf { + let manifest_dir = Path::new(env!("CARGO_MANIFEST_DIR")); + manifest_dir.join("dts").join("lib.deno_webgpu.d.ts") +} + fn get_js_files(d: &str) -> Vec { let manifest_dir = Path::new(env!("CARGO_MANIFEST_DIR")); let mut js_files = std::fs::read_dir(d) diff --git a/cli/tsc.rs b/cli/tsc.rs index e00d7ac3816018..001cfaf5dd9bb5 100644 --- a/cli/tsc.rs +++ b/cli/tsc.rs @@ -37,7 +37,7 @@ pub static DENO_CONSOLE_LIB: &str = include_str!(env!("DENO_CONSOLE_LIB_PATH")); pub static DENO_URL_LIB: &str = include_str!(env!("DENO_URL_LIB_PATH")); pub static DENO_WEB_LIB: &str = include_str!(env!("DENO_WEB_LIB_PATH")); pub static DENO_FETCH_LIB: &str = include_str!(env!("DENO_FETCH_LIB_PATH")); -pub static DENO_WEBGPU_LIB: &str = include_str!("dts/lib.deno_webgpu.d.ts"); +pub static DENO_WEBGPU_LIB: &str = include_str!(env!("DENO_WEBGPU_LIB_PATH")); pub static DENO_WEBSOCKET_LIB: &str = include_str!(env!("DENO_WEBSOCKET_LIB_PATH")); pub static DENO_WEBSTORAGE_LIB: &str = From 067bc859b76ff847c6c00c9888d2c82fad040913 Mon Sep 17 00:00:00 2001 From: crowlkats Date: Tue, 18 Jan 2022 17:37:30 +0100 Subject: [PATCH 11/16] fix test --- cli/tests/testdata/webgpu_computepass_shader.wgsl | 5 ++++- cli/tests/unit/webgpu_test.ts | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/cli/tests/testdata/webgpu_computepass_shader.wgsl b/cli/tests/testdata/webgpu_computepass_shader.wgsl index 9fc79eeba6c565..df541aff5e29c1 100644 --- a/cli/tests/testdata/webgpu_computepass_shader.wgsl +++ b/cli/tests/testdata/webgpu_computepass_shader.wgsl @@ -1,9 +1,10 @@ -[[block]] struct PrimeIndices { data: [[stride(4)]] array; }; // this is used as both input and output for convenience + [[group(0), binding(0)]] var v_indices: PrimeIndices; + // The Collatz Conjecture states that for any integer n: // If n is even, n = n/2 // If n is odd, n = 3n+1 @@ -25,12 +26,14 @@ fn collatz_iterations(n_base: u32) -> u32{ if (n >= 1431655765u) { // 0x55555555u return 4294967295u; // 0xffffffffu } + n = 3u * n + 1u; } i = i + 1u; } return i; } + [[stage(compute), workgroup_size(1)]] fn main([[builtin(global_invocation_id)]] global_id: vec3) { v_indices.data[global_id.x] = collatz_iterations(v_indices.data[global_id.x]); diff --git a/cli/tests/unit/webgpu_test.ts b/cli/tests/unit/webgpu_test.ts index 1d54d7b02667b9..917acc87b339b0 100644 --- a/cli/tests/unit/webgpu_test.ts +++ b/cli/tests/unit/webgpu_test.ts @@ -33,13 +33,13 @@ Deno.test({ const stagingBuffer = device.createBuffer({ size: size, - usage: 1 | 8, + usage: GPUBufferUsage.MAP_READ | GPUBufferUsage.COPY_DST, }); const storageBuffer = device.createBuffer({ label: "Storage Buffer", size: size, - usage: 0x80 | 8 | 4, + usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST | GPUBufferUsage.COPY_SRC, mappedAtCreation: true, }); From 4257f2d29380549a122609f068f223a8db36eaad Mon Sep 17 00:00:00 2001 From: Aaron O'Mullan Date: Tue, 18 Jan 2022 17:40:49 +0100 Subject: [PATCH 12/16] fmt --- cli/tests/unit/webgpu_test.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cli/tests/unit/webgpu_test.ts b/cli/tests/unit/webgpu_test.ts index 917acc87b339b0..b1b3b1ecbc847f 100644 --- a/cli/tests/unit/webgpu_test.ts +++ b/cli/tests/unit/webgpu_test.ts @@ -39,7 +39,8 @@ Deno.test({ const storageBuffer = device.createBuffer({ label: "Storage Buffer", size: size, - usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST | GPUBufferUsage.COPY_SRC, + usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST | + GPUBufferUsage.COPY_SRC, mappedAtCreation: true, }); From 4dc5f2af92dd2e40314c26a3699b6258ad015431 Mon Sep 17 00:00:00 2001 From: crowlkats Date: Tue, 18 Jan 2022 18:25:31 +0100 Subject: [PATCH 13/16] update typings --- cli/dts/lib.deno_webgpu.d.ts | 62 +++++++++++++++++++++++++++++------- 1 file changed, 51 insertions(+), 11 deletions(-) diff --git a/cli/dts/lib.deno_webgpu.d.ts b/cli/dts/lib.deno_webgpu.d.ts index 001b3c1f003a19..8ea8fb0e83f3d2 100644 --- a/cli/dts/lib.deno_webgpu.d.ts +++ b/cli/dts/lib.deno_webgpu.d.ts @@ -92,12 +92,15 @@ declare interface GPUDeviceDescriptor extends GPUObjectDescriptorBase { } declare type GPUFeatureName = - | "depth-clamping" + | "depth-clip-control" | "depth24unorm-stencil8" | "depth32float-stencil8" | "pipeline-statistics-query" | "texture-compression-bc" + | "texture-compression-etc2" + | "texture-compression-astc" | "timestamp-query" + | "indirect-first-instance" // extended from spec | "mappable-primary-buffers" | "sampled-texture-binding-array" @@ -108,9 +111,6 @@ declare type GPUFeatureName = | "multi-draw-indirect-count" | "push-constants" | "address-mode-clamp-to-border" - | "non-fill-polygon-mode" - | "texture-compression-etc2" - | "texture-compression-astc-ldr" | "texture-adapter-specific-format-features" | "shader-float64" | "vertex-attribute-64bit"; @@ -314,6 +314,44 @@ declare type GPUTextureFormat = | "bc6h-rgb-float" | "bc7-rgba-unorm" | "bc7-rgba-unorm-srgb" + | "etc2-rgb8unorm" + | "etc2-rgb8unorm-srgb" + | "etc2-rgb8a1unorm" + | "etc2-rgb8a1unorm-srgb" + | "etc2-rgba8unorm" + | "etc2-rgba8unorm-srgb" + | "eac-r11unorm" + | "eac-r11snorm" + | "eac-rg11unorm" + | "eac-rg11snorm" + | "astc-4x4-unorm" + | "astc-4x4-unorm-srgb" + | "astc-5x4-unorm" + | "astc-5x4-unorm-srgb" + | "astc-5x5-unorm" + | "astc-5x5-unorm-srgb" + | "astc-6x5-unorm" + | "astc-6x5-unorm-srgb" + | "astc-6x6-unorm" + | "astc-6x6-unorm-srgb" + | "astc-8x5-unorm" + | "astc-8x5-unorm-srgb" + | "astc-8x6-unorm" + | "astc-8x6-unorm-srgb" + | "astc-8x8-unorm" + | "astc-8x8-unorm-srgb" + | "astc-10x5-unorm" + | "astc-10x5-unorm-srgb" + | "astc-10x6-unorm" + | "astc-10x6-unorm-srgb" + | "astc-10x8-unorm" + | "astc-10x8-unorm-srgb" + | "astc-10x10-unorm" + | "astc-10x10-unorm-srgb" + | "astc-12x10-unorm" + | "astc-12x10-unorm-srgb" + | "astc-12x12-unorm" + | "astc-12x12-unorm-srgb" | "depth24unorm-stencil8" | "depth32float-stencil8"; @@ -519,7 +557,7 @@ declare interface GPUPrimitiveState { stripIndexFormat?: GPUIndexFormat; frontFace?: GPUFrontFace; cullMode?: GPUCullMode; - clampDepth?: boolean; + unclippedDepth?: boolean; } declare type GPUFrontFace = "ccw" | "cw"; @@ -558,9 +596,9 @@ declare class GPUColorWrite { } declare interface GPUBlendComponent { + operation: GPUBlendOperation; srcFactor: GPUBlendFactor; dstFactor: GPUBlendFactor; - operation: GPUBlendOperation; } declare type GPUBlendFactor = @@ -673,8 +711,6 @@ declare interface GPUVertexAttribute { declare class GPUCommandBuffer implements GPUObjectBase { label: string | null; - - readonly executionTime: Promise; } declare interface GPUCommandBufferDescriptor extends GPUObjectDescriptorBase {} @@ -713,6 +749,12 @@ declare class GPUCommandEncoder implements GPUObjectBase { copySize: GPUExtent3D, ): undefined; + clearBuffer( + destination: GPUBuffer, + destinationOffset: number, + size: number, + ): undefined; + pushDebugGroup(groupLabel: string): undefined; popDebugGroup(): undefined; insertDebugMarker(markerLabel: string): undefined; @@ -730,9 +772,7 @@ declare class GPUCommandEncoder implements GPUObjectBase { finish(descriptor?: GPUCommandBufferDescriptor): GPUCommandBuffer; } -declare interface GPUCommandEncoderDescriptor extends GPUObjectDescriptorBase { - measureExecutionTime?: boolean; -} +declare interface GPUCommandEncoderDescriptor extends GPUObjectDescriptorBase {} declare interface GPUImageDataLayout { offset?: number; From ef00f37814c1e0adc70c6b6d44dd59bd10bd2c2f Mon Sep 17 00:00:00 2001 From: Aaron O'Mullan Date: Tue, 18 Jan 2022 18:29:21 +0100 Subject: [PATCH 14/16] patch the extension's js prefix path --- ext/webgpu/src/lib.rs | 2 +- tools/wgpu_sync.js | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/ext/webgpu/src/lib.rs b/ext/webgpu/src/lib.rs index 2f7fb31d04350b..27bd1792ce83ef 100644 --- a/ext/webgpu/src/lib.rs +++ b/ext/webgpu/src/lib.rs @@ -108,7 +108,7 @@ impl Resource for WebGpuQuerySet { pub fn init(unstable: bool) -> Extension { Extension::builder() .js(include_js_files!( - prefix "deno:deno_webgpu", + prefix "deno:ext/webgpu", "01_webgpu.js", "02_idl_types.js", )) diff --git a/tools/wgpu_sync.js b/tools/wgpu_sync.js index addf1198794f33..f8ed79cf11e0ab 100755 --- a/tools/wgpu_sync.js +++ b/tools/wgpu_sync.js @@ -61,10 +61,22 @@ async function patchCargo() { await Deno.writeTextFile(webgpuCargo, patched); } +async function patchSrcLib() { + const srcLib = join(ROOT_PATH, "ext", "webgpu", "src", "lib.rs"); + const data = await Deno.readTextFile(srcLib); + + // Patch ext/webgpu/src/lib.rs's contents + const patched = data + .replace(`prefix "deno:deno_webgpu",`, `prefix "deno:ext/webgpu",`); + + await Deno.writeTextFile(srcLib, patched); +} + async function main() { await clearTargetDir(); await checkoutUpstream(); await patchCargo(); + await patchSrcLib(); await bash(join(ROOT_PATH, "tools", "format.js")); } From d6e1b207e4fd89537dc5aeaebb4593a0568e03ec Mon Sep 17 00:00:00 2001 From: Aaron O'Mullan Date: Wed, 19 Jan 2022 13:05:07 +0100 Subject: [PATCH 15/16] README --- tools/README.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tools/README.md b/tools/README.md index 7bdf6f77a145a0..65cff694fa0494 100644 --- a/tools/README.md +++ b/tools/README.md @@ -59,3 +59,16 @@ So you can simply run `./tools/flamebench.js op_baseline bench_op_async` or Tip: the `[bench_filter]` argument doesn't have to be an exact bench name, you can use a shorthand or a partial match to profile a group of benches, e.g: `./tools/flamebench.js de v8` + +## wgpu_sync.js + +`wgpu_sync.js` streamlines updating `deno_webgpu` from +[gfx-rs/wgpu](https://github.com/gfx-rs/wgpu/). + +It essentially vendors the `deno_webgpu` tree with a few minor patches applied +on top, somewhat similar to `git subtree`. + +1. Update `COMMIT` in `./tools/wgpu_sync.js` +2. Run `./tools/wgpu_sync.js` +3. Double check changes, possibly patch +4. Commit & send a PR with the updates From 8d814dc3ab2790d0c6782c71ee897a8b3f1ea134 Mon Sep 17 00:00:00 2001 From: Aaron O'Mullan Date: Wed, 19 Jan 2022 13:13:37 +0100 Subject: [PATCH 16/16] read deno_core version from core/Cargo.toml --- tools/wgpu_sync.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/tools/wgpu_sync.js b/tools/wgpu_sync.js index f8ed79cf11e0ab..341cffc71301d6 100755 --- a/tools/wgpu_sync.js +++ b/tools/wgpu_sync.js @@ -7,7 +7,6 @@ import { join, ROOT_PATH } from "./util.js"; const COMMIT = "cdd480a89c9e3b681d9d174e65082d2bdbc903ef"; // tip const REPO = "gfx-rs/wgpu"; // const V_WGPU = "0.12.0"; -const V_DENO_CORE = "0.114.0"; const TARGET_DIR = join(ROOT_PATH, "ext", "webgpu"); async function bash(subcmd, opts = {}) { @@ -35,7 +34,15 @@ async function checkoutUpstream() { await bash(cmd); } +async function denoCoreVersion() { + const coreCargo = join(ROOT_PATH, "core", "Cargo.toml"); + const contents = await Deno.readTextFile(coreCargo); + return contents.match(/^version = "(\d+\.\d+\.\d+)"$/m)[1]; +} + async function patchCargo() { + const vDenoCore = await denoCoreVersion(); + const webgpuCargo = join(ROOT_PATH, "ext", "webgpu", "Cargo.toml"); const data = await Deno.readTextFile(webgpuCargo); @@ -45,7 +52,7 @@ async function patchCargo() { .replace(`edition = "2018"`, `edition = "2021"`) .replace( /^deno_core \= .*$/gm, - `deno_core = { version = "${V_DENO_CORE}", path = "../../core" }`, + `deno_core = { version = "${vDenoCore}", path = "../../core" }`, ) // .replace(/^wgpu-core \= .*$/gm, `wgpu-core = { version = "${V_WGPU}", features = ["trace", "replay", "serde"] }`) // .replace(/^wgpu-types \= .*$/gm, `wgpu-types = { version = "${V_WGPU}", features = ["trace", "replay", "serde"] }`)