From 31163e127031baa29138fa6280c0755269f3a5e8 Mon Sep 17 00:00:00 2001 From: Douglas Dwyer Date: Sat, 11 May 2024 11:46:47 -0400 Subject: [PATCH 1/3] Add support for pipeline-overridable constants in WebGPU --- CHANGELOG.md | 4 ++++ wgpu/src/backend/webgpu.rs | 28 ++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 88f8aade9f..713f626c76 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -76,6 +76,10 @@ By @stefnotch in [#5410](https://github.com/gfx-rs/wgpu/pull/5410) - Fix regression on OpenGL (EGL) where non-sRGB still used sRGB [#5642](https://github.com/gfx-rs/wgpu/pull/5642) +#### WebGPU + +- Added support for pipeline-overridable constants to the WebGPU backend by @DouglasDwyer in [#5688](https://github.com/gfx-rs/wgpu/pull/5688) + ## v0.20.0 (2024-04-28) ### Major Changes diff --git a/wgpu/src/backend/webgpu.rs b/wgpu/src/backend/webgpu.rs index 2185d5b8b8..6facfc8ef5 100644 --- a/wgpu/src/backend/webgpu.rs +++ b/wgpu/src/backend/webgpu.rs @@ -7,6 +7,7 @@ use js_sys::Promise; use std::{ any::Any, cell::RefCell, + collections::HashMap, fmt, future::Future, marker::PhantomData, @@ -1874,6 +1875,11 @@ impl crate::context::Context for ContextWebGpu { let module: &::ShaderModuleData = downcast_ref(desc.vertex.module.data.as_ref()); let mut mapped_vertex_state = webgpu_sys::GpuVertexState::new(&module.0.module); + let _ = js_sys::Reflect::set( + &mapped_vertex_state, + &"constants".into(), + &hashmap_to_jsvalue(desc.vertex.compilation_options.constants), + ); mapped_vertex_state.entry_point(desc.vertex.entry_point); let buffers = desc @@ -1950,6 +1956,11 @@ impl crate::context::Context for ContextWebGpu { downcast_ref(frag.module.data.as_ref()); let mut mapped_fragment_desc = webgpu_sys::GpuFragmentState::new(&module.0.module, &targets); + let _ = js_sys::Reflect::set( + &mapped_fragment_desc, + &"constants".into(), + &hashmap_to_jsvalue(frag.compilation_options.constants), + ); mapped_fragment_desc.entry_point(frag.entry_point); mapped_desc.fragment(&mapped_fragment_desc); } @@ -1976,6 +1987,11 @@ impl crate::context::Context for ContextWebGpu { downcast_ref(desc.module.data.as_ref()); let mut mapped_compute_stage = webgpu_sys::GpuProgrammableStage::new(&shader_module.0.module); + let _ = js_sys::Reflect::set( + &mapped_compute_stage, + &"constants".into(), + &hashmap_to_jsvalue(desc.compilation_options.constants), + ); mapped_compute_stage.entry_point(desc.entry_point); let auto_layout = wasm_bindgen::JsValue::from(webgpu_sys::GpuAutoLayoutMode::Auto); let mut mapped_desc = webgpu_sys::GpuComputePipelineDescriptor::new( @@ -1992,6 +2008,7 @@ impl crate::context::Context for ContextWebGpu { if let Some(label) = desc.label { mapped_desc.label(label); } + create_identified(device_data.0.create_compute_pipeline(&mapped_desc)) } @@ -3808,3 +3825,14 @@ impl Drop for BufferMappedRange { } } } + +/// Converts a hashmap to a Javascript object. +fn hashmap_to_jsvalue(map: &HashMap) -> JsValue { + let obj = js_sys::Object::new(); + + for (k, v) in map.iter() { + let _ = js_sys::Reflect::set(&obj, &k.into(), &(*v).into()); + } + + JsValue::from(obj) +} From 500a8b195ce04210a9f29096e51cff8f8b2339b1 Mon Sep 17 00:00:00 2001 From: Douglas Dwyer Date: Mon, 13 May 2024 21:06:03 -0400 Subject: [PATCH 2/3] Add utility function for setting constants map --- wgpu/src/backend/webgpu.rs | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/wgpu/src/backend/webgpu.rs b/wgpu/src/backend/webgpu.rs index 6facfc8ef5..7abb7ee7c9 100644 --- a/wgpu/src/backend/webgpu.rs +++ b/wgpu/src/backend/webgpu.rs @@ -1875,10 +1875,9 @@ impl crate::context::Context for ContextWebGpu { let module: &::ShaderModuleData = downcast_ref(desc.vertex.module.data.as_ref()); let mut mapped_vertex_state = webgpu_sys::GpuVertexState::new(&module.0.module); - let _ = js_sys::Reflect::set( + insert_constants_map( &mapped_vertex_state, - &"constants".into(), - &hashmap_to_jsvalue(desc.vertex.compilation_options.constants), + desc.vertex.compilation_options.constants, ); mapped_vertex_state.entry_point(desc.vertex.entry_point); @@ -1956,11 +1955,7 @@ impl crate::context::Context for ContextWebGpu { downcast_ref(frag.module.data.as_ref()); let mut mapped_fragment_desc = webgpu_sys::GpuFragmentState::new(&module.0.module, &targets); - let _ = js_sys::Reflect::set( - &mapped_fragment_desc, - &"constants".into(), - &hashmap_to_jsvalue(frag.compilation_options.constants), - ); + insert_constants_map(&mapped_vertex_state, frag.compilation_options.constants); mapped_fragment_desc.entry_point(frag.entry_point); mapped_desc.fragment(&mapped_fragment_desc); } @@ -1987,11 +1982,7 @@ impl crate::context::Context for ContextWebGpu { downcast_ref(desc.module.data.as_ref()); let mut mapped_compute_stage = webgpu_sys::GpuProgrammableStage::new(&shader_module.0.module); - let _ = js_sys::Reflect::set( - &mapped_compute_stage, - &"constants".into(), - &hashmap_to_jsvalue(desc.compilation_options.constants), - ); + insert_constants_map(&mapped_compute_stage, desc.compilation_options.constants); mapped_compute_stage.entry_point(desc.entry_point); let auto_layout = wasm_bindgen::JsValue::from(webgpu_sys::GpuAutoLayoutMode::Auto); let mut mapped_desc = webgpu_sys::GpuComputePipelineDescriptor::new( @@ -3826,12 +3817,30 @@ impl Drop for BufferMappedRange { } } +/// Adds the constants map to the given pipeline descriptor if the map is nonempty. +/// Logs an error if the map cannot be set. +/// +/// This function is necessary because the constants array is not currently +/// exposed by `wasm-bindgen`. See the following issues for details: +/// - [gfx-rs/wgpu#5688](https://github.com/gfx-rs/wgpu/pull/5688) +/// - [rustwasm/wasm-bindgen#3587](https://github.com/rustwasm/wasm-bindgen/issues/3587) +fn insert_constants_map(target: &JsValue, map: &HashMap) { + if !map.is_empty() { + let result = js_sys::Reflect::set(target, &"constants".into(), &hashmap_to_jsvalue(map)); + + if let Err(error) = result { + log::error!("Failed to set constants map for pipeline: {error:?}"); + } + } +} + /// Converts a hashmap to a Javascript object. fn hashmap_to_jsvalue(map: &HashMap) -> JsValue { let obj = js_sys::Object::new(); for (k, v) in map.iter() { - let _ = js_sys::Reflect::set(&obj, &k.into(), &(*v).into()); + js_sys::Reflect::set(&obj, &k.into(), &(*v).into()) + .expect("Setting the values in a Javascript map should never fail"); } JsValue::from(obj) From 8b7c0dc836404891ba66dd37a4ddef3a5448ec1e Mon Sep 17 00:00:00 2001 From: Douglas Dwyer Date: Sun, 19 May 2024 21:21:39 -0400 Subject: [PATCH 3/3] Panic on failure to set constants map --- wgpu/src/backend/webgpu.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/wgpu/src/backend/webgpu.rs b/wgpu/src/backend/webgpu.rs index 7abb7ee7c9..c23057bb9d 100644 --- a/wgpu/src/backend/webgpu.rs +++ b/wgpu/src/backend/webgpu.rs @@ -3818,7 +3818,7 @@ impl Drop for BufferMappedRange { } /// Adds the constants map to the given pipeline descriptor if the map is nonempty. -/// Logs an error if the map cannot be set. +/// Panics if the map cannot be set. /// /// This function is necessary because the constants array is not currently /// exposed by `wasm-bindgen`. See the following issues for details: @@ -3826,11 +3826,8 @@ impl Drop for BufferMappedRange { /// - [rustwasm/wasm-bindgen#3587](https://github.com/rustwasm/wasm-bindgen/issues/3587) fn insert_constants_map(target: &JsValue, map: &HashMap) { if !map.is_empty() { - let result = js_sys::Reflect::set(target, &"constants".into(), &hashmap_to_jsvalue(map)); - - if let Err(error) = result { - log::error!("Failed to set constants map for pipeline: {error:?}"); - } + js_sys::Reflect::set(target, &"constants".into(), &hashmap_to_jsvalue(map)) + .expect("Setting the values in a Javascript pipeline descriptor should never fail"); } }