From 965b00c06b8e5e3926e8b6c41b2e15bc5980a445 Mon Sep 17 00:00:00 2001 From: Daniel McNab <36049421+DJMcNab@users.noreply.github.com> Date: Wed, 17 Apr 2024 20:50:31 +0100 Subject: [PATCH] Allow configuring whether workgroup memory is zero initialised (#5508) --- CHANGELOG.md | 1 + deno_webgpu/pipeline.rs | 5 ++ examples/src/boids/mod.rs | 6 +- examples/src/bunnymark/mod.rs | 4 +- examples/src/conservative_raster/mod.rs | 16 ++--- examples/src/cube/mod.rs | 8 +-- examples/src/hello_compute/mod.rs | 2 +- examples/src/hello_synchronization/mod.rs | 4 +- examples/src/hello_triangle/mod.rs | 4 +- examples/src/hello_workgroups/mod.rs | 2 +- examples/src/mipmap/mod.rs | 8 +-- examples/src/msaa_line/mod.rs | 4 +- examples/src/render_to_texture/mod.rs | 4 +- examples/src/repeated_compute/mod.rs | 2 +- examples/src/shadow/mod.rs | 6 +- examples/src/skybox/mod.rs | 8 +-- examples/src/srgb_blend/mod.rs | 4 +- examples/src/stencil_triangles/mod.rs | 8 +-- examples/src/storage_texture/mod.rs | 2 +- examples/src/texture_arrays/mod.rs | 4 +- examples/src/timestamp_queries/mod.rs | 6 +- examples/src/uniform_values/mod.rs | 4 +- examples/src/water/mod.rs | 8 +-- player/tests/data/bind-group.ron | 1 + .../tests/data/pipeline-statistics-query.ron | 1 + player/tests/data/quad.ron | 2 + player/tests/data/zero-init-buffer.ron | 1 + .../tests/data/zero-init-texture-binding.ron | 1 + tests/src/image.rs | 2 +- tests/tests/bgra8unorm_storage.rs | 2 +- tests/tests/bind_group_layout_dedup.rs | 10 +-- tests/tests/buffer.rs | 4 +- tests/tests/device.rs | 8 +-- tests/tests/mem_leaks.rs | 4 +- tests/tests/nv12_texture/mod.rs | 4 +- tests/tests/occlusion_query/mod.rs | 2 +- tests/tests/partially_bounded_arrays/mod.rs | 2 +- tests/tests/pipeline.rs | 2 +- tests/tests/push_constants.rs | 2 +- tests/tests/regression/issue_3349.rs | 4 +- tests/tests/regression/issue_3457.rs | 8 +-- tests/tests/scissor_tests/mod.rs | 4 +- tests/tests/shader/mod.rs | 2 +- tests/tests/shader/zero_init_workgroup_mem.rs | 4 +- tests/tests/shader_primitive_index/mod.rs | 4 +- tests/tests/shader_view_format/mod.rs | 4 +- tests/tests/vertex_indices/mod.rs | 5 +- wgpu-core/src/device/resource.rs | 5 ++ wgpu-core/src/pipeline.rs | 5 ++ wgpu-hal/examples/halmark/main.rs | 2 + wgpu-hal/examples/ray-traced-triangle/main.rs | 1 + wgpu-hal/src/dx12/device.rs | 15 ++++- wgpu-hal/src/gles/device.rs | 15 ++++- wgpu-hal/src/gles/mod.rs | 1 + wgpu-hal/src/lib.rs | 6 ++ wgpu-hal/src/metal/device.rs | 2 +- wgpu-hal/src/vulkan/device.rs | 8 ++- wgpu/src/backend/wgpu_core.rs | 16 ++++- wgpu/src/lib.rs | 65 +++++++++++++------ 59 files changed, 219 insertions(+), 125 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a84c687f1..8f4cfa4c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -118,6 +118,7 @@ Bottom level categories: - `wgpu::Texture::as_hal` now returns a user-defined type to match the other as_hal functions - Added support for pipeline-overridable constants. By @teoxoy & @jimblandy in [#5500](https://github.com/gfx-rs/wgpu/pull/5500) +- Support disabling zero-initialization of workgroup local memory in compute shaders. By @DJMcNab in [#5508](https://github.com/gfx-rs/wgpu/pull/5508) #### GLES diff --git a/deno_webgpu/pipeline.rs b/deno_webgpu/pipeline.rs index 303128760..e8b5a71cf 100644 --- a/deno_webgpu/pipeline.rs +++ b/deno_webgpu/pipeline.rs @@ -113,6 +113,7 @@ pub fn op_webgpu_create_compute_pipeline( module: compute_shader_module_resource.1, entry_point: compute.entry_point.map(Cow::from), constants: Cow::Owned(compute.constants), + zero_initialize_workgroup_memory: true, }, }; let implicit_pipelines = match layout { @@ -359,6 +360,8 @@ pub fn op_webgpu_create_render_pipeline( module: fragment_shader_module_resource.1, entry_point: Some(Cow::from(fragment.entry_point)), constants: Cow::Owned(fragment.constants), + // Required to be true for WebGPU + zero_initialize_workgroup_memory: true, }, targets: Cow::Owned(fragment.targets), }) @@ -382,6 +385,8 @@ pub fn op_webgpu_create_render_pipeline( module: vertex_shader_module_resource.1, entry_point: Some(Cow::Owned(args.vertex.entry_point)), constants: Cow::Owned(args.vertex.constants), + // Required to be true for WebGPU + zero_initialize_workgroup_memory: true, }, buffers: Cow::Owned(vertex_buffers), }, diff --git a/examples/src/boids/mod.rs b/examples/src/boids/mod.rs index 02846beea..6c8bb6e76 100644 --- a/examples/src/boids/mod.rs +++ b/examples/src/boids/mod.rs @@ -132,7 +132,7 @@ impl crate::framework::Example for Example { vertex: wgpu::VertexState { module: &draw_shader, entry_point: "main_vs", - constants: &Default::default(), + compilation_options: Default::default(), buffers: &[ wgpu::VertexBufferLayout { array_stride: 4 * 4, @@ -149,7 +149,7 @@ impl crate::framework::Example for Example { fragment: Some(wgpu::FragmentState { module: &draw_shader, entry_point: "main_fs", - constants: &Default::default(), + compilation_options: Default::default(), targets: &[Some(config.view_formats[0].into())], }), primitive: wgpu::PrimitiveState::default(), @@ -165,7 +165,7 @@ impl crate::framework::Example for Example { layout: Some(&compute_pipeline_layout), module: &compute_shader, entry_point: "main", - constants: &Default::default(), + compilation_options: Default::default(), }); // buffer for the three 2d triangle vertices of each instance diff --git a/examples/src/bunnymark/mod.rs b/examples/src/bunnymark/mod.rs index be0947807..679fc5014 100644 --- a/examples/src/bunnymark/mod.rs +++ b/examples/src/bunnymark/mod.rs @@ -203,13 +203,13 @@ impl crate::framework::Example for Example { vertex: wgpu::VertexState { module: &shader, entry_point: "vs_main", - constants: &Default::default(), + compilation_options: Default::default(), buffers: &[], }, fragment: Some(wgpu::FragmentState { module: &shader, entry_point: "fs_main", - constants: &Default::default(), + compilation_options: Default::default(), targets: &[Some(wgpu::ColorTargetState { format: config.view_formats[0], blend: Some(wgpu::BlendState::ALPHA_BLENDING), diff --git a/examples/src/conservative_raster/mod.rs b/examples/src/conservative_raster/mod.rs index 12cdaa399..89500a798 100644 --- a/examples/src/conservative_raster/mod.rs +++ b/examples/src/conservative_raster/mod.rs @@ -97,13 +97,13 @@ impl crate::framework::Example for Example { vertex: wgpu::VertexState { module: &shader_triangle_and_lines, entry_point: "vs_main", - constants: &Default::default(), + compilation_options: Default::default(), buffers: &[], }, fragment: Some(wgpu::FragmentState { module: &shader_triangle_and_lines, entry_point: "fs_main_red", - constants: &Default::default(), + compilation_options: Default::default(), targets: &[Some(RENDER_TARGET_FORMAT.into())], }), primitive: wgpu::PrimitiveState { @@ -122,13 +122,13 @@ impl crate::framework::Example for Example { vertex: wgpu::VertexState { module: &shader_triangle_and_lines, entry_point: "vs_main", - constants: &Default::default(), + compilation_options: Default::default(), buffers: &[], }, fragment: Some(wgpu::FragmentState { module: &shader_triangle_and_lines, entry_point: "fs_main_blue", - constants: &Default::default(), + compilation_options: Default::default(), targets: &[Some(RENDER_TARGET_FORMAT.into())], }), primitive: wgpu::PrimitiveState::default(), @@ -148,13 +148,13 @@ impl crate::framework::Example for Example { vertex: wgpu::VertexState { module: &shader_triangle_and_lines, entry_point: "vs_main", - constants: &Default::default(), + compilation_options: Default::default(), buffers: &[], }, fragment: Some(wgpu::FragmentState { module: &shader_triangle_and_lines, entry_point: "fs_main_white", - constants: &Default::default(), + compilation_options: Default::default(), targets: &[Some(config.view_formats[0].into())], }), primitive: wgpu::PrimitiveState { @@ -211,13 +211,13 @@ impl crate::framework::Example for Example { vertex: wgpu::VertexState { module: &shader, entry_point: "vs_main", - constants: &Default::default(), + compilation_options: Default::default(), buffers: &[], }, fragment: Some(wgpu::FragmentState { module: &shader, entry_point: "fs_main", - constants: &Default::default(), + compilation_options: Default::default(), targets: &[Some(config.view_formats[0].into())], }), primitive: wgpu::PrimitiveState::default(), diff --git a/examples/src/cube/mod.rs b/examples/src/cube/mod.rs index d87193fcf..934762781 100644 --- a/examples/src/cube/mod.rs +++ b/examples/src/cube/mod.rs @@ -244,13 +244,13 @@ impl crate::framework::Example for Example { vertex: wgpu::VertexState { module: &shader, entry_point: "vs_main", - constants: &Default::default(), + compilation_options: Default::default(), buffers: &vertex_buffers, }, fragment: Some(wgpu::FragmentState { module: &shader, entry_point: "fs_main", - constants: &Default::default(), + compilation_options: Default::default(), targets: &[Some(config.view_formats[0].into())], }), primitive: wgpu::PrimitiveState { @@ -272,13 +272,13 @@ impl crate::framework::Example for Example { vertex: wgpu::VertexState { module: &shader, entry_point: "vs_main", - constants: &Default::default(), + compilation_options: Default::default(), buffers: &vertex_buffers, }, fragment: Some(wgpu::FragmentState { module: &shader, entry_point: "fs_wire", - constants: &Default::default(), + compilation_options: Default::default(), targets: &[Some(wgpu::ColorTargetState { format: config.view_formats[0], blend: Some(wgpu::BlendState { diff --git a/examples/src/hello_compute/mod.rs b/examples/src/hello_compute/mod.rs index 63169662e..d04aaa430 100644 --- a/examples/src/hello_compute/mod.rs +++ b/examples/src/hello_compute/mod.rs @@ -109,7 +109,7 @@ async fn execute_gpu_inner( layout: None, module: &cs_module, entry_point: "main", - constants: &Default::default(), + compilation_options: Default::default(), }); // Instantiates the bind group, once again specifying the binding of buffers. diff --git a/examples/src/hello_synchronization/mod.rs b/examples/src/hello_synchronization/mod.rs index 7dc2e6c9c..0a222fbe5 100644 --- a/examples/src/hello_synchronization/mod.rs +++ b/examples/src/hello_synchronization/mod.rs @@ -103,14 +103,14 @@ async fn execute( layout: Some(&pipeline_layout), module: &shaders_module, entry_point: "patient_main", - constants: &Default::default(), + compilation_options: Default::default(), }); let hasty_pipeline = device.create_compute_pipeline(&wgpu::ComputePipelineDescriptor { label: None, layout: Some(&pipeline_layout), module: &shaders_module, entry_point: "hasty_main", - constants: &Default::default(), + compilation_options: Default::default(), }); //---------------------------------------------------------- diff --git a/examples/src/hello_triangle/mod.rs b/examples/src/hello_triangle/mod.rs index 76b7a5a73..79162a695 100644 --- a/examples/src/hello_triangle/mod.rs +++ b/examples/src/hello_triangle/mod.rs @@ -60,12 +60,12 @@ async fn run(event_loop: EventLoop<()>, window: Window) { module: &shader, entry_point: "vs_main", buffers: &[], - constants: &Default::default(), + compilation_options: Default::default(), }, fragment: Some(wgpu::FragmentState { module: &shader, entry_point: "fs_main", - constants: &Default::default(), + compilation_options: Default::default(), targets: &[Some(swapchain_format.into())], }), primitive: wgpu::PrimitiveState::default(), diff --git a/examples/src/hello_workgroups/mod.rs b/examples/src/hello_workgroups/mod.rs index 5fb0eff6b..572de36d3 100644 --- a/examples/src/hello_workgroups/mod.rs +++ b/examples/src/hello_workgroups/mod.rs @@ -110,7 +110,7 @@ async fn run() { layout: Some(&pipeline_layout), module: &shader, entry_point: "main", - constants: &Default::default(), + compilation_options: Default::default(), }); //---------------------------------------------------------- diff --git a/examples/src/mipmap/mod.rs b/examples/src/mipmap/mod.rs index fc40d5d88..0848e94e1 100644 --- a/examples/src/mipmap/mod.rs +++ b/examples/src/mipmap/mod.rs @@ -93,13 +93,13 @@ impl Example { vertex: wgpu::VertexState { module: &shader, entry_point: "vs_main", - constants: &Default::default(), + compilation_options: Default::default(), buffers: &[], }, fragment: Some(wgpu::FragmentState { module: &shader, entry_point: "fs_main", - constants: &Default::default(), + compilation_options: Default::default(), targets: &[Some(TEXTURE_FORMAT.into())], }), primitive: wgpu::PrimitiveState { @@ -292,13 +292,13 @@ impl crate::framework::Example for Example { vertex: wgpu::VertexState { module: &shader, entry_point: "vs_main", - constants: &Default::default(), + compilation_options: Default::default(), buffers: &[], }, fragment: Some(wgpu::FragmentState { module: &shader, entry_point: "fs_main", - constants: &Default::default(), + compilation_options: Default::default(), targets: &[Some(config.view_formats[0].into())], }), primitive: wgpu::PrimitiveState { diff --git a/examples/src/msaa_line/mod.rs b/examples/src/msaa_line/mod.rs index 178968f47..cd22e75bc 100644 --- a/examples/src/msaa_line/mod.rs +++ b/examples/src/msaa_line/mod.rs @@ -54,7 +54,7 @@ impl Example { vertex: wgpu::VertexState { module: shader, entry_point: "vs_main", - constants: &Default::default(), + compilation_options: Default::default(), buffers: &[wgpu::VertexBufferLayout { array_stride: std::mem::size_of::() as wgpu::BufferAddress, step_mode: wgpu::VertexStepMode::Vertex, @@ -64,7 +64,7 @@ impl Example { fragment: Some(wgpu::FragmentState { module: shader, entry_point: "fs_main", - constants: &Default::default(), + compilation_options: Default::default(), targets: &[Some(config.view_formats[0].into())], }), primitive: wgpu::PrimitiveState { diff --git a/examples/src/render_to_texture/mod.rs b/examples/src/render_to_texture/mod.rs index 0cb2cdea7..5e571dc74 100644 --- a/examples/src/render_to_texture/mod.rs +++ b/examples/src/render_to_texture/mod.rs @@ -59,13 +59,13 @@ async fn run(_path: Option) { vertex: wgpu::VertexState { module: &shader, entry_point: "vs_main", - constants: &Default::default(), + compilation_options: Default::default(), buffers: &[], }, fragment: Some(wgpu::FragmentState { module: &shader, entry_point: "fs_main", - constants: &Default::default(), + compilation_options: Default::default(), targets: &[Some(wgpu::TextureFormat::Rgba8UnormSrgb.into())], }), primitive: wgpu::PrimitiveState::default(), diff --git a/examples/src/repeated_compute/mod.rs b/examples/src/repeated_compute/mod.rs index 0c4705519..55e87eed9 100644 --- a/examples/src/repeated_compute/mod.rs +++ b/examples/src/repeated_compute/mod.rs @@ -245,7 +245,7 @@ impl WgpuContext { layout: Some(&pipeline_layout), module: &shader, entry_point: "main", - constants: &Default::default(), + compilation_options: Default::default(), }); WgpuContext { diff --git a/examples/src/shadow/mod.rs b/examples/src/shadow/mod.rs index d0a29cc8b..2cb6d6f3e 100644 --- a/examples/src/shadow/mod.rs +++ b/examples/src/shadow/mod.rs @@ -500,7 +500,7 @@ impl crate::framework::Example for Example { vertex: wgpu::VertexState { module: &shader, entry_point: "vs_bake", - constants: &Default::default(), + compilation_options: Default::default(), buffers: &[vb_desc.clone()], }, fragment: None, @@ -633,7 +633,7 @@ impl crate::framework::Example for Example { vertex: wgpu::VertexState { module: &shader, entry_point: "vs_main", - constants: &Default::default(), + compilation_options: Default::default(), buffers: &[vb_desc], }, fragment: Some(wgpu::FragmentState { @@ -643,7 +643,7 @@ impl crate::framework::Example for Example { } else { "fs_main_without_storage" }, - constants: &Default::default(), + compilation_options: Default::default(), targets: &[Some(config.view_formats[0].into())], }), primitive: wgpu::PrimitiveState { diff --git a/examples/src/skybox/mod.rs b/examples/src/skybox/mod.rs index 443c9d41e..35a4266d2 100644 --- a/examples/src/skybox/mod.rs +++ b/examples/src/skybox/mod.rs @@ -199,13 +199,13 @@ impl crate::framework::Example for Example { vertex: wgpu::VertexState { module: &shader, entry_point: "vs_sky", - constants: &Default::default(), + compilation_options: Default::default(), buffers: &[], }, fragment: Some(wgpu::FragmentState { module: &shader, entry_point: "fs_sky", - constants: &Default::default(), + compilation_options: Default::default(), targets: &[Some(config.view_formats[0].into())], }), primitive: wgpu::PrimitiveState { @@ -228,7 +228,7 @@ impl crate::framework::Example for Example { vertex: wgpu::VertexState { module: &shader, entry_point: "vs_entity", - constants: &Default::default(), + compilation_options: Default::default(), buffers: &[wgpu::VertexBufferLayout { array_stride: std::mem::size_of::() as wgpu::BufferAddress, step_mode: wgpu::VertexStepMode::Vertex, @@ -238,7 +238,7 @@ impl crate::framework::Example for Example { fragment: Some(wgpu::FragmentState { module: &shader, entry_point: "fs_entity", - constants: &Default::default(), + compilation_options: Default::default(), targets: &[Some(config.view_formats[0].into())], }), primitive: wgpu::PrimitiveState { diff --git a/examples/src/srgb_blend/mod.rs b/examples/src/srgb_blend/mod.rs index fdff310c3..f701aff98 100644 --- a/examples/src/srgb_blend/mod.rs +++ b/examples/src/srgb_blend/mod.rs @@ -131,13 +131,13 @@ impl crate::framework::Example for Example { vertex: wgpu::VertexState { module: &shader, entry_point: "vs_main", - constants: &Default::default(), + compilation_options: Default::default(), buffers: &vertex_buffers, }, fragment: Some(wgpu::FragmentState { module: &shader, entry_point: "fs_main", - constants: &Default::default(), + compilation_options: Default::default(), targets: &[Some(wgpu::ColorTargetState { format: config.view_formats[0], blend: Some(wgpu::BlendState::ALPHA_BLENDING), diff --git a/examples/src/stencil_triangles/mod.rs b/examples/src/stencil_triangles/mod.rs index 07b8e3ec5..e0f495177 100644 --- a/examples/src/stencil_triangles/mod.rs +++ b/examples/src/stencil_triangles/mod.rs @@ -74,13 +74,13 @@ impl crate::framework::Example for Example { vertex: wgpu::VertexState { module: &shader, entry_point: "vs_main", - constants: &Default::default(), + compilation_options: Default::default(), buffers: &vertex_buffers, }, fragment: Some(wgpu::FragmentState { module: &shader, entry_point: "fs_main", - constants: &Default::default(), + compilation_options: Default::default(), targets: &[Some(wgpu::ColorTargetState { format: config.view_formats[0], blend: None, @@ -114,13 +114,13 @@ impl crate::framework::Example for Example { vertex: wgpu::VertexState { module: &shader, entry_point: "vs_main", - constants: &Default::default(), + compilation_options: Default::default(), buffers: &vertex_buffers, }, fragment: Some(wgpu::FragmentState { module: &shader, entry_point: "fs_main", - constants: &Default::default(), + compilation_options: Default::default(), targets: &[Some(config.view_formats[0].into())], }), primitive: Default::default(), diff --git a/examples/src/storage_texture/mod.rs b/examples/src/storage_texture/mod.rs index f83f61967..02900c891 100644 --- a/examples/src/storage_texture/mod.rs +++ b/examples/src/storage_texture/mod.rs @@ -100,7 +100,7 @@ async fn run(_path: Option) { layout: Some(&pipeline_layout), module: &shader, entry_point: "main", - constants: &Default::default(), + compilation_options: Default::default(), }); log::info!("Wgpu context set up."); diff --git a/examples/src/texture_arrays/mod.rs b/examples/src/texture_arrays/mod.rs index c786b0efe..dd7b4ec89 100644 --- a/examples/src/texture_arrays/mod.rs +++ b/examples/src/texture_arrays/mod.rs @@ -321,7 +321,7 @@ impl crate::framework::Example for Example { vertex: wgpu::VertexState { module: &base_shader_module, entry_point: "vert_main", - constants: &Default::default(), + compilation_options: Default::default(), buffers: &[wgpu::VertexBufferLayout { array_stride: vertex_size as wgpu::BufferAddress, step_mode: wgpu::VertexStepMode::Vertex, @@ -331,7 +331,7 @@ impl crate::framework::Example for Example { fragment: Some(wgpu::FragmentState { module: fragment_shader_module, entry_point: fragment_entry_point, - constants: &Default::default(), + compilation_options: Default::default(), targets: &[Some(config.view_formats[0].into())], }), primitive: wgpu::PrimitiveState { diff --git a/examples/src/timestamp_queries/mod.rs b/examples/src/timestamp_queries/mod.rs index 58952c76c..7042d60fe 100644 --- a/examples/src/timestamp_queries/mod.rs +++ b/examples/src/timestamp_queries/mod.rs @@ -298,7 +298,7 @@ fn compute_pass( layout: None, module, entry_point: "main_cs", - constants: &Default::default(), + compilation_options: Default::default(), }); let bind_group_layout = compute_pipeline.get_bind_group_layout(0); let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { @@ -353,13 +353,13 @@ fn render_pass( vertex: wgpu::VertexState { module, entry_point: "vs_main", - constants: &Default::default(), + compilation_options: Default::default(), buffers: &[], }, fragment: Some(wgpu::FragmentState { module, entry_point: "fs_main", - constants: &Default::default(), + compilation_options: Default::default(), targets: &[Some(format.into())], }), primitive: wgpu::PrimitiveState::default(), diff --git a/examples/src/uniform_values/mod.rs b/examples/src/uniform_values/mod.rs index 1ddee03e9..932c7aaee 100644 --- a/examples/src/uniform_values/mod.rs +++ b/examples/src/uniform_values/mod.rs @@ -179,13 +179,13 @@ impl WgpuContext { vertex: wgpu::VertexState { module: &shader, entry_point: "vs_main", - constants: &Default::default(), + compilation_options: Default::default(), buffers: &[], }, fragment: Some(wgpu::FragmentState { module: &shader, entry_point: "fs_main", - constants: &Default::default(), + compilation_options: Default::default(), targets: &[Some(swapchain_format.into())], }), primitive: wgpu::PrimitiveState::default(), diff --git a/examples/src/water/mod.rs b/examples/src/water/mod.rs index 6bc3824e7..94f12895a 100644 --- a/examples/src/water/mod.rs +++ b/examples/src/water/mod.rs @@ -512,7 +512,7 @@ impl crate::framework::Example for Example { vertex: wgpu::VertexState { module: &water_module, entry_point: "vs_main", - constants: &Default::default(), + compilation_options: Default::default(), // Layout of our vertices. This should match the structs // which are uploaded to the GPU. This should also be // ensured by tagging on either a `#[repr(C)]` onto a @@ -528,7 +528,7 @@ impl crate::framework::Example for Example { fragment: Some(wgpu::FragmentState { module: &water_module, entry_point: "fs_main", - constants: &Default::default(), + compilation_options: Default::default(), // Describes how the colour will be interpolated // and assigned to the output attachment. targets: &[Some(wgpu::ColorTargetState { @@ -583,7 +583,7 @@ impl crate::framework::Example for Example { vertex: wgpu::VertexState { module: &terrain_module, entry_point: "vs_main", - constants: &Default::default(), + compilation_options: Default::default(), buffers: &[wgpu::VertexBufferLayout { array_stride: terrain_vertex_size as wgpu::BufferAddress, step_mode: wgpu::VertexStepMode::Vertex, @@ -593,7 +593,7 @@ impl crate::framework::Example for Example { fragment: Some(wgpu::FragmentState { module: &terrain_module, entry_point: "fs_main", - constants: &Default::default(), + compilation_options: Default::default(), targets: &[Some(config.view_formats[0].into())], }), primitive: wgpu::PrimitiveState { diff --git a/player/tests/data/bind-group.ron b/player/tests/data/bind-group.ron index 92415e4ff..9da7abe09 100644 --- a/player/tests/data/bind-group.ron +++ b/player/tests/data/bind-group.ron @@ -58,6 +58,7 @@ module: Id(0, 1, Empty), entry_point: None, constants: {}, + zero_initialize_workgroup_memory: true, ), ), ), diff --git a/player/tests/data/pipeline-statistics-query.ron b/player/tests/data/pipeline-statistics-query.ron index 3c672f4e5..f0f96d42c 100644 --- a/player/tests/data/pipeline-statistics-query.ron +++ b/player/tests/data/pipeline-statistics-query.ron @@ -31,6 +31,7 @@ module: Id(0, 1, Empty), entry_point: None, constants: {}, + zero_initialize_workgroup_memory: true, ), ), ), diff --git a/player/tests/data/quad.ron b/player/tests/data/quad.ron index 9d6b4a25f..1a8b4028b 100644 --- a/player/tests/data/quad.ron +++ b/player/tests/data/quad.ron @@ -59,6 +59,7 @@ module: Id(0, 1, Empty), entry_point: None, constants: {}, + zero_initialize_workgroup_memory: true, ), buffers: [], ), @@ -67,6 +68,7 @@ module: Id(0, 1, Empty), entry_point: None, constants: {}, + zero_initialize_workgroup_memory: true, ), targets: [ Some(( diff --git a/player/tests/data/zero-init-buffer.ron b/player/tests/data/zero-init-buffer.ron index 5697a2555..1ce7924dd 100644 --- a/player/tests/data/zero-init-buffer.ron +++ b/player/tests/data/zero-init-buffer.ron @@ -135,6 +135,7 @@ module: Id(0, 1, Empty), entry_point: None, constants: {}, + zero_initialize_workgroup_memory: true, ), ), ), diff --git a/player/tests/data/zero-init-texture-binding.ron b/player/tests/data/zero-init-texture-binding.ron index 340cb0cfa..2aeaf22c7 100644 --- a/player/tests/data/zero-init-texture-binding.ron +++ b/player/tests/data/zero-init-texture-binding.ron @@ -136,6 +136,7 @@ module: Id(0, 1, Empty), entry_point: None, constants: {}, + zero_initialize_workgroup_memory: true, ), ), ), diff --git a/tests/src/image.rs b/tests/src/image.rs index 98310233c..8996f361c 100644 --- a/tests/src/image.rs +++ b/tests/src/image.rs @@ -369,7 +369,7 @@ fn copy_via_compute( layout: Some(&pll), module: &sm, entry_point: "copy_texture_to_buffer", - constants: &Default::default(), + compilation_options: Default::default(), }); { diff --git a/tests/tests/bgra8unorm_storage.rs b/tests/tests/bgra8unorm_storage.rs index c3913e5df..17082a9ed 100644 --- a/tests/tests/bgra8unorm_storage.rs +++ b/tests/tests/bgra8unorm_storage.rs @@ -96,7 +96,7 @@ static BGRA8_UNORM_STORAGE: GpuTestConfiguration = GpuTestConfiguration::new() label: None, layout: Some(&pl), entry_point: "main", - constants: &Default::default(), + compilation_options: Default::default(), module: &module, }); diff --git a/tests/tests/bind_group_layout_dedup.rs b/tests/tests/bind_group_layout_dedup.rs index 519cfbda2..3466e1e24 100644 --- a/tests/tests/bind_group_layout_dedup.rs +++ b/tests/tests/bind_group_layout_dedup.rs @@ -90,7 +90,7 @@ async fn bgl_dedupe(ctx: TestingContext) { layout: Some(&pipeline_layout), module: &module, entry_point: "no_resources", - constants: &Default::default(), + compilation_options: Default::default(), }; let pipeline = ctx.device.create_compute_pipeline(&desc); @@ -219,7 +219,7 @@ fn bgl_dedupe_with_dropped_user_handle(ctx: TestingContext) { layout: Some(&pipeline_layout), module: &module, entry_point: "no_resources", - constants: &Default::default(), + compilation_options: Default::default(), }); let mut encoder = ctx.device.create_command_encoder(&Default::default()); @@ -265,7 +265,7 @@ fn bgl_dedupe_derived(ctx: TestingContext) { layout: None, module: &module, entry_point: "resources", - constants: &Default::default(), + compilation_options: Default::default(), }); // We create two bind groups, pulling the bind_group_layout from the pipeline each time. @@ -336,7 +336,7 @@ fn separate_programs_have_incompatible_derived_bgls(ctx: TestingContext) { layout: None, module: &module, entry_point: "resources", - constants: &Default::default(), + compilation_options: Default::default(), }; // Create two pipelines, creating a BG from the second. let pipeline1 = ctx.device.create_compute_pipeline(&desc); @@ -398,7 +398,7 @@ fn derived_bgls_incompatible_with_regular_bgls(ctx: TestingContext) { layout: None, module: &module, entry_point: "resources", - constants: &Default::default(), + compilation_options: Default::default(), }); // Create a matching BGL diff --git a/tests/tests/buffer.rs b/tests/tests/buffer.rs index 1622995c3..0693877d0 100644 --- a/tests/tests/buffer.rs +++ b/tests/tests/buffer.rs @@ -224,7 +224,7 @@ static MINIMUM_BUFFER_BINDING_SIZE_LAYOUT: GpuTestConfiguration = GpuTestConfigu layout: Some(&pipeline_layout), module: &shader_module, entry_point: "main", - constants: &Default::default(), + compilation_options: Default::default(), }); }); }); @@ -293,7 +293,7 @@ static MINIMUM_BUFFER_BINDING_SIZE_DISPATCH: GpuTestConfiguration = GpuTestConfi layout: Some(&pipeline_layout), module: &shader_module, entry_point: "main", - constants: &Default::default(), + compilation_options: Default::default(), }); let buffer = ctx.device.create_buffer(&wgpu::BufferDescriptor { diff --git a/tests/tests/device.rs b/tests/tests/device.rs index 82e3f71a1..649a850fa 100644 --- a/tests/tests/device.rs +++ b/tests/tests/device.rs @@ -480,7 +480,7 @@ static DEVICE_DESTROY_THEN_MORE: GpuTestConfiguration = GpuTestConfiguration::ne vertex: wgpu::VertexState { module: &shader_module, entry_point: "", - constants: &Default::default(), + compilation_options: Default::default(), buffers: &[], }, primitive: wgpu::PrimitiveState::default(), @@ -499,7 +499,7 @@ static DEVICE_DESTROY_THEN_MORE: GpuTestConfiguration = GpuTestConfiguration::ne layout: None, module: &shader_module, entry_point: "", - constants: &Default::default(), + compilation_options: Default::default(), }); }); @@ -736,7 +736,7 @@ fn vs_main() -> @builtin(position) vec4 { fragment: Some(wgpu::FragmentState { module: &trivial_shaders_with_some_reversed_bindings, entry_point: "fs_main", - constants: &Default::default(), + compilation_options: Default::default(), targets: &[Some(wgt::ColorTargetState { format: wgt::TextureFormat::Bgra8Unorm, blend: None, @@ -750,7 +750,7 @@ fn vs_main() -> @builtin(position) vec4 { vertex: wgpu::VertexState { module: &trivial_shaders_with_some_reversed_bindings, entry_point: "vs_main", - constants: &Default::default(), + compilation_options: Default::default(), buffers: &[], }, primitive: wgt::PrimitiveState::default(), diff --git a/tests/tests/mem_leaks.rs b/tests/tests/mem_leaks.rs index 949b4d96c..7002ebabe 100644 --- a/tests/tests/mem_leaks.rs +++ b/tests/tests/mem_leaks.rs @@ -97,7 +97,7 @@ async fn draw_test_with_reports( buffers: &[], module: &shader, entry_point: "vs_main_builtin", - constants: &Default::default(), + compilation_options: Default::default(), }, primitive: wgpu::PrimitiveState::default(), depth_stencil: None, @@ -105,7 +105,7 @@ async fn draw_test_with_reports( fragment: Some(wgpu::FragmentState { module: &shader, entry_point: "fs_main", - constants: &Default::default(), + compilation_options: Default::default(), targets: &[Some(wgpu::ColorTargetState { format: wgpu::TextureFormat::Rgba8Unorm, blend: None, diff --git a/tests/tests/nv12_texture/mod.rs b/tests/tests/nv12_texture/mod.rs index 0f4ba16f2..70ee84983 100644 --- a/tests/tests/nv12_texture/mod.rs +++ b/tests/tests/nv12_texture/mod.rs @@ -24,13 +24,13 @@ static NV12_TEXTURE_CREATION_SAMPLING: GpuTestConfiguration = GpuTestConfigurati vertex: wgpu::VertexState { module: &shader, entry_point: "vs_main", - constants: &Default::default(), + compilation_options: Default::default(), buffers: &[], }, fragment: Some(wgpu::FragmentState { module: &shader, entry_point: "fs_main", - constants: &Default::default(), + compilation_options: Default::default(), targets: &[Some(target_format.into())], }), primitive: wgpu::PrimitiveState { diff --git a/tests/tests/occlusion_query/mod.rs b/tests/tests/occlusion_query/mod.rs index 2db035bfb..1a68ecf79 100644 --- a/tests/tests/occlusion_query/mod.rs +++ b/tests/tests/occlusion_query/mod.rs @@ -37,7 +37,7 @@ static OCCLUSION_QUERY: GpuTestConfiguration = GpuTestConfiguration::new() vertex: wgpu::VertexState { module: &shader, entry_point: "vs_main", - constants: &Default::default(), + compilation_options: Default::default(), buffers: &[], }, fragment: None, diff --git a/tests/tests/partially_bounded_arrays/mod.rs b/tests/tests/partially_bounded_arrays/mod.rs index b93e900a9..11eee5b20 100644 --- a/tests/tests/partially_bounded_arrays/mod.rs +++ b/tests/tests/partially_bounded_arrays/mod.rs @@ -69,7 +69,7 @@ static PARTIALLY_BOUNDED_ARRAY: GpuTestConfiguration = GpuTestConfiguration::new layout: Some(&pipeline_layout), module: &cs_module, entry_point: "main", - constants: &Default::default(), + compilation_options: Default::default(), }); let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { diff --git a/tests/tests/pipeline.rs b/tests/tests/pipeline.rs index c8814e25f..a07e158a5 100644 --- a/tests/tests/pipeline.rs +++ b/tests/tests/pipeline.rs @@ -28,7 +28,7 @@ static PIPELINE_DEFAULT_LAYOUT_BAD_MODULE: GpuTestConfiguration = GpuTestConfigu layout: None, module: &module, entry_point: "doesn't exist", - constants: &Default::default(), + compilation_options: Default::default(), }); pipeline.get_bind_group_layout(0); diff --git a/tests/tests/push_constants.rs b/tests/tests/push_constants.rs index d1119476c..04d9a00f7 100644 --- a/tests/tests/push_constants.rs +++ b/tests/tests/push_constants.rs @@ -103,7 +103,7 @@ async fn partial_update_test(ctx: TestingContext) { layout: Some(&pipeline_layout), module: &sm, entry_point: "main", - constants: &Default::default(), + compilation_options: Default::default(), }); let mut encoder = ctx diff --git a/tests/tests/regression/issue_3349.rs b/tests/tests/regression/issue_3349.rs index 93b91b9d7..74c466b45 100644 --- a/tests/tests/regression/issue_3349.rs +++ b/tests/tests/regression/issue_3349.rs @@ -102,13 +102,13 @@ async fn multi_stage_data_binding_test(ctx: TestingContext) { vertex: wgpu::VertexState { module: &vs_sm, entry_point: "vs_main", - constants: &Default::default(), + compilation_options: Default::default(), buffers: &[], }, fragment: Some(wgpu::FragmentState { module: &fs_sm, entry_point: "fs_main", - constants: &Default::default(), + compilation_options: Default::default(), targets: &[Some(wgpu::ColorTargetState { format: wgpu::TextureFormat::Rgba8Unorm, blend: None, diff --git a/tests/tests/regression/issue_3457.rs b/tests/tests/regression/issue_3457.rs index 0fca44b0c..f18d681ae 100644 --- a/tests/tests/regression/issue_3457.rs +++ b/tests/tests/regression/issue_3457.rs @@ -52,7 +52,7 @@ static PASS_RESET_VERTEX_BUFFER: GpuTestConfiguration = vertex: VertexState { module: &module, entry_point: "double_buffer_vert", - constants: &Default::default(), + compilation_options: Default::default(), buffers: &[ VertexBufferLayout { array_stride: 16, @@ -72,7 +72,7 @@ static PASS_RESET_VERTEX_BUFFER: GpuTestConfiguration = fragment: Some(FragmentState { module: &module, entry_point: "double_buffer_frag", - constants: &Default::default(), + compilation_options: Default::default(), targets: &[Some(ColorTargetState { format: TextureFormat::Rgba8Unorm, blend: None, @@ -90,7 +90,7 @@ static PASS_RESET_VERTEX_BUFFER: GpuTestConfiguration = vertex: VertexState { module: &module, entry_point: "single_buffer_vert", - constants: &Default::default(), + compilation_options: Default::default(), buffers: &[VertexBufferLayout { array_stride: 16, step_mode: VertexStepMode::Vertex, @@ -103,7 +103,7 @@ static PASS_RESET_VERTEX_BUFFER: GpuTestConfiguration = fragment: Some(FragmentState { module: &module, entry_point: "single_buffer_frag", - constants: &Default::default(), + compilation_options: Default::default(), targets: &[Some(ColorTargetState { format: TextureFormat::Rgba8Unorm, blend: None, diff --git a/tests/tests/scissor_tests/mod.rs b/tests/tests/scissor_tests/mod.rs index efc658501..15c35644e 100644 --- a/tests/tests/scissor_tests/mod.rs +++ b/tests/tests/scissor_tests/mod.rs @@ -44,7 +44,7 @@ async fn scissor_test_impl( vertex: wgpu::VertexState { module: &shader, entry_point: "vs_main", - constants: &Default::default(), + compilation_options: Default::default(), buffers: &[], }, primitive: wgpu::PrimitiveState::default(), @@ -53,7 +53,7 @@ async fn scissor_test_impl( fragment: Some(wgpu::FragmentState { module: &shader, entry_point: "fs_main", - constants: &Default::default(), + compilation_options: Default::default(), targets: &[Some(wgpu::ColorTargetState { format: wgpu::TextureFormat::Rgba8Unorm, blend: None, diff --git a/tests/tests/shader/mod.rs b/tests/tests/shader/mod.rs index bb93c690e..dcd9d1f13 100644 --- a/tests/tests/shader/mod.rs +++ b/tests/tests/shader/mod.rs @@ -307,7 +307,7 @@ async fn shader_input_output_test( layout: Some(&pll), module: &sm, entry_point: "cs_main", - constants: &Default::default(), + compilation_options: Default::default(), }); // -- Initializing data -- diff --git a/tests/tests/shader/zero_init_workgroup_mem.rs b/tests/tests/shader/zero_init_workgroup_mem.rs index 2bbcd87d9..cb9f341ee 100644 --- a/tests/tests/shader/zero_init_workgroup_mem.rs +++ b/tests/tests/shader/zero_init_workgroup_mem.rs @@ -87,7 +87,7 @@ static ZERO_INIT_WORKGROUP_MEMORY: GpuTestConfiguration = GpuTestConfiguration:: layout: Some(&pll), module: &sm, entry_point: "read", - constants: &Default::default(), + compilation_options: Default::default(), }); let pipeline_write = ctx @@ -97,7 +97,7 @@ static ZERO_INIT_WORKGROUP_MEMORY: GpuTestConfiguration = GpuTestConfiguration:: layout: None, module: &sm, entry_point: "write", - constants: &Default::default(), + compilation_options: Default::default(), }); // -- Initializing data -- diff --git a/tests/tests/shader_primitive_index/mod.rs b/tests/tests/shader_primitive_index/mod.rs index fa6bbcfb5..fb4339783 100644 --- a/tests/tests/shader_primitive_index/mod.rs +++ b/tests/tests/shader_primitive_index/mod.rs @@ -122,7 +122,7 @@ async fn pulling_common( vertex: wgpu::VertexState { module: &shader, entry_point: "vs_main", - constants: &Default::default(), + compilation_options: Default::default(), buffers: &[wgpu::VertexBufferLayout { array_stride: 8, step_mode: wgpu::VertexStepMode::Vertex, @@ -139,7 +139,7 @@ async fn pulling_common( fragment: Some(wgpu::FragmentState { module: &shader, entry_point: "fs_main", - constants: &Default::default(), + compilation_options: Default::default(), targets: &[Some(wgpu::ColorTargetState { format: wgpu::TextureFormat::Rgba8Unorm, blend: None, diff --git a/tests/tests/shader_view_format/mod.rs b/tests/tests/shader_view_format/mod.rs index 60efa0130..53c642bf7 100644 --- a/tests/tests/shader_view_format/mod.rs +++ b/tests/tests/shader_view_format/mod.rs @@ -93,13 +93,13 @@ async fn reinterpret( vertex: wgpu::VertexState { module: shader, entry_point: "vs_main", - constants: &Default::default(), + compilation_options: Default::default(), buffers: &[], }, fragment: Some(wgpu::FragmentState { module: shader, entry_point: "fs_main", - constants: &Default::default(), + compilation_options: Default::default(), targets: &[Some(src_format.into())], }), primitive: wgpu::PrimitiveState { diff --git a/tests/tests/vertex_indices/mod.rs b/tests/tests/vertex_indices/mod.rs index 77e08489b..cad7e731d 100644 --- a/tests/tests/vertex_indices/mod.rs +++ b/tests/tests/vertex_indices/mod.rs @@ -272,7 +272,6 @@ async fn vertex_index_common(ctx: TestingContext) { push_constant_ranges: &[], }); - let constants = &Default::default(); let mut pipeline_desc = wgpu::RenderPipelineDescriptor { label: None, layout: Some(&ppl), @@ -280,7 +279,7 @@ async fn vertex_index_common(ctx: TestingContext) { buffers: &[], module: &shader, entry_point: "vs_main_builtin", - constants, + compilation_options: Default::default(), }, primitive: wgpu::PrimitiveState::default(), depth_stencil: None, @@ -288,7 +287,7 @@ async fn vertex_index_common(ctx: TestingContext) { fragment: Some(wgpu::FragmentState { module: &shader, entry_point: "fs_main", - constants, + compilation_options: Default::default(), targets: &[Some(wgpu::ColorTargetState { format: wgpu::TextureFormat::Rgba8Unorm, blend: None, diff --git a/wgpu-core/src/device/resource.rs b/wgpu-core/src/device/resource.rs index 52ade2683..645e86bc4 100644 --- a/wgpu-core/src/device/resource.rs +++ b/wgpu-core/src/device/resource.rs @@ -2789,6 +2789,7 @@ impl Device { module: shader_module.raw(), entry_point: final_entry_point_name.as_ref(), constants: desc.stage.constants.as_ref(), + zero_initialize_workgroup_memory: desc.stage.zero_initialize_workgroup_memory, }, }; @@ -3204,6 +3205,7 @@ impl Device { module: vertex_shader_module.raw(), entry_point: &vertex_entry_point_name, constants: stage_desc.constants.as_ref(), + zero_initialize_workgroup_memory: stage_desc.zero_initialize_workgroup_memory, } }; @@ -3264,6 +3266,9 @@ impl Device { module: shader_module.raw(), entry_point: &fragment_entry_point_name, constants: fragment_state.stage.constants.as_ref(), + zero_initialize_workgroup_memory: fragment_state + .stage + .zero_initialize_workgroup_memory, }) } None => None, diff --git a/wgpu-core/src/pipeline.rs b/wgpu-core/src/pipeline.rs index b1689bd69..6f34155a9 100644 --- a/wgpu-core/src/pipeline.rs +++ b/wgpu-core/src/pipeline.rs @@ -241,6 +241,11 @@ pub struct ProgrammableStageDescriptor<'a> { /// /// The value may represent any of WGSL's concrete scalar types. pub constants: Cow<'a, naga::back::PipelineConstants>, + /// Whether workgroup scoped memory will be initialized with zero values for this stage. + /// + /// This is required by the WebGPU spec, but may have overhead which can be avoided + /// for cross-platform applications + pub zero_initialize_workgroup_memory: bool, } /// Number of implicit bind groups derived at pipeline creation. diff --git a/wgpu-hal/examples/halmark/main.rs b/wgpu-hal/examples/halmark/main.rs index 29dfd49d2..f376f1025 100644 --- a/wgpu-hal/examples/halmark/main.rs +++ b/wgpu-hal/examples/halmark/main.rs @@ -253,12 +253,14 @@ impl Example { module: &shader, entry_point: "vs_main", constants: &constants, + zero_initialize_workgroup_memory: true, }, vertex_buffers: &[], fragment_stage: Some(hal::ProgrammableStage { module: &shader, entry_point: "fs_main", constants: &constants, + zero_initialize_workgroup_memory: true, }), primitive: wgt::PrimitiveState { topology: wgt::PrimitiveTopology::TriangleStrip, diff --git a/wgpu-hal/examples/ray-traced-triangle/main.rs b/wgpu-hal/examples/ray-traced-triangle/main.rs index 2ed2d6462..3985cd60a 100644 --- a/wgpu-hal/examples/ray-traced-triangle/main.rs +++ b/wgpu-hal/examples/ray-traced-triangle/main.rs @@ -372,6 +372,7 @@ impl Example { module: &shader_module, entry_point: "main", constants: &Default::default(), + zero_initialize_workgroup_memory: true, }, }) } diff --git a/wgpu-hal/src/dx12/device.rs b/wgpu-hal/src/dx12/device.rs index f4539817d..82075294e 100644 --- a/wgpu-hal/src/dx12/device.rs +++ b/wgpu-hal/src/dx12/device.rs @@ -226,9 +226,20 @@ impl super::Device { ) .map_err(|e| crate::PipelineError::Linkage(stage_bit, format!("HLSL: {e:?}")))?; + let needs_temp_options = stage.zero_initialize_workgroup_memory + != layout.naga_options.zero_initialize_workgroup_memory; + let mut temp_options; + let naga_options = if needs_temp_options { + temp_options = layout.naga_options.clone(); + temp_options.zero_initialize_workgroup_memory = stage.zero_initialize_workgroup_memory; + &temp_options + } else { + &layout.naga_options + }; + //TODO: reuse the writer let mut source = String::new(); - let mut writer = hlsl::Writer::new(&mut source, &layout.naga_options); + let mut writer = hlsl::Writer::new(&mut source, naga_options); let reflection_info = { profiling::scope!("naga::back::hlsl::write"); writer @@ -239,7 +250,7 @@ impl super::Device { let full_stage = format!( "{}_{}\0", naga_stage.to_hlsl_str(), - layout.naga_options.shader_model.to_str() + naga_options.shader_model.to_str() ); let ep_index = module diff --git a/wgpu-hal/src/gles/device.rs b/wgpu-hal/src/gles/device.rs index 921941735..a1e2736aa 100644 --- a/wgpu-hal/src/gles/device.rs +++ b/wgpu-hal/src/gles/device.rs @@ -255,11 +255,23 @@ impl super::Device { }; let mut output = String::new(); + let needs_temp_options = stage.zero_initialize_workgroup_memory + != context.layout.naga_options.zero_initialize_workgroup_memory; + let mut temp_options; + let naga_options = if needs_temp_options { + // We use a conditional here, as cloning the naga_options could be expensive + // That is, we want to avoid doing that unless we cannot avoid it + temp_options = context.layout.naga_options.clone(); + temp_options.zero_initialize_workgroup_memory = stage.zero_initialize_workgroup_memory; + &temp_options + } else { + &context.layout.naga_options + }; let mut writer = glsl::Writer::new( &mut output, &module, &info, - &context.layout.naga_options, + naga_options, &pipeline_options, policies, ) @@ -305,6 +317,7 @@ impl super::Device { naga_stage: naga_stage.to_owned(), shader_id: stage.module.id, entry_point: stage.entry_point.to_owned(), + zero_initialize_workgroup_memory: stage.zero_initialize_workgroup_memory, }); } let mut guard = self diff --git a/wgpu-hal/src/gles/mod.rs b/wgpu-hal/src/gles/mod.rs index 6f41f7c00..0fcb09be4 100644 --- a/wgpu-hal/src/gles/mod.rs +++ b/wgpu-hal/src/gles/mod.rs @@ -602,6 +602,7 @@ struct ProgramStage { naga_stage: naga::ShaderStage, shader_id: ShaderId, entry_point: String, + zero_initialize_workgroup_memory: bool, } #[derive(PartialEq, Eq, Hash)] diff --git a/wgpu-hal/src/lib.rs b/wgpu-hal/src/lib.rs index 0b8e8d1e1..1aff08160 100644 --- a/wgpu-hal/src/lib.rs +++ b/wgpu-hal/src/lib.rs @@ -1459,6 +1459,11 @@ pub struct ProgrammableStage<'a, A: Api> { pub entry_point: &'a str, /// Pipeline constants pub constants: &'a naga::back::PipelineConstants, + /// Whether workgroup scoped memory will be initialized with zero values for this stage. + /// + /// This is required by the WebGPU spec, but may have overhead which can be avoided + /// for cross-platform applications + pub zero_initialize_workgroup_memory: bool, } // Rust gets confused about the impl requirements for `A` @@ -1468,6 +1473,7 @@ impl Clone for ProgrammableStage<'_, A> { module: self.module, entry_point: self.entry_point, constants: self.constants, + zero_initialize_workgroup_memory: self.zero_initialize_workgroup_memory, } } } diff --git a/wgpu-hal/src/metal/device.rs b/wgpu-hal/src/metal/device.rs index 0906d2151..2c8f5a2bf 100644 --- a/wgpu-hal/src/metal/device.rs +++ b/wgpu-hal/src/metal/device.rs @@ -112,7 +112,7 @@ impl super::Device { // TODO: support bounds checks on binding arrays binding_array: naga::proc::BoundsCheckPolicy::Unchecked, }, - zero_initialize_workgroup_memory: true, + zero_initialize_workgroup_memory: stage.zero_initialize_workgroup_memory, }; let pipeline_options = naga::back::msl::PipelineOptions { diff --git a/wgpu-hal/src/vulkan/device.rs b/wgpu-hal/src/vulkan/device.rs index e9e26c2b1..ec392533a 100644 --- a/wgpu-hal/src/vulkan/device.rs +++ b/wgpu-hal/src/vulkan/device.rs @@ -2,6 +2,7 @@ use super::conv; use arrayvec::ArrayVec; use ash::{extensions::khr, vk}; +use naga::back::spv::ZeroInitializeWorkgroupMemoryMode; use parking_lot::Mutex; use std::{ @@ -737,7 +738,8 @@ impl super::Device { }; let needs_temp_options = !runtime_checks || !binding_map.is_empty() - || naga_shader.debug_source.is_some(); + || naga_shader.debug_source.is_some() + || !stage.zero_initialize_workgroup_memory; let mut temp_options; let options = if needs_temp_options { temp_options = self.naga_options.clone(); @@ -760,6 +762,10 @@ impl super::Device { file_name: debug.file_name.as_ref().as_ref(), }) } + if !stage.zero_initialize_workgroup_memory { + temp_options.zero_initialize_workgroup_memory = + ZeroInitializeWorkgroupMemoryMode::None; + } &temp_options } else { diff --git a/wgpu/src/backend/wgpu_core.rs b/wgpu/src/backend/wgpu_core.rs index edf5bc5e2..41e3e1816 100644 --- a/wgpu/src/backend/wgpu_core.rs +++ b/wgpu/src/backend/wgpu_core.rs @@ -1143,7 +1143,11 @@ impl crate::Context for ContextWgpuCore { stage: pipe::ProgrammableStageDescriptor { module: desc.vertex.module.id.into(), entry_point: Some(Borrowed(desc.vertex.entry_point)), - constants: Borrowed(desc.vertex.constants), + constants: Borrowed(desc.vertex.compilation_options.constants), + zero_initialize_workgroup_memory: desc + .vertex + .compilation_options + .zero_initialize_workgroup_memory, }, buffers: Borrowed(&vertex_buffers), }, @@ -1154,7 +1158,10 @@ impl crate::Context for ContextWgpuCore { stage: pipe::ProgrammableStageDescriptor { module: frag.module.id.into(), entry_point: Some(Borrowed(frag.entry_point)), - constants: Borrowed(frag.constants), + constants: Borrowed(frag.compilation_options.constants), + zero_initialize_workgroup_memory: frag + .compilation_options + .zero_initialize_workgroup_memory, }, targets: Borrowed(frag.targets), }), @@ -1203,7 +1210,10 @@ impl crate::Context for ContextWgpuCore { stage: pipe::ProgrammableStageDescriptor { module: desc.module.id.into(), entry_point: Some(Borrowed(desc.entry_point)), - constants: Borrowed(desc.constants), + constants: Borrowed(desc.compilation_options.constants), + zero_initialize_workgroup_memory: desc + .compilation_options + .zero_initialize_workgroup_memory, }, }; diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index 4d14f9d5c..2807c55cb 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -1647,14 +1647,10 @@ pub struct VertexState<'a> { /// The name of the entry point in the compiled shader. There must be a function with this name /// in the shader. pub entry_point: &'a str, - /// Specifies the values of pipeline-overridable constants in the shader module. + /// Advanced options for when this pipeline is compiled /// - /// If an `@id` attribute was specified on the declaration, - /// the key must be the pipeline constant ID as a decimal ASCII number; if not, - /// the key must be the constant's identifier name. - /// - /// The value may represent any of WGSL's concrete scalar types. - pub constants: &'a HashMap, + /// This implements `Default`, and for most users can be set to `Default::default()` + pub compilation_options: PipelineCompilationOptions<'a>, /// The format of any vertex buffers used with this pipeline. pub buffers: &'a [VertexBufferLayout<'a>], } @@ -1674,14 +1670,10 @@ pub struct FragmentState<'a> { /// The name of the entry point in the compiled shader. There must be a function with this name /// in the shader. pub entry_point: &'a str, - /// Specifies the values of pipeline-overridable constants in the shader module. + /// Advanced options for when this pipeline is compiled /// - /// If an `@id` attribute was specified on the declaration, - /// the key must be the pipeline constant ID as a decimal ASCII number; if not, - /// the key must be the constant's identifier name. - /// - /// The value may represent any of WGSL's concrete scalar types. - pub constants: &'a HashMap, + /// This implements `Default`, and for most users can be set to `Default::default()` + pub compilation_options: PipelineCompilationOptions<'a>, /// The color state of the render targets. pub targets: &'a [Option], } @@ -1754,6 +1746,41 @@ pub struct ComputePassDescriptor<'a> { #[cfg(send_sync)] static_assertions::assert_impl_all!(ComputePassDescriptor<'_>: Send, Sync); +#[derive(Clone, Debug)] +/// Advanced options for use when a pipeline is compiled +/// +/// This implements `Default`, and for most users can be set to `Default::default()` +pub struct PipelineCompilationOptions<'a> { + /// Specifies the values of pipeline-overridable constants in the shader module. + /// + /// If an `@id` attribute was specified on the declaration, + /// the key must be the pipeline constant ID as a decimal ASCII number; if not, + /// the key must be the constant's identifier name. + /// + /// The value may represent any of WGSL's concrete scalar types. + pub constants: &'a HashMap, + /// Whether workgroup scoped memory will be initialized with zero values for this stage. + /// + /// This is required by the WebGPU spec, but may have overhead which can be avoided + /// for cross-platform applications + pub zero_initialize_workgroup_memory: bool, +} + +impl<'a> Default for PipelineCompilationOptions<'a> { + fn default() -> Self { + // HashMap doesn't have a const constructor, due to the use of RandomState + // This does introduce some synchronisation costs, but these should be minor, + // and might be cheaper than the alternative of getting new random state + static DEFAULT_CONSTANTS: std::sync::OnceLock> = + std::sync::OnceLock::new(); + let constants = DEFAULT_CONSTANTS.get_or_init(Default::default); + Self { + constants, + zero_initialize_workgroup_memory: true, + } + } +} + /// Describes a compute pipeline. /// /// For use with [`Device::create_compute_pipeline`]. @@ -1771,14 +1798,10 @@ pub struct ComputePipelineDescriptor<'a> { /// The name of the entry point in the compiled shader. There must be a function with this name /// and no return value in the shader. pub entry_point: &'a str, - /// Specifies the values of pipeline-overridable constants in the shader module. + /// Advanced options for when this pipeline is compiled /// - /// If an `@id` attribute was specified on the declaration, - /// the key must be the pipeline constant ID as a decimal ASCII number; if not, - /// the key must be the constant's identifier name. - /// - /// The value may represent any of WGSL's concrete scalar types. - pub constants: &'a HashMap, + /// This implements `Default`, and for most users can be set to `Default::default()` + pub compilation_options: PipelineCompilationOptions<'a>, } #[cfg(send_sync)] static_assertions::assert_impl_all!(ComputePipelineDescriptor<'_>: Send, Sync);