diff --git a/Cargo.lock b/Cargo.lock index 1e28756c5ae832..eabbaa96c4b8c9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -136,9 +136,9 @@ dependencies = [ [[package]] name = "ash" -version = "0.35.0+1.2.203" +version = "0.33.3+1.2.191" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a7638ce84f8c84d6fd6faa63aa267574d345181ba591c0eeb5550d4c30cd600" +checksum = "cc4f1d82f164f838ae413296d1131aa6fa79b917d25bebaa7033d25620c09219" dependencies = [ "libloading", ] @@ -283,16 +283,6 @@ 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" @@ -1438,6 +1428,12 @@ 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" @@ -1801,12 +1797,6 @@ 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" @@ -2317,7 +2307,8 @@ dependencies = [ [[package]] name = "metal" version = "0.23.1" -source = "git+https://github.com/gfx-rs/metal-rs?rev=140c8f4#140c8f4e39001ae154f153ffc767da6c0c9d7f06" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0514f491f4cc03632ab399ee01e2c1c1b12d3e1cf2d667c1ff5f87d6dcd2084" dependencies = [ "bitflags", "block", @@ -2367,17 +2358,17 @@ dependencies = [ [[package]] name = "naga" -version = "0.8.0" -source = "git+https://github.com/gfx-rs/naga?rev=a1840be#a1840beb1a96c9a49980fe3efa8e2f3dcd88abe6" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c5859e55c51da10b98e7a73068e0a0c5da7bbcae4fc38f86043d0c6d1b917cf" dependencies = [ "bit-set", "bitflags", "codespan-reporting", - "hexf-parse", - "indexmap", + "fxhash", "log", "num-traits", - "rustc-hash", + "petgraph 0.6.0", "serde", "spirv", "thiserror", @@ -2669,7 +2660,17 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "467d164a6de56270bd7c4d070df81d07beace25012d5103ced4e9ff08d6afdb7" dependencies = [ - "fixedbitset", + "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", "indexmap", ] @@ -3037,6 +3038,16 @@ 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" @@ -3172,9 +3183,9 @@ dependencies = [ [[package]] name = "ron" -version = "0.7.0" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b861ecaade43ac97886a512b360d01d66be9f41f3c61088b42cedf92e03d678" +checksum = "86018df177b1beef6c7c8ef949969c4f7cb9a9344181b92486b23c79995bdaa4" dependencies = [ "base64 0.13.0", "bitflags", @@ -3719,7 +3730,7 @@ dependencies = [ "is-macro", "once_cell", "parking_lot", - "petgraph", + "petgraph 0.5.1", "radix_fmt", "relative-path", "retain_mut", @@ -4070,7 +4081,7 @@ checksum = "1d53bbcbb4b055c547f283af1f84211f425b95ac59e02d8b70c94b8a63a4704f" dependencies = [ "ahash", "indexmap", - "petgraph", + "petgraph 0.5.1", "swc_common", ] @@ -4082,7 +4093,7 @@ checksum = "83b42a8b13068dd90dec954ec44576d5922914687bc34277f3b0f8d0bbeb4e83" dependencies = [ "ahash", "auto_impl", - "petgraph", + "petgraph 0.5.1", "swc_fast_graph", "tracing", ] @@ -4892,13 +4903,13 @@ dependencies = [ [[package]] name = "wgpu-core" -version = "0.12.0" -source = "git+https://github.com/gfx-rs/wgpu?rev=cdd480a89c9e3b681d9d174e65082d2bdbc903ef#cdd480a89c9e3b681d9d174e65082d2bdbc903ef" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f963c62473a36e3cef6c58181f2ed6d0d38d2043d970dbed46cb197190090c99" dependencies = [ "arrayvec 0.7.2", "bitflags", "cfg_aliases", - "codespan-reporting", "copyless", "fxhash", "log", @@ -4915,8 +4926,9 @@ dependencies = [ [[package]] name = "wgpu-hal" -version = "0.12.0" -source = "git+https://github.com/gfx-rs/wgpu?rev=cdd480a89c9e3b681d9d174e65082d2bdbc903ef#cdd480a89c9e3b681d9d174e65082d2bdbc903ef" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27cd894b17bff1958ee93da1cc991fd64bf99667746d4bd2a7403855f4d37fe2" dependencies = [ "arrayvec 0.7.2", "ash", @@ -4931,7 +4943,6 @@ dependencies = [ "gpu-alloc", "gpu-descriptor", "inplace_it", - "js-sys", "khronos-egl", "libloading", "log", @@ -4939,24 +4950,21 @@ dependencies = [ "naga", "objc", "parking_lot", - "profiling", "range-alloc", - "raw-window-handle", + "raw-window-handle 0.3.4", "renderdoc-sys", "thiserror", - "wasm-bindgen", - "web-sys", "wgpu-types", "winapi 0.3.9", ] [[package]] name = "wgpu-types" -version = "0.12.0" -source = "git+https://github.com/gfx-rs/wgpu?rev=cdd480a89c9e3b681d9d174e65082d2bdbc903ef#cdd480a89c9e3b681d9d174e65082d2bdbc903ef" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25feb2fbf24ab3219a9f10890ceb8e1ef02b13314ed89d64a9ae99dcad883e18" dependencies = [ "bitflags", - "bitflags_serde_shim", "serde", ] diff --git a/cli/build.rs b/cli/build.rs index 2daeffa0d780de..87c68848044150 100644 --- a/cli/build.rs +++ b/cli/build.rs @@ -82,7 +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.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()); @@ -322,7 +322,7 @@ fn main() { ); println!( "cargo:rustc-env=DENO_WEBGPU_LIB_PATH={}", - deno_webgpu_get_declaration().display() + deno_webgpu::get_declaration().display() ); println!( "cargo:rustc-env=DENO_WEBSOCKET_LIB_PATH={}", @@ -369,11 +369,6 @@ 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/tests/testdata/webgpu_computepass_shader.wgsl b/cli/tests/testdata/webgpu_computepass_shader.wgsl index df541aff5e29c1..9fc79eeba6c565 100644 --- a/cli/tests/testdata/webgpu_computepass_shader.wgsl +++ b/cli/tests/testdata/webgpu_computepass_shader.wgsl @@ -1,10 +1,9 @@ +[[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 @@ -26,14 +25,12 @@ 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 b1b3b1ecbc847f..1d54d7b02667b9 100644 --- a/cli/tests/unit/webgpu_test.ts +++ b/cli/tests/unit/webgpu_test.ts @@ -33,14 +33,13 @@ Deno.test({ const stagingBuffer = device.createBuffer({ size: size, - usage: GPUBufferUsage.MAP_READ | GPUBufferUsage.COPY_DST, + usage: 1 | 8, }); const storageBuffer = device.createBuffer({ label: "Storage Buffer", size: size, - usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST | - GPUBufferUsage.COPY_SRC, + usage: 0x80 | 8 | 4, mappedAtCreation: true, }); diff --git a/ext/webgpu/01_webgpu.js b/ext/webgpu/01_webgpu.js index 45d910c1a2cd0a..f1d3eb120a3735 100644 --- a/ext/webgpu/01_webgpu.js +++ b/ext/webgpu/01_webgpu.js @@ -3060,48 +3060,6 @@ 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 */ @@ -3245,7 +3203,7 @@ prefix, context: "Argument 3", }); - destination = webidl.converters.GPUBuffer(destination, { + destination = webidl.converters.GPUQuerySet(destination, { prefix, context: "Argument 4", }); @@ -4569,10 +4527,15 @@ 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 }) }`; } diff --git a/ext/webgpu/02_idl_types.js b/ext/webgpu/02_idl_types.js index bc92bebab07e04..3c49c18884bb4b 100644 --- a/ext/webgpu/02_idl_types.js +++ b/ext/webgpu/02_idl_types.js @@ -111,35 +111,28 @@ webidl.converters["GPUFeatureName"] = webidl.createEnumConverter( "GPUFeatureName", [ - "depth-clip-control", + "depth-clamping", "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", - "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", + "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", - "conservative-rasterization", - "vertex-writable-storage", - "clear-commands", - "spirv-shader-passthrough", - "shader-primitive-index", ], ); @@ -355,44 +348,6 @@ "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", ], @@ -1176,7 +1131,7 @@ defaultValue: "none", }, { - key: "unclippedDepth", + key: "clampDepth", converter: webidl.converters["boolean"], defaultValue: false, }, @@ -1503,7 +1458,13 @@ ); // DICTIONARY: GPUCommandEncoderDescriptor - const dictMembersGPUCommandEncoderDescriptor = []; + const dictMembersGPUCommandEncoderDescriptor = [ + { + key: "measureExecutionTime", + converter: webidl.converters["boolean"], + defaultValue: false, + }, + ]; webidl.converters["GPUCommandEncoderDescriptor"] = webidl .createDictionaryConverter( "GPUCommandEncoderDescriptor", diff --git a/ext/webgpu/Cargo.toml b/ext/webgpu/Cargo.toml index fa1228ff01fc7c..284f81278a8594 100644 --- a/ext/webgpu/Cargo.toml +++ b/ext/webgpu/Cargo.toml @@ -7,12 +7,15 @@ authors = ["the Deno authors"] edition = "2021" license = "MIT" readme = "README.md" -repository = "https://github.com/gfx-rs/wgpu" +repository = "https://github.com/denoland/deno" description = "WebGPU implementation for Deno" +[lib] +path = "lib.rs" + [dependencies] 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 = "cdd480a89c9e3b681d9d174e65082d2bdbc903ef", features = ["trace", "replay", "serde"] } -wgpu-types = { git = "https://github.com/gfx-rs/wgpu", rev = "cdd480a89c9e3b681d9d174e65082d2bdbc903ef", features = ["trace", "replay", "serde"] } +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" diff --git a/ext/webgpu/src/binding.rs b/ext/webgpu/binding.rs similarity index 88% rename from ext/webgpu/src/binding.rs rename to ext/webgpu/binding.rs index 9a8fa455f239af..fea99fc163583a 100644 --- a/ext/webgpu/src/binding.rs +++ b/ext/webgpu/binding.rs @@ -5,7 +5,8 @@ use deno_core::ResourceId; use deno_core::{OpState, Resource}; use serde::Deserialize; use std::borrow::Cow; -use std::convert::{TryFrom, TryInto}; + +use crate::texture::{GpuTextureFormat, GpuTextureViewDimension}; use super::error::WebGpuResult; @@ -58,14 +59,41 @@ impl From for wgpu_types::BufferBindingType { #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct GpuSamplerBindingLayout { - r#type: wgpu_types::SamplerBindingType, + 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: wgpu_types::TextureViewDimension, + view_dimension: GpuTextureViewDimension, multisampled: bool, } @@ -99,8 +127,8 @@ impl From for wgpu_types::TextureSampleType { #[serde(rename_all = "camelCase")] struct GpuStorageTextureBindingLayout { access: GpuStorageTextureAccess, - format: wgpu_types::TextureFormat, - view_dimension: wgpu_types::TextureViewDimension, + format: GpuTextureFormat, + view_dimension: GpuTextureViewDimension, } #[derive(Deserialize)] @@ -149,19 +177,17 @@ impl TryFrom for wgpu_types::BindingType { 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::Sampler(sampler) => sampler.r#type.into(), GpuBindingType::Texture(texture) => wgpu_types::BindingType::Texture { sample_type: texture.sample_type.into(), - view_dimension: texture.view_dimension, + 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, - view_dimension: storage_texture.view_dimension, + format: storage_texture.format.try_into()?, + view_dimension: storage_texture.view_dimension.into(), } } }; diff --git a/ext/webgpu/src/buffer.rs b/ext/webgpu/buffer.rs similarity index 100% rename from ext/webgpu/src/buffer.rs rename to ext/webgpu/buffer.rs diff --git a/ext/webgpu/src/bundle.rs b/ext/webgpu/bundle.rs similarity index 97% rename from ext/webgpu/src/bundle.rs rename to ext/webgpu/bundle.rs index ea327651a51448..7b32c1ecefc1c9 100644 --- a/ext/webgpu/src/bundle.rs +++ b/ext/webgpu/bundle.rs @@ -9,6 +9,9 @@ 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( @@ -32,8 +35,8 @@ impl Resource for WebGpuRenderBundle { pub struct CreateRenderBundleEncoderArgs { device_rid: ResourceId, label: Option, - color_formats: Vec, - depth_stencil_format: Option, + color_formats: Vec, + depth_stencil_format: Option, sample_count: u32, depth_read_only: bool, stencil_read_only: bool, @@ -52,12 +55,12 @@ pub fn op_webgpu_create_render_bundle_encoder( let mut color_formats = vec![]; for format in args.color_formats { - color_formats.push(format); + color_formats.push(format.try_into()?); } let depth_stencil = if let Some(format) = args.depth_stencil_format { Some(wgpu_types::RenderBundleDepthStencil { - format, + format: format.try_into()?, depth_read_only: args.depth_read_only, stencil_read_only: args.stencil_read_only, }) @@ -70,7 +73,6 @@ pub fn op_webgpu_create_render_bundle_encoder( color_formats: Cow::from(color_formats), sample_count: args.sample_count, depth_stencil, - multiview: None, }; let res = @@ -299,7 +301,7 @@ pub fn op_webgpu_render_bundle_encoder_set_pipeline( pub struct RenderBundleEncoderSetIndexBufferArgs { render_bundle_encoder_rid: ResourceId, buffer: ResourceId, - index_format: wgpu_types::IndexFormat, + index_format: GpuIndexFormat, offset: u64, size: u64, } @@ -322,7 +324,7 @@ pub fn op_webgpu_render_bundle_encoder_set_index_buffer( .borrow_mut() .set_index_buffer( buffer_resource.0, - args.index_format, + args.index_format.into(), args.offset, std::num::NonZeroU64::new(args.size), ); diff --git a/ext/webgpu/src/command_encoder.rs b/ext/webgpu/command_encoder.rs similarity index 89% rename from ext/webgpu/src/command_encoder.rs rename to ext/webgpu/command_encoder.rs index 894b08f274de20..cbd57f694e8015 100644 --- a/ext/webgpu/src/command_encoder.rs +++ b/ext/webgpu/command_encoder.rs @@ -8,6 +8,8 @@ use std::borrow::Cow; use std::cell::RefCell; use std::num::NonZeroU32; +use crate::texture::GpuTextureAspect; + use super::error::WebGpuResult; pub(crate) struct WebGpuCommandEncoder( @@ -63,8 +65,8 @@ pub fn op_webgpu_create_command_encoder( pub struct GpuRenderPassColorAttachment { view: ResourceId, resolve_target: Option, - load_op: GpuLoadOp, - store_op: wgpu_core::command::StoreOp, + load_op: GpuLoadOp, + store_op: GpuStoreOp, } #[derive(Deserialize)] @@ -74,15 +76,31 @@ enum GpuLoadOp { 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: wgpu_core::command::StoreOp, + depth_store_op: GpuStoreOp, depth_read_only: bool, stencil_load_op: GpuLoadOp, - stencil_store_op: wgpu_core::command::StoreOp, + stencil_store_op: GpuStoreOp, stencil_read_only: bool, } @@ -129,14 +147,19 @@ pub fn op_webgpu_command_encoder_begin_render_pass( 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, + 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, - clear_value: color, + 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, }, }, @@ -159,13 +182,13 @@ pub fn op_webgpu_command_encoder_begin_render_pass( 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, + 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, + store_op: attachment.depth_store_op.into(), clear_value: value, read_only: attachment.depth_read_only, }, @@ -173,13 +196,13 @@ pub fn op_webgpu_command_encoder_begin_render_pass( 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, + 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, + store_op: attachment.stencil_store_op.into(), clear_value: value, read_only: attachment.stencil_read_only, }, @@ -292,13 +315,31 @@ pub struct GpuImageCopyBuffer { 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: wgpu_types::Origin3d, - pub aspect: wgpu_types::TextureAspect, + pub origin: GpuOrigin3D, + pub aspect: GpuTextureAspect, } #[derive(Deserialize)] @@ -307,7 +348,7 @@ pub struct CommandEncoderCopyBufferToTextureArgs { command_encoder_rid: ResourceId, source: GpuImageCopyBuffer, destination: GpuImageCopyTexture, - copy_size: wgpu_types::Extent3d, + copy_size: super::texture::GpuExtent3D, } pub fn op_webgpu_command_encoder_copy_buffer_to_texture( @@ -340,14 +381,14 @@ pub fn op_webgpu_command_encoder_copy_buffer_to_texture( 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, + 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 + &args.copy_size.into() )) } @@ -357,7 +398,7 @@ pub struct CommandEncoderCopyTextureToBufferArgs { command_encoder_rid: ResourceId, source: GpuImageCopyTexture, destination: GpuImageCopyBuffer, - copy_size: wgpu_types::Extent3d, + copy_size: super::texture::GpuExtent3D, } pub fn op_webgpu_command_encoder_copy_texture_to_buffer( @@ -382,8 +423,8 @@ pub fn op_webgpu_command_encoder_copy_texture_to_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, + origin: args.source.origin.into(), + aspect: args.source.aspect.into(), }; let destination = wgpu_core::command::ImageCopyBuffer { buffer: destination_buffer_resource.0, @@ -401,7 +442,7 @@ pub fn op_webgpu_command_encoder_copy_texture_to_buffer( command_encoder, &source, &destination, - &args.copy_size + &args.copy_size.into() )) } @@ -411,7 +452,7 @@ pub struct CommandEncoderCopyTextureToTextureArgs { command_encoder_rid: ResourceId, source: GpuImageCopyTexture, destination: GpuImageCopyTexture, - copy_size: wgpu_types::Extent3d, + copy_size: super::texture::GpuExtent3D, } pub fn op_webgpu_command_encoder_copy_texture_to_texture( @@ -436,51 +477,20 @@ pub fn op_webgpu_command_encoder_copy_texture_to_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, + 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, - aspect: args.destination.aspect, + 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 - )) -} - -#[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) + &args.copy_size.into() )) } diff --git a/ext/webgpu/src/compute_pass.rs b/ext/webgpu/compute_pass.rs similarity index 98% rename from ext/webgpu/src/compute_pass.rs rename to ext/webgpu/compute_pass.rs index 03d9163cb207c2..e52db461c7a8bf 100644 --- a/ext/webgpu/src/compute_pass.rs +++ b/ext/webgpu/compute_pass.rs @@ -125,10 +125,10 @@ pub fn op_webgpu_compute_pass_begin_pipeline_statistics_query( .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, - ); + &mut compute_pass_resource.0.borrow_mut(), + query_set_resource.0, + args.query_index, + ); Ok(WebGpuResult::empty()) } @@ -149,8 +149,8 @@ pub fn op_webgpu_compute_pass_end_pipeline_statistics_query( .get::(args.compute_pass_rid)?; wgpu_core::command::compute_ffi::wgpu_compute_pass_end_pipeline_statistics_query( - &mut compute_pass_resource.0.borrow_mut(), - ); + &mut compute_pass_resource.0.borrow_mut(), + ); Ok(WebGpuResult::empty()) } diff --git a/ext/webgpu/src/error.rs b/ext/webgpu/error.rs similarity index 97% rename from ext/webgpu/src/error.rs rename to ext/webgpu/error.rs index ae6e480546a396..18ffdf1a8225ed 100644 --- a/ext/webgpu/src/error.rs +++ b/ext/webgpu/error.rs @@ -8,7 +8,6 @@ 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; @@ -259,12 +258,6 @@ impl From for WebGpuError { } } -impl From for WebGpuError { - fn from(err: ClearError) -> Self { - WebGpuError::Validation(err.to_string()) - } -} - #[derive(Debug)] pub struct DomExceptionOperationError { pub msg: String, diff --git a/cli/dts/lib.deno_webgpu.d.ts b/ext/webgpu/lib.deno_webgpu.d.ts similarity index 95% rename from cli/dts/lib.deno_webgpu.d.ts rename to ext/webgpu/lib.deno_webgpu.d.ts index 1337b3f5e26f59..6d480d3c3ab4a4 100644 --- a/cli/dts/lib.deno_webgpu.d.ts +++ b/ext/webgpu/lib.deno_webgpu.d.ts @@ -92,15 +92,12 @@ declare interface GPUDeviceDescriptor extends GPUObjectDescriptorBase { } declare type GPUFeatureName = - | "depth-clip-control" + | "depth-clamping" | "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" @@ -111,6 +108,9 @@ 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,44 +314,6 @@ 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"; @@ -557,7 +519,7 @@ declare interface GPUPrimitiveState { stripIndexFormat?: GPUIndexFormat; frontFace?: GPUFrontFace; cullMode?: GPUCullMode; - unclippedDepth?: boolean; + clampDepth?: boolean; } declare type GPUFrontFace = "ccw" | "cw"; @@ -596,9 +558,9 @@ declare class GPUColorWrite { } declare interface GPUBlendComponent { - operation: GPUBlendOperation; srcFactor: GPUBlendFactor; dstFactor: GPUBlendFactor; + operation: GPUBlendOperation; } declare type GPUBlendFactor = @@ -711,6 +673,8 @@ declare interface GPUVertexAttribute { declare class GPUCommandBuffer implements GPUObjectBase { label: string | null; + + readonly executionTime: Promise; } declare interface GPUCommandBufferDescriptor extends GPUObjectDescriptorBase {} @@ -749,12 +713,6 @@ 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; @@ -772,7 +730,9 @@ declare class GPUCommandEncoder implements GPUObjectBase { finish(descriptor?: GPUCommandBufferDescriptor): GPUCommandBuffer; } -declare interface GPUCommandEncoderDescriptor extends GPUObjectDescriptorBase {} +declare interface GPUCommandEncoderDescriptor extends GPUObjectDescriptorBase { + measureExecutionTime?: boolean; +} declare interface GPUImageDataLayout { offset?: number; diff --git a/ext/webgpu/src/lib.rs b/ext/webgpu/lib.rs similarity index 68% rename from ext/webgpu/src/lib.rs rename to ext/webgpu/lib.rs index 77bb10a6065067..81f84f6bf934ee 100644 --- a/ext/webgpu/src/lib.rs +++ b/ext/webgpu/lib.rs @@ -14,6 +14,7 @@ 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; @@ -124,11 +125,15 @@ pub fn init(unstable: bool) -> Extension { .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_CLIP_CONTROL) { - return_features.push("depth-clip-control"); + 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"); @@ -136,18 +141,9 @@ fn deserialize_features(features: &wgpu_types::Features) -> Vec<&'static str> { 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) { @@ -162,16 +158,12 @@ fn deserialize_features(features: &wgpu_types::Features) -> Vec<&'static str> { 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::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"); } @@ -187,6 +179,15 @@ fn deserialize_features(features: &wgpu_types::Features) -> Vec<&'static str> { 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) { @@ -204,8 +205,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_TEXTURE) { - return_features.push("clear-texture"); + 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"); @@ -217,11 +218,28 @@ fn deserialize_features(features: &wgpu_types::Features) -> Vec<&'static str> { 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, - force_fallback_adapter: bool, + power_preference: Option, } #[derive(Serialize)] @@ -248,35 +266,31 @@ pub async fn op_webgpu_request_adapter( ) -> 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, + wgpu_types::Backends::PRIMARY, )); state.borrow::() }; let descriptor = wgpu_core::instance::RequestAdapterOptions { power_preference: match args.power_preference { - Some(power_preference) => power_preference, + Some(power_preference) => power_preference.into(), None => PowerPreference::default(), }, - force_fallback_adapter: args.force_fallback_adapter, + // TODO(lucacasonato): respect forceFallbackAdapter compatible_surface: None, // windowless }; let res = instance.request_adapter( &descriptor, - wgpu_core::instance::AdapterInputs::Mask(backends, |_| { - std::marker::PhantomData - }), + wgpu_core::instance::AdapterInputs::Mask( + wgpu_types::Backends::PRIMARY, + |_| std::marker::PhantomData, + ), ); let adapter = match res { @@ -305,13 +319,116 @@ pub async fn op_webgpu_request_adapter( })) } +#[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, + required_limits: Option, } #[derive(Deserialize)] @@ -320,120 +437,101 @@ 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"), - ); + + 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 - 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_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"), - ); + 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 } @@ -677,10 +775,6 @@ fn declare_webgpu_ops() -> Vec<(&'static str, Box)> { 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), @@ -801,22 +895,6 @@ fn declare_webgpu_ops() -> Vec<(&'static str, Box)> { "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), diff --git a/ext/webgpu/pipeline.rs b/ext/webgpu/pipeline.rs new file mode 100644 index 00000000000000..1d22bdba0da19e --- /dev/null +++ b/ext/webgpu/pipeline.rs @@ -0,0 +1,791 @@ +// 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/src/queue.rs b/ext/webgpu/queue.rs similarity index 96% rename from ext/webgpu/src/queue.rs rename to ext/webgpu/queue.rs index a662c4ead6f8eb..39bd936037c4af 100644 --- a/ext/webgpu/src/queue.rs +++ b/ext/webgpu/queue.rs @@ -108,7 +108,7 @@ pub struct QueueWriteTextureArgs { queue_rid: ResourceId, destination: super::command_encoder::GpuImageCopyTexture, data_layout: GpuImageDataLayout, - size: wgpu_types::Extent3d, + size: super::texture::GpuExtent3D, } pub fn op_webgpu_write_texture( @@ -127,8 +127,8 @@ pub fn op_webgpu_write_texture( let destination = wgpu_core::command::ImageCopyTexture { texture: texture_resource.0, mip_level: args.destination.mip_level, - origin: args.destination.origin, - aspect: args.destination.aspect, + origin: args.destination.origin.into(), + aspect: args.destination.aspect.into(), }; let data_layout = args.data_layout.into(); @@ -137,6 +137,6 @@ pub fn op_webgpu_write_texture( &destination, &*zero_copy, &data_layout, - &args.size + &args.size.into() )) } diff --git a/ext/webgpu/src/render_pass.rs b/ext/webgpu/render_pass.rs similarity index 96% rename from ext/webgpu/src/render_pass.rs rename to ext/webgpu/render_pass.rs index 469bf727e42b83..780b6ea577e4ed 100644 --- a/ext/webgpu/src/render_pass.rs +++ b/ext/webgpu/render_pass.rs @@ -9,6 +9,8 @@ use serde::Deserialize; use std::borrow::Cow; use std::cell::RefCell; +use crate::pipeline::GpuIndexFormat; + use super::error::WebGpuResult; pub(crate) struct WebGpuRenderPass( @@ -84,11 +86,20 @@ pub fn op_webgpu_render_pass_set_scissor_rect( 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: wgpu_types::Color, + color: GpuColor, } pub fn op_webgpu_render_pass_set_blend_constant( @@ -102,7 +113,12 @@ pub fn op_webgpu_render_pass_set_blend_constant( wgpu_core::command::render_ffi::wgpu_render_pass_set_blend_constant( &mut render_pass_resource.0.borrow_mut(), - &args.color, + &wgpu_types::Color { + r: args.color.r, + g: args.color.g, + b: args.color.b, + a: args.color.a, + }, ); Ok(WebGpuResult::empty()) @@ -153,10 +169,10 @@ pub fn op_webgpu_render_pass_begin_pipeline_statistics_query( .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, - ); + &mut render_pass_resource.0.borrow_mut(), + query_set_resource.0, + args.query_index, + ); Ok(WebGpuResult::empty()) } @@ -177,8 +193,8 @@ pub fn op_webgpu_render_pass_end_pipeline_statistics_query( .get::(args.render_pass_rid)?; wgpu_core::command::render_ffi::wgpu_render_pass_end_pipeline_statistics_query( - &mut render_pass_resource.0.borrow_mut(), - ); + &mut render_pass_resource.0.borrow_mut(), + ); Ok(WebGpuResult::empty()) } @@ -450,7 +466,7 @@ pub fn op_webgpu_render_pass_set_pipeline( pub struct RenderPassSetIndexBufferArgs { render_pass_rid: ResourceId, buffer: u32, - index_format: wgpu_types::IndexFormat, + index_format: GpuIndexFormat, offset: u64, size: Option, } @@ -478,7 +494,7 @@ pub fn op_webgpu_render_pass_set_index_buffer( render_pass_resource.0.borrow_mut().set_index_buffer( buffer_resource.0, - args.index_format, + args.index_format.into(), args.offset, size, ); diff --git a/ext/webgpu/sampler.rs b/ext/webgpu/sampler.rs new file mode 100644 index 00000000000000..23652cc4702c17 --- /dev/null +++ b/ext/webgpu/sampler.rs @@ -0,0 +1,132 @@ +// 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/src/shader.rs b/ext/webgpu/shader.rs similarity index 95% rename from ext/webgpu/src/shader.rs rename to ext/webgpu/shader.rs index 60290de8b0cb01..2477beceb965e5 100644 --- a/ext/webgpu/src/shader.rs +++ b/ext/webgpu/shader.rs @@ -40,7 +40,6 @@ pub fn op_webgpu_create_shader_module( 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( diff --git a/ext/webgpu/texture.rs b/ext/webgpu/texture.rs new file mode 100644 index 00000000000000..9b007b34d463e4 --- /dev/null +++ b/ext/webgpu/texture.rs @@ -0,0 +1,419 @@ +// 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 79d65791d4e6fa..02650699688999 100644 --- a/ext/webgpu/webgpu.idl +++ b/ext/webgpu/webgpu.idl @@ -6,7 +6,7 @@ dictionary GPUObjectDescriptorBase { USVString label; }; -[Exposed=(Window, DedicatedWorker), SecureContext] +[Exposed=(Window, DedicatedWorker)] 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), SecureContext] +[Exposed=(Window, DedicatedWorker)] interface GPUSupportedFeatures { readonly setlike; }; @@ -46,12 +46,12 @@ enum GPUPredefinedColorSpace { }; interface mixin NavigatorGPU { - [SameObject, SecureContext] readonly attribute GPU gpu; + [SameObject] readonly attribute GPU gpu; }; Navigator includes NavigatorGPU; WorkerNavigator includes NavigatorGPU; -[Exposed=(Window, DedicatedWorker), SecureContext] +[Exposed=(Window, DedicatedWorker)] interface GPU { Promise requestAdapter(optional GPURequestAdapterOptions options = {}); }; @@ -63,10 +63,10 @@ dictionary GPURequestAdapterOptions { enum GPUPowerPreference { "low-power", - "high-performance", + "high-performance" }; -[Exposed=(Window, DedicatedWorker), SecureContext] +[Exposed=(Window, DedicatedWorker)] interface GPUAdapter { readonly attribute DOMString name; [SameObject] readonly attribute GPUSupportedFeatures features; @@ -82,18 +82,15 @@ dictionary GPUDeviceDescriptor : GPUObjectDescriptorBase { }; enum GPUFeatureName { - "depth-clip-control", + "depth-clamping", "depth24unorm-stencil8", "depth32float-stencil8", "pipeline-statistics-query", "texture-compression-bc", - "texture-compression-etc2", - "texture-compression-astc", "timestamp-query", - "indirect-first-instance", }; -[Exposed=(Window, DedicatedWorker), SecureContext] +[Exposed=(Window, DedicatedWorker)] interface GPUDevice : EventTarget { [SameObject] readonly attribute GPUSupportedFeatures features; [SameObject] readonly attribute GPUSupportedLimits limits; @@ -123,7 +120,7 @@ interface GPUDevice : EventTarget { }; GPUDevice includes GPUObjectBase; -[Exposed=(Window, DedicatedWorker), SecureContext] +[Exposed=(Window, DedicatedWorker)] interface GPUBuffer { Promise mapAsync(GPUMapModeFlags mode, optional GPUSize64 offset = 0, optional GPUSize64 size); ArrayBuffer getMappedRange(optional GPUSize64 offset = 0, optional GPUSize64 size); @@ -161,7 +158,7 @@ interface GPUMapMode { const GPUFlagsConstant WRITE = 0x0002; }; -[Exposed=(Window, DedicatedWorker), SecureContext] +[Exposed=(Window, DedicatedWorker)] interface GPUTexture { GPUTextureView createView(optional GPUTextureViewDescriptor descriptor = {}); @@ -194,7 +191,7 @@ interface GPUTextureUsage { const GPUFlagsConstant RENDER_ATTACHMENT = 0x10; }; -[Exposed=(Window, DedicatedWorker), SecureContext] +[Exposed=(Window, DedicatedWorker)] interface GPUTextureView { }; GPUTextureView includes GPUObjectBase; @@ -215,13 +212,13 @@ enum GPUTextureViewDimension { "2d-array", "cube", "cube-array", - "3d", + "3d" }; enum GPUTextureAspect { "all", "stencil-only", - "depth-only", + "depth-only" }; enum GPUTextureFormat { @@ -296,50 +293,6 @@ 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", @@ -347,7 +300,7 @@ enum GPUTextureFormat { "depth32float-stencil8", }; -[Exposed=(Window, DedicatedWorker), SecureContext] +[Exposed=(Window, DedicatedWorker)] interface GPUSampler { }; GPUSampler includes GPUObjectBase; @@ -368,12 +321,12 @@ dictionary GPUSamplerDescriptor : GPUObjectDescriptorBase { enum GPUAddressMode { "clamp-to-edge", "repeat", - "mirror-repeat", + "mirror-repeat" }; enum GPUFilterMode { "nearest", - "linear", + "linear" }; enum GPUCompareFunction { @@ -384,10 +337,10 @@ enum GPUCompareFunction { "greater", "not-equal", "greater-equal", - "always", + "always" }; -[Exposed=(Window, DedicatedWorker), SecureContext] +[Exposed=(Window, DedicatedWorker)] interface GPUBindGroupLayout { }; GPUBindGroupLayout includes GPUObjectBase; @@ -437,11 +390,11 @@ dictionary GPUSamplerBindingLayout { }; enum GPUTextureSampleType { - "float", - "unfilterable-float", - "depth", - "sint", - "uint", + "float", + "unfilterable-float", + "depth", + "sint", + "uint", }; dictionary GPUTextureBindingLayout { @@ -460,7 +413,7 @@ dictionary GPUStorageTextureBindingLayout { GPUTextureViewDimension viewDimension = "2d"; }; -[Exposed=(Window, DedicatedWorker), SecureContext] +[Exposed=(Window, DedicatedWorker)] interface GPUBindGroup { }; GPUBindGroup includes GPUObjectBase; @@ -483,7 +436,7 @@ dictionary GPUBufferBinding { GPUSize64 size; }; -[Exposed=(Window, DedicatedWorker), SecureContext] +[Exposed=(Window, DedicatedWorker)] interface GPUPipelineLayout { }; GPUPipelineLayout includes GPUObjectBase; @@ -492,7 +445,7 @@ dictionary GPUPipelineLayoutDescriptor : GPUObjectDescriptorBase { required sequence bindGroupLayouts; }; -[Exposed=(Window, DedicatedWorker), SecureContext] +[Exposed=(Window, DedicatedWorker)] interface GPUShaderModule { Promise compilationInfo(); }; @@ -506,10 +459,10 @@ dictionary GPUShaderModuleDescriptor : GPUObjectDescriptorBase { enum GPUCompilationMessageType { "error", "warning", - "info", + "info" }; -[Exposed=(Window, DedicatedWorker), Serializable, SecureContext] +[Exposed=(Window, DedicatedWorker), Serializable] interface GPUCompilationMessage { readonly attribute DOMString message; readonly attribute GPUCompilationMessageType type; @@ -519,7 +472,7 @@ interface GPUCompilationMessage { readonly attribute unsigned long long length; }; -[Exposed=(Window, DedicatedWorker), Serializable, SecureContext] +[Exposed=(Window, DedicatedWorker), Serializable] interface GPUCompilationInfo { readonly attribute FrozenArray messages; }; @@ -540,7 +493,7 @@ dictionary GPUProgrammableStage { typedef double GPUPipelineConstantValue; // May represent WGSL’s bool, f32, i32, u32. -[Exposed=(Window, DedicatedWorker), SecureContext] +[Exposed=(Window, DedicatedWorker)] interface GPUComputePipeline { }; GPUComputePipeline includes GPUObjectBase; @@ -550,7 +503,7 @@ dictionary GPUComputePipelineDescriptor : GPUPipelineDescriptorBase { required GPUProgrammableStage compute; }; -[Exposed=(Window, DedicatedWorker), SecureContext] +[Exposed=(Window, DedicatedWorker)] interface GPURenderPipeline { }; GPURenderPipeline includes GPUObjectBase; @@ -569,7 +522,7 @@ enum GPUPrimitiveTopology { "line-list", "line-strip", "triangle-list", - "triangle-strip", + "triangle-strip" }; dictionary GPUPrimitiveState { @@ -578,19 +531,19 @@ dictionary GPUPrimitiveState { GPUFrontFace frontFace = "ccw"; GPUCullMode cullMode = "none"; - // Requires "depth-clip-control" feature. - boolean unclippedDepth = false; + // Enable depth clamping (requires "depth-clamping" feature) + boolean clampDepth = false; }; enum GPUFrontFace { "ccw", - "cw", + "cw" }; enum GPUCullMode { "none", "front", - "back", + "back" }; dictionary GPUMultisampleState { @@ -599,7 +552,7 @@ dictionary GPUMultisampleState { boolean alphaToCoverageEnabled = false; }; -dictionary GPUFragmentState : GPUProgrammableStage { +dictionary GPUFragmentState: GPUProgrammableStage { required sequence targets; }; @@ -626,9 +579,9 @@ interface GPUColorWrite { }; dictionary GPUBlendComponent { - GPUBlendOperation operation = "add"; GPUBlendFactor srcFactor = "one"; GPUBlendFactor dstFactor = "zero"; + GPUBlendOperation operation = "add"; }; enum GPUBlendFactor { @@ -644,7 +597,7 @@ enum GPUBlendFactor { "one-minus-dst-alpha", "src-alpha-saturated", "constant", - "one-minus-constant", + "one-minus-constant" }; enum GPUBlendOperation { @@ -652,7 +605,7 @@ enum GPUBlendOperation { "subtract", "reverse-subtract", "min", - "max", + "max" }; dictionary GPUDepthStencilState { @@ -687,12 +640,12 @@ enum GPUStencilOperation { "increment-clamp", "decrement-clamp", "increment-wrap", - "decrement-wrap", + "decrement-wrap" }; enum GPUIndexFormat { "uint16", - "uint32", + "uint32" }; enum GPUVertexFormat { @@ -730,10 +683,10 @@ enum GPUVertexFormat { enum GPUVertexStepMode { "vertex", - "instance", + "instance" }; -dictionary GPUVertexState : GPUProgrammableStage { +dictionary GPUVertexState: GPUProgrammableStage { sequence buffers = []; }; @@ -750,15 +703,16 @@ dictionary GPUVertexAttribute { required GPUIndex32 shaderLocation; }; -[Exposed=(Window, DedicatedWorker), SecureContext] +[Exposed=(Window, DedicatedWorker)] interface GPUCommandBuffer { + readonly attribute Promise executionTime; }; GPUCommandBuffer includes GPUObjectBase; dictionary GPUCommandBufferDescriptor : GPUObjectDescriptorBase { }; -[Exposed=(Window, DedicatedWorker), SecureContext] +[Exposed=(Window, DedicatedWorker)] interface GPUCommandEncoder { GPURenderPassEncoder beginRenderPass(GPURenderPassDescriptor descriptor); GPUComputePassEncoder beginComputePass(optional GPUComputePassDescriptor descriptor = {}); @@ -785,11 +739,6 @@ interface GPUCommandEncoder { GPUImageCopyTexture destination, GPUExtent3D copySize); - undefined clearBuffer( - GPUBuffer destination, - GPUSize64 destinationOffset, - GPUSize64 size); - undefined pushDebugGroup(USVString groupLabel); undefined popDebugGroup(); undefined insertDebugMarker(USVString markerLabel); @@ -808,6 +757,7 @@ interface GPUCommandEncoder { GPUCommandEncoder includes GPUObjectBase; dictionary GPUCommandEncoderDescriptor : GPUObjectDescriptorBase { + boolean measureExecutionTime = false; }; dictionary GPUImageDataLayout { @@ -841,7 +791,7 @@ interface mixin GPUProgrammablePassEncoder { undefined insertDebugMarker(USVString markerLabel); }; -[Exposed=(Window, DedicatedWorker), SecureContext] +[Exposed=(Window, DedicatedWorker)] interface GPUComputePassEncoder { undefined setPipeline(GPUComputePipeline pipeline); undefined dispatch(GPUSize32 x, optional GPUSize32 y = 1, optional GPUSize32 z = 1); @@ -877,7 +827,7 @@ interface mixin GPURenderEncoderBase { undefined drawIndexedIndirect(GPUBuffer indirectBuffer, GPUSize64 indirectOffset); }; -[Exposed=(Window, DedicatedWorker), SecureContext] +[Exposed=(Window, DedicatedWorker)] interface GPURenderPassEncoder { undefined setViewport(float x, float y, float width, float height, @@ -931,12 +881,12 @@ dictionary GPURenderPassDepthStencilAttachment { }; enum GPULoadOp { - "load", + "load" }; enum GPUStoreOp { "store", - "discard", + "discard" }; dictionary GPURenderPassLayout: GPUObjectDescriptorBase { @@ -945,7 +895,7 @@ dictionary GPURenderPassLayout: GPUObjectDescriptorBase { GPUSize32 sampleCount = 1; }; -[Exposed=(Window, DedicatedWorker), SecureContext] +[Exposed=(Window, DedicatedWorker)] interface GPURenderBundle { }; GPURenderBundle includes GPUObjectBase; @@ -953,7 +903,7 @@ GPURenderBundle includes GPUObjectBase; dictionary GPURenderBundleDescriptor : GPUObjectDescriptorBase { }; -[Exposed=(Window, DedicatedWorker), SecureContext] +[Exposed=(Window, DedicatedWorker)] interface GPURenderBundleEncoder { GPURenderBundle finish(optional GPURenderBundleDescriptor descriptor = {}); }; @@ -966,7 +916,7 @@ dictionary GPURenderBundleEncoderDescriptor : GPURenderPassLayout { boolean stencilReadOnly = false; }; -[Exposed=(Window, DedicatedWorker), SecureContext] +[Exposed=(Window, DedicatedWorker)] interface GPUQueue { undefined submit(sequence commandBuffers); @@ -980,14 +930,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), SecureContext] +[Exposed=(Window, DedicatedWorker)] interface GPUQuerySet { undefined destroy(); }; @@ -1002,7 +952,7 @@ dictionary GPUQuerySetDescriptor : GPUObjectDescriptorBase { enum GPUQueryType { "occlusion", "pipeline-statistics", - "timestamp", + "timestamp" }; enum GPUPipelineStatisticName { @@ -1010,14 +960,14 @@ enum GPUPipelineStatisticName { "clipper-invocations", "clipper-primitives-out", "fragment-shader-invocations", - "compute-shader-invocations", + "compute-shader-invocations" }; enum GPUDeviceLostReason { "destroyed", }; -[Exposed=(Window, DedicatedWorker), SecureContext] +[Exposed=(Window, DedicatedWorker)] interface GPUDeviceLostInfo { readonly attribute (GPUDeviceLostReason or undefined) reason; readonly attribute DOMString message; @@ -1029,15 +979,15 @@ partial interface GPUDevice { enum GPUErrorFilter { "out-of-memory", - "validation", + "validation" }; -[Exposed=(Window, DedicatedWorker), SecureContext] +[Exposed=(Window, DedicatedWorker)] interface GPUOutOfMemoryError { constructor(); }; -[Exposed=(Window, DedicatedWorker), SecureContext] +[Exposed=(Window, DedicatedWorker)] interface GPUValidationError { constructor(DOMString message); readonly attribute DOMString message; @@ -1050,7 +1000,9 @@ partial interface GPUDevice { Promise popErrorScope(); }; -[Exposed=(Window, DedicatedWorker), SecureContext] +[ + Exposed=(Window, DedicatedWorker) +] interface GPUUncapturedErrorEvent : Event { constructor( DOMString type, @@ -1108,4 +1060,3 @@ dictionary GPUExtent3DDict { GPUIntegerCoordinate depthOrArrayLayers = 1; }; typedef (sequence or GPUExtent3DDict) GPUExtent3D; - diff --git a/tools/README.md b/tools/README.md index 65cff694fa0494..7bdf6f77a145a0 100644 --- a/tools/README.md +++ b/tools/README.md @@ -59,16 +59,3 @@ 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 diff --git a/tools/wgpu_sync.js b/tools/wgpu_sync.js deleted file mode 100755 index 341cffc71301d6..00000000000000 --- a/tools/wgpu_sync.js +++ /dev/null @@ -1,90 +0,0 @@ -#!/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 COMMIT = "cdd480a89c9e3b681d9d174e65082d2bdbc903ef"; // tip -const REPO = "gfx-rs/wgpu"; -// const V_WGPU = "0.12.0"; -const TARGET_DIR = join(ROOT_PATH, "ext", "webgpu"); - -async function bash(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 bash(`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 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); - - // 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 = "${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"] }`) - .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); -} - -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")); -} - -await main();