From c46d5f290d56e1629151ec3fedd5a3c63849d1bc Mon Sep 17 00:00:00 2001 From: Brad Werth Date: Fri, 30 Aug 2024 16:53:20 -0700 Subject: [PATCH] Make bind group an Option for set_bind_group calls. This is just an API change for all the "set_bind_group" calls. Calls that pass a Some() argument should have unchanged behavior. The None cases are left as TODOs. --- CHANGELOG.md | 9 ++++ benches/benches/computepass.rs | 4 +- benches/benches/renderpass.rs | 4 +- deno_webgpu/bundle.rs | 2 +- deno_webgpu/compute_pass.rs | 2 +- deno_webgpu/render_pass.rs | 2 +- examples/src/boids/mod.rs | 2 +- examples/src/bunnymark/mod.rs | 4 +- examples/src/conservative_raster/mod.rs | 2 +- examples/src/cube/mod.rs | 2 +- examples/src/hello_compute/mod.rs | 2 +- examples/src/hello_synchronization/mod.rs | 4 +- examples/src/hello_workgroups/mod.rs | 2 +- examples/src/mipmap/mod.rs | 4 +- examples/src/repeated_compute/mod.rs | 2 +- examples/src/shadow/mod.rs | 8 ++-- examples/src/skybox/mod.rs | 2 +- examples/src/srgb_blend/mod.rs | 2 +- examples/src/storage_texture/mod.rs | 2 +- examples/src/texture_arrays/mod.rs | 6 +-- examples/src/timestamp_queries/mod.rs | 2 +- examples/src/uniform_values/mod.rs | 6 ++- examples/src/water/mod.rs | 6 +-- player/tests/data/bind-group.ron | 2 +- player/tests/data/zero-init-buffer.ron | 2 +- .../tests/data/zero-init-texture-binding.ron | 2 +- tests/src/image.rs | 2 +- tests/tests/bgra8unorm_storage.rs | 2 +- tests/tests/bind_group_layout_dedup.rs | 18 +++---- tests/tests/buffer.rs | 2 +- tests/tests/compute_pass_ownership.rs | 8 ++-- tests/tests/mem_leaks.rs | 2 +- tests/tests/nv12_texture/mod.rs | 2 +- tests/tests/partially_bounded_arrays/mod.rs | 2 +- tests/tests/pipeline_cache.rs | 4 +- tests/tests/poll.rs | 2 +- tests/tests/push_constants.rs | 2 +- tests/tests/regression/issue_3349.rs | 2 +- tests/tests/render_pass_ownership.rs | 8 ++-- tests/tests/shader/mod.rs | 2 +- tests/tests/shader/zero_init_workgroup_mem.rs | 2 +- tests/tests/shader_view_format/mod.rs | 2 +- tests/tests/subgroup_operations/mod.rs | 2 +- tests/tests/vertex_formats/mod.rs | 2 +- tests/tests/vertex_indices/mod.rs | 2 +- wgpu-core/src/command/bundle.rs | 22 +++++++-- wgpu-core/src/command/compute.rs | 37 +++++++++----- wgpu-core/src/command/compute_command.rs | 29 +++++++---- wgpu-core/src/command/mod.rs | 4 +- wgpu-core/src/command/render.rs | 48 ++++++++++++------- wgpu-core/src/command/render_command.rs | 31 ++++++++---- wgpu-hal/src/dynamic/command.rs | 10 +++- wgpu/src/api/compute_pass.rs | 5 +- wgpu/src/api/render_bundle_encoder.rs | 5 +- wgpu/src/api/render_pass.rs | 5 +- wgpu/src/backend/webgpu.rs | 21 ++++++-- wgpu/src/backend/wgpu_core.rs | 23 ++++----- wgpu/src/context.rs | 36 ++++++-------- wgpu/src/util/encoder.rs | 21 ++++++-- 59 files changed, 283 insertions(+), 169 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c3fe5c417d..9d48afc76d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -65,6 +65,15 @@ traits that have now been implemented for `wgpu` resources. By @teoxoy [#6134](https://github.com/gfx-rs/wgpu/pull/6134). +#### `set_bind_group` now takes an `Option` for the bind group argument. + +https://gpuweb.github.io/gpuweb/#programmable-passes-bind-groups specifies that bindGroup +is nullable. This change is the start of implementing this part of the spec. Callers that +specify a `Some()` value should have unchanged behavior. Handling of `None` values still +needs to be implemented by backends. + +By @bradwerth [#6216](https://github.com/gfx-rs/wgpu/pull/6216). + ### New Features #### Naga diff --git a/benches/benches/computepass.rs b/benches/benches/computepass.rs index 2af1413605..959dc05e6f 100644 --- a/benches/benches/computepass.rs +++ b/benches/benches/computepass.rs @@ -389,7 +389,7 @@ impl ComputepassState { let end_idx = start_idx + dispatch_per_pass; for dispatch_idx in start_idx..end_idx { compute_pass.set_pipeline(&self.pipeline); - compute_pass.set_bind_group(0, &self.bind_groups[dispatch_idx], &[]); + compute_pass.set_bind_group(0, Some(&self.bind_groups[dispatch_idx]), &[]); compute_pass.dispatch_workgroups(1, 1, 1); } @@ -412,7 +412,7 @@ impl ComputepassState { }); compute_pass.set_pipeline(self.bindless_pipeline.as_ref().unwrap()); - compute_pass.set_bind_group(0, self.bindless_bind_group.as_ref().unwrap(), &[]); + compute_pass.set_bind_group(0, Some(self.bindless_bind_group.as_ref().unwrap()), &[]); for _ in 0..dispatch_count_bindless { compute_pass.dispatch_workgroups(1, 1, 1); } diff --git a/benches/benches/renderpass.rs b/benches/benches/renderpass.rs index 7f2e14116e..0458891b75 100644 --- a/benches/benches/renderpass.rs +++ b/benches/benches/renderpass.rs @@ -367,7 +367,7 @@ impl RenderpassState { let end_idx = start_idx + draws_per_pass; for draw_idx in start_idx..end_idx { render_pass.set_pipeline(&self.pipeline); - render_pass.set_bind_group(0, &self.bind_groups[draw_idx], &[]); + render_pass.set_bind_group(0, Some(&self.bind_groups[draw_idx]), &[]); for i in 0..VERTEX_BUFFERS_PER_DRAW { render_pass.set_vertex_buffer( i as u32, @@ -410,7 +410,7 @@ impl RenderpassState { }); render_pass.set_pipeline(self.bindless_pipeline.as_ref().unwrap()); - render_pass.set_bind_group(0, self.bindless_bind_group.as_ref().unwrap(), &[]); + render_pass.set_bind_group(0, Some(self.bindless_bind_group.as_ref().unwrap()), &[]); for i in 0..VERTEX_BUFFERS_PER_DRAW { render_pass.set_vertex_buffer(i as u32, self.vertex_buffers[0].slice(..)); } diff --git a/deno_webgpu/bundle.rs b/deno_webgpu/bundle.rs index 0d1421d202..58d179051b 100644 --- a/deno_webgpu/bundle.rs +++ b/deno_webgpu/bundle.rs @@ -150,7 +150,7 @@ pub fn op_webgpu_render_bundle_encoder_set_bind_group( wgpu_core::command::bundle_ffi::wgpu_render_bundle_set_bind_group( &mut render_bundle_encoder_resource.0.borrow_mut(), index, - bind_group_resource.1, + Some(bind_group_resource.1), dynamic_offsets_data.as_ptr(), dynamic_offsets_data.len(), ); diff --git a/deno_webgpu/compute_pass.rs b/deno_webgpu/compute_pass.rs index e3e69860ab..6755e84a6a 100644 --- a/deno_webgpu/compute_pass.rs +++ b/deno_webgpu/compute_pass.rs @@ -136,7 +136,7 @@ pub fn op_webgpu_compute_pass_set_bind_group( .compute_pass_set_bind_group( &mut compute_pass_resource.0.borrow_mut(), index, - bind_group_resource.1, + Some(bind_group_resource.1), dynamic_offsets_data, )?; diff --git a/deno_webgpu/render_pass.rs b/deno_webgpu/render_pass.rs index 2d4557cf03..4929fbbe90 100644 --- a/deno_webgpu/render_pass.rs +++ b/deno_webgpu/render_pass.rs @@ -231,7 +231,7 @@ pub fn op_webgpu_render_pass_set_bind_group( .render_pass_set_bind_group( &mut render_pass_resource.0.borrow_mut(), index, - bind_group_resource.1, + Some(bind_group_resource.1), dynamic_offsets_data, )?; diff --git a/examples/src/boids/mod.rs b/examples/src/boids/mod.rs index f7875ed764..c527be96d9 100644 --- a/examples/src/boids/mod.rs +++ b/examples/src/boids/mod.rs @@ -298,7 +298,7 @@ impl crate::framework::Example for Example { timestamp_writes: None, }); cpass.set_pipeline(&self.compute_pipeline); - cpass.set_bind_group(0, &self.particle_bind_groups[self.frame_num % 2], &[]); + cpass.set_bind_group(0, Some(&self.particle_bind_groups[self.frame_num % 2]), &[]); cpass.dispatch_workgroups(self.work_group_count, 1, 1); } command_encoder.pop_debug_group(); diff --git a/examples/src/bunnymark/mod.rs b/examples/src/bunnymark/mod.rs index 54bdc2a941..8df973e238 100644 --- a/examples/src/bunnymark/mod.rs +++ b/examples/src/bunnymark/mod.rs @@ -118,11 +118,11 @@ impl Example { occlusion_query_set: None, }); rpass.set_pipeline(&self.pipeline); - rpass.set_bind_group(0, &self.global_group, &[]); + rpass.set_bind_group(0, Some(&self.global_group), &[]); for i in 0..self.bunnies.len() { let offset = (i as wgpu::DynamicOffset) * (uniform_alignment as wgpu::DynamicOffset); - rpass.set_bind_group(1, &self.local_group, &[offset]); + rpass.set_bind_group(1, Some(&self.local_group), &[offset]); rpass.draw(0..4, 0..1); } } diff --git a/examples/src/conservative_raster/mod.rs b/examples/src/conservative_raster/mod.rs index d029134756..46fb8742a0 100644 --- a/examples/src/conservative_raster/mod.rs +++ b/examples/src/conservative_raster/mod.rs @@ -305,7 +305,7 @@ impl crate::framework::Example for Example { }); rpass.set_pipeline(&self.pipeline_upscale); - rpass.set_bind_group(0, &self.bind_group_upscale, &[]); + rpass.set_bind_group(0, Some(&self.bind_group_upscale), &[]); rpass.draw(0..3, 0..1); if let Some(pipeline_lines) = &self.pipeline_lines { diff --git a/examples/src/cube/mod.rs b/examples/src/cube/mod.rs index 00e2ffcfc3..78dc06e061 100644 --- a/examples/src/cube/mod.rs +++ b/examples/src/cube/mod.rs @@ -361,7 +361,7 @@ impl crate::framework::Example for Example { }); rpass.push_debug_group("Prepare data for draw."); rpass.set_pipeline(&self.pipeline); - rpass.set_bind_group(0, &self.bind_group, &[]); + rpass.set_bind_group(0, Some(&self.bind_group), &[]); rpass.set_index_buffer(self.index_buf.slice(..), wgpu::IndexFormat::Uint16); rpass.set_vertex_buffer(0, self.vertex_buf.slice(..)); rpass.pop_debug_group(); diff --git a/examples/src/hello_compute/mod.rs b/examples/src/hello_compute/mod.rs index a5257c07ff..e53f49fa43 100644 --- a/examples/src/hello_compute/mod.rs +++ b/examples/src/hello_compute/mod.rs @@ -135,7 +135,7 @@ async fn execute_gpu_inner( timestamp_writes: None, }); cpass.set_pipeline(&compute_pipeline); - cpass.set_bind_group(0, &bind_group, &[]); + cpass.set_bind_group(0, Some(&bind_group), &[]); cpass.insert_debug_marker("compute collatz iterations"); cpass.dispatch_workgroups(numbers.len() as u32, 1, 1); // Number of cells to run, the (x,y,z) size of item being processed } diff --git a/examples/src/hello_synchronization/mod.rs b/examples/src/hello_synchronization/mod.rs index 20743549f3..fad5d7a9da 100644 --- a/examples/src/hello_synchronization/mod.rs +++ b/examples/src/hello_synchronization/mod.rs @@ -128,7 +128,7 @@ async fn execute( timestamp_writes: None, }); compute_pass.set_pipeline(&patient_pipeline); - compute_pass.set_bind_group(0, &bind_group, &[]); + compute_pass.set_bind_group(0, Some(&bind_group), &[]); compute_pass.dispatch_workgroups(local_patient_workgroup_results.len() as u32, 1, 1); } queue.submit(Some(command_encoder.finish())); @@ -150,7 +150,7 @@ async fn execute( timestamp_writes: None, }); compute_pass.set_pipeline(&hasty_pipeline); - compute_pass.set_bind_group(0, &bind_group, &[]); + compute_pass.set_bind_group(0, Some(&bind_group), &[]); compute_pass.dispatch_workgroups(local_patient_workgroup_results.len() as u32, 1, 1); } queue.submit(Some(command_encoder.finish())); diff --git a/examples/src/hello_workgroups/mod.rs b/examples/src/hello_workgroups/mod.rs index d140bc5b06..7a653cf3e8 100644 --- a/examples/src/hello_workgroups/mod.rs +++ b/examples/src/hello_workgroups/mod.rs @@ -127,7 +127,7 @@ async fn run() { timestamp_writes: None, }); compute_pass.set_pipeline(&pipeline); - compute_pass.set_bind_group(0, &bind_group, &[]); + compute_pass.set_bind_group(0, Some(&bind_group), &[]); /* Note that since each workgroup will cover both arrays, we only need to cover the length of one array. */ compute_pass.dispatch_workgroups(local_a.len() as u32, 1, 1); diff --git a/examples/src/mipmap/mod.rs b/examples/src/mipmap/mod.rs index a3f7833b4c..179970ad7f 100644 --- a/examples/src/mipmap/mod.rs +++ b/examples/src/mipmap/mod.rs @@ -180,7 +180,7 @@ impl Example { ); } rpass.set_pipeline(&pipeline); - rpass.set_bind_group(0, &bind_group, &[]); + rpass.set_bind_group(0, Some(&bind_group), &[]); rpass.draw(0..3, 0..1); if let Some(ref query_sets) = query_sets { rpass.write_timestamp(&query_sets.timestamp, timestamp_query_index_base + 1); @@ -497,7 +497,7 @@ impl crate::framework::Example for Example { occlusion_query_set: None, }); rpass.set_pipeline(&self.draw_pipeline); - rpass.set_bind_group(0, &self.bind_group, &[]); + rpass.set_bind_group(0, Some(&self.bind_group), &[]); rpass.draw(0..4, 0..1); } diff --git a/examples/src/repeated_compute/mod.rs b/examples/src/repeated_compute/mod.rs index 5dac9ce7c2..83dcd4099e 100644 --- a/examples/src/repeated_compute/mod.rs +++ b/examples/src/repeated_compute/mod.rs @@ -59,7 +59,7 @@ async fn compute(local_buffer: &mut [u32], context: &WgpuContext) { timestamp_writes: None, }); compute_pass.set_pipeline(&context.pipeline); - compute_pass.set_bind_group(0, &context.bind_group, &[]); + compute_pass.set_bind_group(0, Some(&context.bind_group), &[]); compute_pass.dispatch_workgroups(local_buffer.len() as u32, 1, 1); } // We finish the compute pass by dropping it. diff --git a/examples/src/shadow/mod.rs b/examples/src/shadow/mod.rs index 5e3511ed81..a7edcce7e8 100644 --- a/examples/src/shadow/mod.rs +++ b/examples/src/shadow/mod.rs @@ -779,10 +779,10 @@ impl crate::framework::Example for Example { occlusion_query_set: None, }); pass.set_pipeline(&self.shadow_pass.pipeline); - pass.set_bind_group(0, &self.shadow_pass.bind_group, &[]); + pass.set_bind_group(0, Some(&self.shadow_pass.bind_group), &[]); for entity in &self.entities { - pass.set_bind_group(1, &self.entity_bind_group, &[entity.uniform_offset]); + pass.set_bind_group(1, Some(&self.entity_bind_group), &[entity.uniform_offset]); pass.set_index_buffer(entity.index_buf.slice(..), entity.index_format); pass.set_vertex_buffer(0, entity.vertex_buf.slice(..)); pass.draw_indexed(0..entity.index_count as u32, 0, 0..1); @@ -823,10 +823,10 @@ impl crate::framework::Example for Example { occlusion_query_set: None, }); pass.set_pipeline(&self.forward_pass.pipeline); - pass.set_bind_group(0, &self.forward_pass.bind_group, &[]); + pass.set_bind_group(0, Some(&self.forward_pass.bind_group), &[]); for entity in &self.entities { - pass.set_bind_group(1, &self.entity_bind_group, &[entity.uniform_offset]); + pass.set_bind_group(1, Some(&self.entity_bind_group), &[entity.uniform_offset]); pass.set_index_buffer(entity.index_buf.slice(..), entity.index_format); pass.set_vertex_buffer(0, entity.vertex_buf.slice(..)); pass.draw_indexed(0..entity.index_count as u32, 0, 0..1); diff --git a/examples/src/skybox/mod.rs b/examples/src/skybox/mod.rs index 7397d88466..82e58ef6d5 100644 --- a/examples/src/skybox/mod.rs +++ b/examples/src/skybox/mod.rs @@ -451,7 +451,7 @@ impl crate::framework::Example for Example { occlusion_query_set: None, }); - rpass.set_bind_group(0, &self.bind_group, &[]); + rpass.set_bind_group(0, Some(&self.bind_group), &[]); rpass.set_pipeline(&self.entity_pipeline); for entity in self.entities.iter() { diff --git a/examples/src/srgb_blend/mod.rs b/examples/src/srgb_blend/mod.rs index 63e5e79cb5..822d95d3c4 100644 --- a/examples/src/srgb_blend/mod.rs +++ b/examples/src/srgb_blend/mod.rs @@ -202,7 +202,7 @@ impl crate::framework::Example for Example { }); rpass.push_debug_group("Prepare data for draw."); rpass.set_pipeline(&self.pipeline); - rpass.set_bind_group(0, &self.bind_group, &[]); + rpass.set_bind_group(0, Some(&self.bind_group), &[]); rpass.set_index_buffer(self.index_buf.slice(..), wgpu::IndexFormat::Uint16); rpass.set_vertex_buffer(0, self.vertex_buf.slice(..)); rpass.pop_debug_group(); diff --git a/examples/src/storage_texture/mod.rs b/examples/src/storage_texture/mod.rs index 904a721f07..a687584196 100644 --- a/examples/src/storage_texture/mod.rs +++ b/examples/src/storage_texture/mod.rs @@ -117,7 +117,7 @@ async fn run(_path: Option) { label: None, timestamp_writes: None, }); - compute_pass.set_bind_group(0, &bind_group, &[]); + compute_pass.set_bind_group(0, Some(&bind_group), &[]); compute_pass.set_pipeline(&pipeline); compute_pass.dispatch_workgroups(TEXTURE_DIMS.0 as u32, TEXTURE_DIMS.1 as u32, 1); } diff --git a/examples/src/texture_arrays/mod.rs b/examples/src/texture_arrays/mod.rs index 00b90603fd..8c81950e9a 100644 --- a/examples/src/texture_arrays/mod.rs +++ b/examples/src/texture_arrays/mod.rs @@ -391,12 +391,12 @@ impl crate::framework::Example for Example { rpass.set_vertex_buffer(0, self.vertex_buffer.slice(..)); rpass.set_index_buffer(self.index_buffer.slice(..), self.index_format); if self.uniform_workaround { - rpass.set_bind_group(0, &self.bind_group, &[0]); + rpass.set_bind_group(0, Some(&self.bind_group), &[0]); rpass.draw_indexed(0..6, 0, 0..1); - rpass.set_bind_group(0, &self.bind_group, &[256]); + rpass.set_bind_group(0, Some(&self.bind_group), &[256]); rpass.draw_indexed(6..12, 0, 0..1); } else { - rpass.set_bind_group(0, &self.bind_group, &[0]); + rpass.set_bind_group(0, Some(&self.bind_group), &[0]); rpass.draw_indexed(0..12, 0, 0..1); } diff --git a/examples/src/timestamp_queries/mod.rs b/examples/src/timestamp_queries/mod.rs index 0daa71c0ea..2921ae4c85 100644 --- a/examples/src/timestamp_queries/mod.rs +++ b/examples/src/timestamp_queries/mod.rs @@ -324,7 +324,7 @@ fn compute_pass( }); *next_unused_query += 2; cpass.set_pipeline(&compute_pipeline); - cpass.set_bind_group(0, &bind_group, &[]); + cpass.set_bind_group(0, Some(&bind_group), &[]); cpass.dispatch_workgroups(1, 1, 1); if device .features() diff --git a/examples/src/uniform_values/mod.rs b/examples/src/uniform_values/mod.rs index 770fcd1aaa..1ef58de09a 100644 --- a/examples/src/uniform_values/mod.rs +++ b/examples/src/uniform_values/mod.rs @@ -327,7 +327,11 @@ async fn run(event_loop: EventLoop<()>, window: Arc) { }); render_pass.set_pipeline(&wgpu_context_ref.pipeline); // (9) - render_pass.set_bind_group(0, &wgpu_context_ref.bind_group, &[]); + render_pass.set_bind_group( + 0, + Some(&wgpu_context_ref.bind_group), + &[], + ); render_pass.draw(0..3, 0..1); } wgpu_context_ref.queue.submit(Some(encoder.finish())); diff --git a/examples/src/water/mod.rs b/examples/src/water/mod.rs index 7f766034a4..505f5707e5 100644 --- a/examples/src/water/mod.rs +++ b/examples/src/water/mod.rs @@ -630,7 +630,7 @@ impl crate::framework::Example for Example { multiview: None, }); encoder.set_pipeline(&terrain_pipeline); - encoder.set_bind_group(0, &terrain_flipped_bind_group, &[]); + encoder.set_bind_group(0, Some(&terrain_flipped_bind_group), &[]); encoder.set_vertex_buffer(0, terrain_vertex_buf.slice(..)); encoder.draw(0..terrain_vertices.len() as u32, 0..1); encoder.finish(&wgpu::RenderBundleDescriptor::default()) @@ -784,7 +784,7 @@ impl crate::framework::Example for Example { occlusion_query_set: None, }); rpass.set_pipeline(&self.terrain_pipeline); - rpass.set_bind_group(0, &self.terrain_normal_bind_group, &[]); + rpass.set_bind_group(0, Some(&self.terrain_normal_bind_group), &[]); rpass.set_vertex_buffer(0, self.terrain_vertex_buf.slice(..)); rpass.draw(0..self.terrain_vertex_count as u32, 0..1); } @@ -811,7 +811,7 @@ impl crate::framework::Example for Example { }); rpass.set_pipeline(&self.water_pipeline); - rpass.set_bind_group(0, &self.water_bind_group, &[]); + rpass.set_bind_group(0, Some(&self.water_bind_group), &[]); rpass.set_vertex_buffer(0, self.water_vertex_buf.slice(..)); rpass.draw(0..self.water_vertex_count as u32, 0..1); } diff --git a/player/tests/data/bind-group.ron b/player/tests/data/bind-group.ron index a53a77b16f..87b3a1c725 100644 --- a/player/tests/data/bind-group.ron +++ b/player/tests/data/bind-group.ron @@ -70,7 +70,7 @@ SetBindGroup( index: 0, num_dynamic_offsets: 0, - bind_group_id: Id(0, 1, Empty), + bind_group_id: Some(Id(0, 1, Empty)), ), SetPipeline(Id(0, 1, Empty)), ], diff --git a/player/tests/data/zero-init-buffer.ron b/player/tests/data/zero-init-buffer.ron index b13786e262..2b3f4a890e 100644 --- a/player/tests/data/zero-init-buffer.ron +++ b/player/tests/data/zero-init-buffer.ron @@ -149,7 +149,7 @@ SetBindGroup( index: 0, num_dynamic_offsets: 0, - bind_group_id: Id(0, 1, Empty), + bind_group_id: Some(Id(0, 1, Empty)), ), Dispatch((4, 1, 1)), ], diff --git a/player/tests/data/zero-init-texture-binding.ron b/player/tests/data/zero-init-texture-binding.ron index ba4951c198..e828b6c130 100644 --- a/player/tests/data/zero-init-texture-binding.ron +++ b/player/tests/data/zero-init-texture-binding.ron @@ -150,7 +150,7 @@ SetBindGroup( index: 0, num_dynamic_offsets: 0, - bind_group_id: Id(0, 1, Empty), + bind_group_id: Some(Id(0, 1, Empty)), ), Dispatch((4, 1, 1)), ], diff --git a/tests/src/image.rs b/tests/src/image.rs index e72d3ee442..602d93c4e2 100644 --- a/tests/src/image.rs +++ b/tests/src/image.rs @@ -377,7 +377,7 @@ fn copy_via_compute( let mut pass = encoder.begin_compute_pass(&ComputePassDescriptor::default()); pass.set_pipeline(&pipeline_copy); - pass.set_bind_group(0, &bg, &[]); + pass.set_bind_group(0, Some(&bg), &[]); pass.dispatch_workgroups(1, 1, 1); } diff --git a/tests/tests/bgra8unorm_storage.rs b/tests/tests/bgra8unorm_storage.rs index 0859473b2f..fa8310c7ea 100644 --- a/tests/tests/bgra8unorm_storage.rs +++ b/tests/tests/bgra8unorm_storage.rs @@ -110,7 +110,7 @@ static BGRA8_UNORM_STORAGE: GpuTestConfiguration = GpuTestConfiguration::new() timestamp_writes: None, }); - pass.set_bind_group(0, &bg, &[]); + pass.set_bind_group(0, Some(&bg), &[]); pass.set_pipeline(&pipeline); pass.dispatch_workgroups(256, 256, 1); } diff --git a/tests/tests/bind_group_layout_dedup.rs b/tests/tests/bind_group_layout_dedup.rs index b322b019b9..f81360288f 100644 --- a/tests/tests/bind_group_layout_dedup.rs +++ b/tests/tests/bind_group_layout_dedup.rs @@ -92,11 +92,11 @@ async fn bgl_dedupe(ctx: TestingContext) { timestamp_writes: None, }); - pass.set_bind_group(0, &bg_1b, &[]); + pass.set_bind_group(0, Some(&bg_1b), &[]); pass.set_pipeline(&pipeline); pass.dispatch_workgroups(1, 1, 1); - pass.set_bind_group(0, &bg_1a, &[]); + pass.set_bind_group(0, Some(&bg_1a), &[]); pass.dispatch_workgroups(1, 1, 1); drop(pass); @@ -179,7 +179,7 @@ fn bgl_dedupe_with_dropped_user_handle(ctx: TestingContext) { timestamp_writes: None, }); - pass.set_bind_group(0, &bg, &[]); + pass.set_bind_group(0, Some(&bg), &[]); pass.set_pipeline(&pipeline); pass.dispatch_workgroups(1, 1, 1); @@ -250,10 +250,10 @@ fn get_derived_bgl(ctx: TestingContext) { pass.set_pipeline(&pipeline); - pass.set_bind_group(0, &bg1, &[]); + pass.set_bind_group(0, Some(&bg1), &[]); pass.dispatch_workgroups(1, 1, 1); - pass.set_bind_group(0, &bg2, &[]); + pass.set_bind_group(0, Some(&bg2), &[]); pass.dispatch_workgroups(1, 1, 1); drop(pass); @@ -313,7 +313,7 @@ fn separate_pipelines_have_incompatible_derived_bgls(ctx: TestingContext) { pass.set_pipeline(&pipeline1); // We use the wrong bind group for this pipeline here. This should fail. - pass.set_bind_group(0, &bg2, &[]); + pass.set_bind_group(0, Some(&bg2), &[]); pass.dispatch_workgroups(1, 1, 1); fail( @@ -385,7 +385,7 @@ fn derived_bgls_incompatible_with_regular_bgls(ctx: TestingContext) { pass.set_pipeline(&pipeline); - pass.set_bind_group(0, &bg, &[]); + pass.set_bind_group(0, Some(&bg), &[]); pass.dispatch_workgroups(1, 1, 1); fail( @@ -476,8 +476,8 @@ fn bgl_dedupe_derived(ctx: TestingContext) { timestamp_writes: None, }); pass.set_pipeline(&pipeline); - pass.set_bind_group(0, &bind_group_0, &[]); - pass.set_bind_group(1, &bind_group_1, &[]); + pass.set_bind_group(0, Some(&bind_group_0), &[]); + pass.set_bind_group(1, Some(&bind_group_1), &[]); pass.dispatch_workgroups(1, 1, 1); drop(pass); diff --git a/tests/tests/buffer.rs b/tests/tests/buffer.rs index b3a48f178a..f76a9fc352 100644 --- a/tests/tests/buffer.rs +++ b/tests/tests/buffer.rs @@ -328,7 +328,7 @@ static MINIMUM_BUFFER_BINDING_SIZE_DISPATCH: GpuTestConfiguration = GpuTestConfi timestamp_writes: None, }); - pass.set_bind_group(0, &bind_group, &[]); + pass.set_bind_group(0, Some(&bind_group), &[]); pass.set_pipeline(&pipeline); pass.dispatch_workgroups(1, 1, 1); diff --git a/tests/tests/compute_pass_ownership.rs b/tests/tests/compute_pass_ownership.rs index df50f51e05..6b5bad8cf7 100644 --- a/tests/tests/compute_pass_ownership.rs +++ b/tests/tests/compute_pass_ownership.rs @@ -45,7 +45,7 @@ async fn compute_pass_resource_ownership(ctx: TestingContext) { { let mut cpass = encoder.begin_compute_pass(&wgpu::ComputePassDescriptor::default()); cpass.set_pipeline(&pipeline); - cpass.set_bind_group(0, &bind_group, &[]); + cpass.set_bind_group(0, Some(&bind_group), &[]); cpass.dispatch_workgroups_indirect(&indirect_buffer, 0); // Now drop all resources we set. Then do a device poll to make sure the resources are really not dropped too early, no matter what. @@ -95,7 +95,7 @@ async fn compute_pass_query_set_ownership_pipeline_statistics(ctx: TestingContex { let mut cpass = encoder.begin_compute_pass(&wgpu::ComputePassDescriptor::default()); cpass.set_pipeline(&pipeline); - cpass.set_bind_group(0, &bind_group, &[]); + cpass.set_bind_group(0, Some(&bind_group), &[]); cpass.begin_pipeline_statistics_query(&query_set, 0); cpass.dispatch_workgroups(1, 1, 1); cpass.end_pipeline_statistics_query(); @@ -153,7 +153,7 @@ async fn compute_pass_query_set_ownership_timestamps(ctx: TestingContext) { }), }); cpass.set_pipeline(&pipeline); - cpass.set_bind_group(0, &bind_group, &[]); + cpass.set_bind_group(0, Some(&bind_group), &[]); cpass.write_timestamp(&query_set_write_timestamp, 0); cpass.dispatch_workgroups(1, 1, 1); @@ -203,7 +203,7 @@ async fn compute_pass_keep_encoder_alive(ctx: TestingContext) { // Record some draw commands. cpass.set_pipeline(&pipeline); - cpass.set_bind_group(0, &bind_group, &[]); + cpass.set_bind_group(0, Some(&bind_group), &[]); cpass.dispatch_workgroups_indirect(&indirect_buffer, 0); // Dropping the pass will still execute the pass, even though there's no way to submit it. diff --git a/tests/tests/mem_leaks.rs b/tests/tests/mem_leaks.rs index 75de0776e8..84879efda3 100644 --- a/tests/tests/mem_leaks.rs +++ b/tests/tests/mem_leaks.rs @@ -194,7 +194,7 @@ async fn draw_test_with_reports( }); rpass.set_pipeline(&pipeline); - rpass.set_bind_group(0, &bg, &[]); + rpass.set_bind_group(0, Some(&bg), &[]); let global_report = ctx.instance.generate_report().unwrap(); let report = global_report.hub_report(); diff --git a/tests/tests/nv12_texture/mod.rs b/tests/tests/nv12_texture/mod.rs index 6ded163a3a..d6af8496f7 100644 --- a/tests/tests/nv12_texture/mod.rs +++ b/tests/tests/nv12_texture/mod.rs @@ -115,7 +115,7 @@ static NV12_TEXTURE_CREATION_SAMPLING: GpuTestConfiguration = GpuTestConfigurati occlusion_query_set: None, }); rpass.set_pipeline(&pipeline); - rpass.set_bind_group(0, &bind_group, &[]); + rpass.set_bind_group(0, Some(&bind_group), &[]); rpass.draw(0..4, 0..1); drop(rpass); ctx.queue.submit(Some(encoder.finish())); diff --git a/tests/tests/partially_bounded_arrays/mod.rs b/tests/tests/partially_bounded_arrays/mod.rs index 195fd88dd4..4e6d6fc097 100644 --- a/tests/tests/partially_bounded_arrays/mod.rs +++ b/tests/tests/partially_bounded_arrays/mod.rs @@ -90,7 +90,7 @@ static PARTIALLY_BOUNDED_ARRAY: GpuTestConfiguration = GpuTestConfiguration::new timestamp_writes: None, }); cpass.set_pipeline(&compute_pipeline); - cpass.set_bind_group(0, &bind_group, &[]); + cpass.set_bind_group(0, Some(&bind_group), &[]); cpass.dispatch_workgroups(1, 1, 1); } diff --git a/tests/tests/pipeline_cache.rs b/tests/tests/pipeline_cache.rs index 67e9e68270..c88a871c75 100644 --- a/tests/tests/pipeline_cache.rs +++ b/tests/tests/pipeline_cache.rs @@ -32,7 +32,7 @@ fn shader() -> String { r#" @group(0) @binding(0) var output: array; - + @compute @workgroup_size(1) fn main() {{ {body} @@ -167,7 +167,7 @@ async fn validate_pipeline( timestamp_writes: None, }); cpass.set_pipeline(&pipeline); - cpass.set_bind_group(0, bind_group, &[]); + cpass.set_bind_group(0, Some(bind_group), &[]); cpass.dispatch_workgroups(1, 1, 1); } diff --git a/tests/tests/poll.rs b/tests/tests/poll.rs index 7e99cbcd7d..aeea2617f6 100644 --- a/tests/tests/poll.rs +++ b/tests/tests/poll.rs @@ -46,7 +46,7 @@ fn generate_dummy_work(ctx: &TestingContext) -> CommandBuffer { .create_command_encoder(&CommandEncoderDescriptor::default()); let mut cpass = cmd_buf.begin_compute_pass(&ComputePassDescriptor::default()); - cpass.set_bind_group(0, &bind_group, &[]); + cpass.set_bind_group(0, Some(&bind_group), &[]); drop(cpass); cmd_buf.finish() diff --git a/tests/tests/push_constants.rs b/tests/tests/push_constants.rs index 905578d533..047fe5c8f2 100644 --- a/tests/tests/push_constants.rs +++ b/tests/tests/push_constants.rs @@ -119,7 +119,7 @@ async fn partial_update_test(ctx: TestingContext) { timestamp_writes: None, }); cpass.set_pipeline(&pipeline); - cpass.set_bind_group(0, &bind_group, &[]); + cpass.set_bind_group(0, Some(&bind_group), &[]); // -- Dispatch 0 -- diff --git a/tests/tests/regression/issue_3349.rs b/tests/tests/regression/issue_3349.rs index 21929bd9b7..b1361722fd 100644 --- a/tests/tests/regression/issue_3349.rs +++ b/tests/tests/regression/issue_3349.rs @@ -163,7 +163,7 @@ async fn multi_stage_data_binding_test(ctx: TestingContext) { }); rpass.set_pipeline(&pipeline); - rpass.set_bind_group(0, &bg, &[]); + rpass.set_bind_group(0, Some(&bg), &[]); rpass.set_push_constants( wgpu::ShaderStages::VERTEX_FRAGMENT, 0, diff --git a/tests/tests/render_pass_ownership.rs b/tests/tests/render_pass_ownership.rs index 7c41c85916..5086d38d91 100644 --- a/tests/tests/render_pass_ownership.rs +++ b/tests/tests/render_pass_ownership.rs @@ -87,7 +87,7 @@ async fn render_pass_resource_ownership(ctx: TestingContext) { drop(depth_stencil_view); rpass.set_pipeline(&pipeline); - rpass.set_bind_group(0, &bind_group, &[]); + rpass.set_bind_group(0, Some(&bind_group), &[]); rpass.set_vertex_buffer(0, vertex_buffer.slice(..)); rpass.set_index_buffer(index_buffer.slice(..), wgpu::IndexFormat::Uint32); rpass.begin_occlusion_query(0); @@ -163,7 +163,7 @@ async fn render_pass_query_set_ownership_pipeline_statistics(ctx: TestingContext ..Default::default() }); rpass.set_pipeline(&pipeline); - rpass.set_bind_group(0, &bind_group, &[]); + rpass.set_bind_group(0, Some(&bind_group), &[]); rpass.set_vertex_buffer(0, vertex_buffer.slice(..)); rpass.set_index_buffer(index_buffer.slice(..), wgpu::IndexFormat::Uint32); rpass.begin_pipeline_statistics_query(&query_set, 0); @@ -242,7 +242,7 @@ async fn render_pass_query_set_ownership_timestamps(ctx: TestingContext) { rpass.write_timestamp(&query_set_write_timestamp, 0); rpass.set_pipeline(&pipeline); - rpass.set_bind_group(0, &bind_group, &[]); + rpass.set_bind_group(0, Some(&bind_group), &[]); rpass.set_vertex_buffer(0, vertex_buffer.slice(..)); rpass.set_index_buffer(index_buffer.slice(..), wgpu::IndexFormat::Uint32); rpass.draw(0..3, 0..1); @@ -305,7 +305,7 @@ async fn render_pass_keep_encoder_alive(ctx: TestingContext) { // Record some a draw command. rpass.set_pipeline(&pipeline); - rpass.set_bind_group(0, &bind_group, &[]); + rpass.set_bind_group(0, Some(&bind_group), &[]); rpass.set_vertex_buffer(0, vertex_buffer.slice(..)); rpass.set_index_buffer(index_buffer.slice(..), wgpu::IndexFormat::Uint32); rpass.draw(0..3, 0..1); diff --git a/tests/tests/shader/mod.rs b/tests/tests/shader/mod.rs index 7d6ed7aaaa..2e7dfd9424 100644 --- a/tests/tests/shader/mod.rs +++ b/tests/tests/shader/mod.rs @@ -349,7 +349,7 @@ async fn shader_input_output_test( timestamp_writes: None, }); cpass.set_pipeline(&pipeline); - cpass.set_bind_group(0, &bg, &[]); + cpass.set_bind_group(0, Some(&bg), &[]); if let InputStorageType::PushConstant = storage_type { cpass.set_push_constants(0, bytemuck::cast_slice(&test.input_values)) diff --git a/tests/tests/shader/zero_init_workgroup_mem.rs b/tests/tests/shader/zero_init_workgroup_mem.rs index beacb4fcc8..084498770e 100644 --- a/tests/tests/shader/zero_init_workgroup_mem.rs +++ b/tests/tests/shader/zero_init_workgroup_mem.rs @@ -119,7 +119,7 @@ static ZERO_INIT_WORKGROUP_MEMORY: GpuTestConfiguration = GpuTestConfiguration:: cpass.set_pipeline(&pipeline_read); for i in 0..NR_OF_DISPATCHES { - cpass.set_bind_group(0, &bg, &[i * BUFFER_BINDING_SIZE]); + cpass.set_bind_group(0, Some(&bg), &[i * BUFFER_BINDING_SIZE]); cpass.dispatch_workgroups(DISPATCH_SIZE.0, DISPATCH_SIZE.1, DISPATCH_SIZE.2); } drop(cpass); diff --git a/tests/tests/shader_view_format/mod.rs b/tests/tests/shader_view_format/mod.rs index b2bc0426eb..052573bc0d 100644 --- a/tests/tests/shader_view_format/mod.rs +++ b/tests/tests/shader_view_format/mod.rs @@ -148,7 +148,7 @@ async fn reinterpret( occlusion_query_set: None, }); rpass.set_pipeline(&pipeline); - rpass.set_bind_group(0, &bind_group, &[]); + rpass.set_bind_group(0, Some(&bind_group), &[]); rpass.draw(0..3, 0..1); drop(rpass); ctx.queue.submit(Some(encoder.finish())); diff --git a/tests/tests/subgroup_operations/mod.rs b/tests/tests/subgroup_operations/mod.rs index b11dd7f6a2..ecf8adfd7d 100644 --- a/tests/tests/subgroup_operations/mod.rs +++ b/tests/tests/subgroup_operations/mod.rs @@ -93,7 +93,7 @@ static SUBGROUP_OPERATIONS: GpuTestConfiguration = GpuTestConfiguration::new() timestamp_writes: None, }); cpass.set_pipeline(&compute_pipeline); - cpass.set_bind_group(0, &bind_group, &[]); + cpass.set_bind_group(0, Some(&bind_group), &[]); cpass.dispatch_workgroups(1, 1, 1); } ctx.queue.submit(Some(encoder.finish())); diff --git a/tests/tests/vertex_formats/mod.rs b/tests/tests/vertex_formats/mod.rs index d2ff09447a..d447ac8f7e 100644 --- a/tests/tests/vertex_formats/mod.rs +++ b/tests/tests/vertex_formats/mod.rs @@ -315,7 +315,7 @@ async fn vertex_formats_common(ctx: TestingContext, tests: &[Test<'_>]) { rpass.set_vertex_buffer(0, buffer_input.slice(..)); rpass.set_pipeline(&pipeline); - rpass.set_bind_group(0, &bg, &[]); + rpass.set_bind_group(0, Some(&bg), &[]); // Draw three vertices and no instance, which is enough to generate the // checksums. diff --git a/tests/tests/vertex_indices/mod.rs b/tests/tests/vertex_indices/mod.rs index d2b6a874f9..5c5ce8a202 100644 --- a/tests/tests/vertex_indices/mod.rs +++ b/tests/tests/vertex_indices/mod.rs @@ -409,7 +409,7 @@ async fn vertex_index_common(ctx: TestingContext) { render_encoder.set_vertex_buffer(1, identity_buffer.slice(..)); render_encoder.set_index_buffer(identity_buffer.slice(..), wgpu::IndexFormat::Uint32); render_encoder.set_pipeline(pipeline); - render_encoder.set_bind_group(0, &bg, &[]); + render_encoder.set_bind_group(0, Some(&bg), &[]); let draws = test.case.draws(); diff --git a/wgpu-core/src/command/bundle.rs b/wgpu-core/src/command/bundle.rs index a7a43e1e2e..775bd5f825 100644 --- a/wgpu-core/src/command/bundle.rs +++ b/wgpu-core/src/command/bundle.rs @@ -582,8 +582,15 @@ fn set_bind_group( dynamic_offsets: &[u32], index: u32, num_dynamic_offsets: usize, - bind_group_id: id::Id, + bind_group_id: Option>, ) -> Result<(), RenderBundleErrorInner> { + if bind_group_id.is_none() { + // TODO: do appropriate cleanup for null bind_group. + return Ok(()); + } + + let bind_group_id = bind_group_id.unwrap(); + let bind_group = bind_group_guard .get_owned(bind_group_id) .map_err(|_| RenderCommandError::InvalidBindGroupId(bind_group_id))?; @@ -981,12 +988,17 @@ impl RenderBundle { num_dynamic_offsets, bind_group, } => { - let raw_bg = bind_group.try_raw(snatch_guard)?; + let mut bg = None; + if bind_group.is_some() { + let bind_group = bind_group.as_ref().unwrap(); + let raw_bg = bind_group.try_raw(snatch_guard)?; + bg = Some(raw_bg); + } unsafe { raw.set_bind_group( pipeline_layout.as_ref().unwrap().raw(), *index, - raw_bg, + bg, &offsets[..*num_dynamic_offsets], ) }; @@ -1501,7 +1513,7 @@ impl State { let offsets = &contents.dynamic_offsets; return Some(ArcRenderCommand::SetBindGroup { index: i.try_into().unwrap(), - bind_group: contents.bind_group.clone(), + bind_group: Some(contents.bind_group.clone()), num_dynamic_offsets: offsets.end - offsets.start, }); } @@ -1581,7 +1593,7 @@ pub mod bundle_ffi { pub unsafe extern "C" fn wgpu_render_bundle_set_bind_group( bundle: &mut RenderBundleEncoder, index: u32, - bind_group_id: id::BindGroupId, + bind_group_id: Option, offsets: *const DynamicOffset, offset_length: usize, ) { diff --git a/wgpu-core/src/command/compute.rs b/wgpu-core/src/command/compute.rs index eb929740c8..2a258f1efb 100644 --- a/wgpu-core/src/command/compute.rs +++ b/wgpu-core/src/command/compute.rs @@ -649,10 +649,8 @@ fn set_bind_group( dynamic_offsets: &[DynamicOffset], index: u32, num_dynamic_offsets: usize, - bind_group: Arc, + bind_group: Option>, ) -> Result<(), ComputePassErrorInner> { - bind_group.same_device_as(cmd_buf)?; - let max_bind_groups = state.device.limits.max_bind_groups; if index >= max_bind_groups { return Err(ComputePassErrorInner::BindGroupIndexOutOfRange { @@ -668,7 +666,16 @@ fn set_bind_group( ); state.dynamic_offset_count += num_dynamic_offsets; + if bind_group.is_none() { + // TODO: Handle bind_group None. + return Ok(()); + } + + let bind_group = bind_group.unwrap(); let bind_group = state.tracker.bind_groups.insert_single(bind_group); + + bind_group.same_device_as(cmd_buf)?; + bind_group.validate_dynamic_bindings(index, &state.temp_offsets)?; state @@ -700,7 +707,7 @@ fn set_bind_group( state.raw_encoder.set_bind_group( pipeline_layout, index + i as u32, - raw_bg, + Some(raw_bg), &e.dynamic_offsets, ); } @@ -745,7 +752,7 @@ fn set_pipeline( state.raw_encoder.set_bind_group( pipeline.layout.raw(), start_index as u32 + i as u32, - raw_bg, + Some(raw_bg), &e.dynamic_offsets, ); } @@ -952,7 +959,7 @@ impl Global { &self, pass: &mut ComputePass, index: u32, - bind_group_id: id::BindGroupId, + bind_group_id: Option, offsets: &[DynamicOffset], ) -> Result<(), ComputePassError> { let scope = PassErrorScope::SetBindGroup; @@ -973,12 +980,18 @@ impl Global { return Ok(()); } - let hub = &self.hub; - let bind_group = hub - .bind_groups - .get(bind_group_id) - .map_err(|_| ComputePassErrorInner::InvalidBindGroupId(bind_group_id)) - .map_pass_err(scope)?; + let mut bind_group = None; + if bind_group_id.is_some() { + let bind_group_id = bind_group_id.unwrap(); + + let hub = &self.hub; + let bg = hub + .bind_groups + .get(bind_group_id) + .map_err(|_| ComputePassErrorInner::InvalidBindGroupId(bind_group_id)) + .map_pass_err(scope)?; + bind_group = Some(bg); + } base.commands.push(ArcComputeCommand::SetBindGroup { index, diff --git a/wgpu-core/src/command/compute_command.rs b/wgpu-core/src/command/compute_command.rs index e16487b7ea..c9db7cf6cb 100644 --- a/wgpu-core/src/command/compute_command.rs +++ b/wgpu-core/src/command/compute_command.rs @@ -13,7 +13,7 @@ pub enum ComputeCommand { SetBindGroup { index: u32, num_dynamic_offsets: usize, - bind_group_id: id::BindGroupId, + bind_group_id: Option, }, SetPipeline(id::ComputePipelineId), @@ -89,16 +89,29 @@ impl ComputeCommand { index, num_dynamic_offsets, bind_group_id, - } => ArcComputeCommand::SetBindGroup { - index, - num_dynamic_offsets, - bind_group: bind_group_guard.get_owned(bind_group_id).map_err(|_| { + } => { + if bind_group_id.is_none() { + return Ok(ArcComputeCommand::SetBindGroup { + index, + num_dynamic_offsets, + bind_group: None, + }); + } + + let bind_group_id = bind_group_id.unwrap(); + let bg = bind_group_guard.get_owned(bind_group_id).map_err(|_| { ComputePassError { scope: PassErrorScope::SetBindGroup, inner: ComputePassErrorInner::InvalidBindGroupId(bind_group_id), } - })?, - }, + })?; + + ArcComputeCommand::SetBindGroup { + index, + num_dynamic_offsets, + bind_group: Some(bg), + } + } ComputeCommand::SetPipeline(pipeline_id) => ArcComputeCommand::SetPipeline( pipelines_guard @@ -185,7 +198,7 @@ pub enum ArcComputeCommand { SetBindGroup { index: u32, num_dynamic_offsets: usize, - bind_group: Arc, + bind_group: Option>, }, SetPipeline(Arc), diff --git a/wgpu-core/src/command/mod.rs b/wgpu-core/src/command/mod.rs index 313bf813a1..b5e7b4b6f0 100644 --- a/wgpu-core/src/command/mod.rs +++ b/wgpu-core/src/command/mod.rs @@ -805,7 +805,7 @@ impl Default for StateChange { #[derive(Debug)] struct BindGroupStateChange { - last_states: [StateChange; hal::MAX_BIND_GROUPS], + last_states: [StateChange>; hal::MAX_BIND_GROUPS], } impl BindGroupStateChange { @@ -817,7 +817,7 @@ impl BindGroupStateChange { fn set_and_check_redundant( &mut self, - bind_group_id: id::BindGroupId, + bind_group_id: Option, index: u32, dynamic_offsets: &mut Vec, offsets: &[wgt::DynamicOffset], diff --git a/wgpu-core/src/command/render.rs b/wgpu-core/src/command/render.rs index f85696ced9..684bf3612a 100644 --- a/wgpu-core/src/command/render.rs +++ b/wgpu-core/src/command/render.rs @@ -635,8 +635,8 @@ pub enum RenderPassErrorInner { SurfaceTextureDropped, #[error("Not enough memory left for render pass")] OutOfMemory, - #[error("The bind group at index {0:?} is invalid")] - InvalidBindGroup(u32), + #[error("BindGroupId {0:?} is invalid")] + InvalidBindGroupId(id::BindGroupId), #[error("Unable to clear non-present/read-only depth")] InvalidDepthOps, #[error("Unable to clear non-present/read-only stencil")] @@ -1934,12 +1934,16 @@ fn set_bind_group( dynamic_offsets: &[DynamicOffset], index: u32, num_dynamic_offsets: usize, - bind_group: Arc, + bind_group: Option>, ) -> Result<(), RenderPassErrorInner> { - api_log!( - "RenderPass::set_bind_group {index} {}", - bind_group.error_ident() - ); + if bind_group.is_none() { + api_log!("RenderPass::set_bind_group {index} None"); + } else { + api_log!( + "RenderPass::set_bind_group {index} {}", + bind_group.as_ref().unwrap().error_ident() + ); + } let max_bind_groups = state.device.limits.max_bind_groups; if index >= max_bind_groups { @@ -1957,6 +1961,12 @@ fn set_bind_group( ); state.dynamic_offset_count += num_dynamic_offsets; + if bind_group.is_none() { + // TODO: Handle bind_group None. + return Ok(()); + } + + let bind_group = bind_group.unwrap(); let bind_group = state.tracker.bind_groups.insert_single(bind_group); bind_group.same_device_as(cmd_buf.as_ref())?; @@ -1999,7 +2009,7 @@ fn set_bind_group( state.raw_encoder.set_bind_group( pipeline_layout, index + i as u32, - raw_bg, + Some(raw_bg), &e.dynamic_offsets, ); } @@ -2073,7 +2083,7 @@ fn set_pipeline( state.raw_encoder.set_bind_group( pipeline.layout.raw(), start_index as u32 + i as u32, - raw_bg, + Some(raw_bg), &e.dynamic_offsets, ); } @@ -2788,7 +2798,7 @@ impl Global { &self, pass: &mut RenderPass, index: u32, - bind_group_id: id::BindGroupId, + bind_group_id: Option, offsets: &[DynamicOffset], ) -> Result<(), RenderPassError> { let scope = PassErrorScope::SetBindGroup; @@ -2808,12 +2818,18 @@ impl Global { return Ok(()); } - let hub = &self.hub; - let bind_group = hub - .bind_groups - .get(bind_group_id) - .map_err(|_| RenderPassErrorInner::InvalidBindGroup(index)) - .map_pass_err(scope)?; + let mut bind_group = None; + if bind_group_id.is_some() { + let bind_group_id = bind_group_id.unwrap(); + + let hub = &self.hub; + let bg = hub + .bind_groups + .get(bind_group_id) + .map_err(|_| RenderPassErrorInner::InvalidBindGroupId(bind_group_id)) + .map_pass_err(scope)?; + bind_group = Some(bg); + } base.commands.push(ArcRenderCommand::SetBindGroup { index, diff --git a/wgpu-core/src/command/render_command.rs b/wgpu-core/src/command/render_command.rs index 891ee3cfbc..48f057e260 100644 --- a/wgpu-core/src/command/render_command.rs +++ b/wgpu-core/src/command/render_command.rs @@ -17,7 +17,7 @@ pub enum RenderCommand { SetBindGroup { index: u32, num_dynamic_offsets: usize, - bind_group_id: id::BindGroupId, + bind_group_id: Option, }, SetPipeline(id::RenderPipelineId), SetIndexBuffer { @@ -147,16 +147,29 @@ impl RenderCommand { index, num_dynamic_offsets, bind_group_id, - } => ArcRenderCommand::SetBindGroup { - index, - num_dynamic_offsets, - bind_group: bind_group_guard.get_owned(bind_group_id).map_err(|_| { + } => { + if bind_group_id.is_none() { + return Ok(ArcRenderCommand::SetBindGroup { + index, + num_dynamic_offsets, + bind_group: None, + }); + } + + let bind_group_id = bind_group_id.unwrap(); + let bg = bind_group_guard.get_owned(bind_group_id).map_err(|_| { RenderPassError { scope: PassErrorScope::SetBindGroup, - inner: RenderPassErrorInner::InvalidBindGroup(index), + inner: RenderPassErrorInner::InvalidBindGroupId(bind_group_id), } - })?, - }, + })?; + + ArcRenderCommand::SetBindGroup { + index, + num_dynamic_offsets, + bind_group: Some(bg), + } + } RenderCommand::SetPipeline(pipeline_id) => ArcRenderCommand::SetPipeline( pipelines_guard @@ -384,7 +397,7 @@ pub enum ArcRenderCommand { SetBindGroup { index: u32, num_dynamic_offsets: usize, - bind_group: Arc, + bind_group: Option>, }, SetPipeline(Arc), SetIndexBuffer { diff --git a/wgpu-hal/src/dynamic/command.rs b/wgpu-hal/src/dynamic/command.rs index 6c0f1cb02d..4ecdf74723 100644 --- a/wgpu-hal/src/dynamic/command.rs +++ b/wgpu-hal/src/dynamic/command.rs @@ -61,7 +61,7 @@ pub trait DynCommandEncoder: DynResource + std::fmt::Debug { &mut self, layout: &dyn DynPipelineLayout, index: u32, - group: &dyn DynBindGroup, + group: Option<&dyn DynBindGroup>, dynamic_offsets: &[wgt::DynamicOffset], ); @@ -282,9 +282,15 @@ impl DynCommandEncoder for C { &mut self, layout: &dyn DynPipelineLayout, index: u32, - group: &dyn DynBindGroup, + group: Option<&dyn DynBindGroup>, dynamic_offsets: &[wgt::DynamicOffset], ) { + if group.is_none() { + // TODO: Handle group None correctly. + return; + } + let group = group.unwrap(); + let layout = layout.expect_downcast_ref(); let group = group.expect_downcast_ref(); unsafe { C::set_bind_group(self, layout, index, group, dynamic_offsets) }; diff --git a/wgpu/src/api/compute_pass.rs b/wgpu/src/api/compute_pass.rs index bd0575bbd0..306a9f0b47 100644 --- a/wgpu/src/api/compute_pass.rs +++ b/wgpu/src/api/compute_pass.rs @@ -48,14 +48,15 @@ impl<'encoder> ComputePass<'encoder> { pub fn set_bind_group( &mut self, index: u32, - bind_group: &BindGroup, + bind_group: Option<&BindGroup>, offsets: &[DynamicOffset], ) { + let bg = bind_group.map(|x| x.data.as_ref()); DynContext::compute_pass_set_bind_group( &*self.inner.context, self.inner.data.as_mut(), index, - bind_group.data.as_ref(), + bg, offsets, ); } diff --git a/wgpu/src/api/render_bundle_encoder.rs b/wgpu/src/api/render_bundle_encoder.rs index 446b4cbf8a..d69548cdfd 100644 --- a/wgpu/src/api/render_bundle_encoder.rs +++ b/wgpu/src/api/render_bundle_encoder.rs @@ -66,14 +66,15 @@ impl<'a> RenderBundleEncoder<'a> { pub fn set_bind_group( &mut self, index: u32, - bind_group: &'a BindGroup, + bind_group: Option<&'a BindGroup>, offsets: &[DynamicOffset], ) { + let bg = bind_group.map(|x| x.data.as_ref()); DynContext::render_bundle_encoder_set_bind_group( &*self.parent.context, self.data.as_mut(), index, - bind_group.data.as_ref(), + bg, offsets, ) } diff --git a/wgpu/src/api/render_pass.rs b/wgpu/src/api/render_pass.rs index 8fddfd0090..7cdbc31355 100644 --- a/wgpu/src/api/render_pass.rs +++ b/wgpu/src/api/render_pass.rs @@ -77,14 +77,15 @@ impl<'encoder> RenderPass<'encoder> { pub fn set_bind_group( &mut self, index: u32, - bind_group: &BindGroup, + bind_group: Option<&BindGroup>, offsets: &[DynamicOffset], ) { + let bg = bind_group.map(|x| x.data.as_ref()); DynContext::render_pass_set_bind_group( &*self.inner.context, self.inner.data.as_mut(), index, - bind_group.data.as_ref(), + bg, offsets, ) } diff --git a/wgpu/src/backend/webgpu.rs b/wgpu/src/backend/webgpu.rs index 5a9a3b9887..8bb9b5a1bd 100644 --- a/wgpu/src/backend/webgpu.rs +++ b/wgpu/src/backend/webgpu.rs @@ -2771,9 +2771,14 @@ impl crate::context::Context for ContextWebGpu { &self, pass_data: &mut Self::ComputePassData, index: u32, - bind_group_data: &Self::BindGroupData, + bind_group_data: Option<&Self::BindGroupData>, offsets: &[wgt::DynamicOffset], ) { + if bind_group_data.is_none() { + // TODO: Handle the None case. + return; + } + let bind_group_data = bind_group_data.unwrap(); if offsets.is_empty() { pass_data.0.set_bind_group(index, Some(&bind_group_data.0)); } else { @@ -2883,9 +2888,14 @@ impl crate::context::Context for ContextWebGpu { &self, encoder_data: &mut Self::RenderBundleEncoderData, index: u32, - bind_group_data: &Self::BindGroupData, + bind_group_data: Option<&Self::BindGroupData>, offsets: &[wgt::DynamicOffset], ) { + if bind_group_data.is_none() { + // TODO: Handle the None case. + return; + } + let bind_group_data = bind_group_data.unwrap(); if offsets.is_empty() { encoder_data .0 @@ -3081,9 +3091,14 @@ impl crate::context::Context for ContextWebGpu { &self, pass_data: &mut Self::RenderPassData, index: u32, - bind_group_data: &Self::BindGroupData, + bind_group_data: Option<&Self::BindGroupData>, offsets: &[wgt::DynamicOffset], ) { + if bind_group_data.is_none() { + // TODO: Handle the None case. + return; + } + let bind_group_data = bind_group_data.unwrap(); if offsets.is_empty() { pass_data.0.set_bind_group(index, Some(&bind_group_data.0)); } else { diff --git a/wgpu/src/backend/wgpu_core.rs b/wgpu/src/backend/wgpu_core.rs index 8ed6acdd80..6bb54bce58 100644 --- a/wgpu/src/backend/wgpu_core.rs +++ b/wgpu/src/backend/wgpu_core.rs @@ -2180,15 +2180,14 @@ impl crate::Context for ContextWgpuCore { &self, pass_data: &mut Self::ComputePassData, index: u32, - bind_group_data: &Self::BindGroupData, + bind_group_data: Option<&Self::BindGroupData>, offsets: &[wgt::DynamicOffset], ) { - if let Err(cause) = self.0.compute_pass_set_bind_group( - &mut pass_data.pass, - index, - *bind_group_data, - offsets, - ) { + let bg = bind_group_data.cloned(); + if let Err(cause) = + self.0 + .compute_pass_set_bind_group(&mut pass_data.pass, index, bg, offsets) + { self.handle_error( &pass_data.error_sink, cause, @@ -2376,14 +2375,15 @@ impl crate::Context for ContextWgpuCore { &self, encoder_data: &mut Self::RenderBundleEncoderData, index: u32, - bind_group_data: &Self::BindGroupData, + bind_group_data: Option<&Self::BindGroupData>, offsets: &[wgt::DynamicOffset], ) { + let bg = bind_group_data.cloned(); unsafe { wgpu_render_bundle_set_bind_group( encoder_data, index, - *bind_group_data, + bg, offsets.as_ptr(), offsets.len(), ) @@ -2550,12 +2550,13 @@ impl crate::Context for ContextWgpuCore { &self, pass_data: &mut Self::RenderPassData, index: u32, - bind_group_data: &Self::BindGroupData, + bind_group_data: Option<&Self::BindGroupData>, offsets: &[wgt::DynamicOffset], ) { + let bg = bind_group_data.cloned(); if let Err(cause) = self.0 - .render_pass_set_bind_group(&mut pass_data.pass, index, *bind_group_data, offsets) + .render_pass_set_bind_group(&mut pass_data.pass, index, bg, offsets) { self.handle_error( &pass_data.error_sink, diff --git a/wgpu/src/context.rs b/wgpu/src/context.rs index 5e6d85192a..2624d40e63 100644 --- a/wgpu/src/context.rs +++ b/wgpu/src/context.rs @@ -441,7 +441,7 @@ pub trait Context: Debug + WasmNotSendSync + Sized { &self, pass_data: &mut Self::ComputePassData, index: u32, - bind_group_data: &Self::BindGroupData, + bind_group_data: Option<&Self::BindGroupData>, offsets: &[DynamicOffset], ); fn compute_pass_set_push_constants( @@ -494,7 +494,7 @@ pub trait Context: Debug + WasmNotSendSync + Sized { &self, encoder_data: &mut Self::RenderBundleEncoderData, index: u32, - bind_group_data: &Self::BindGroupData, + bind_group_data: Option<&Self::BindGroupData>, offsets: &[DynamicOffset], ); #[allow(clippy::too_many_arguments)] @@ -591,7 +591,7 @@ pub trait Context: Debug + WasmNotSendSync + Sized { &self, pass_data: &mut Self::RenderPassData, index: u32, - bind_group_data: &Self::BindGroupData, + bind_group_data: Option<&Self::BindGroupData>, offsets: &[DynamicOffset], ); #[allow(clippy::too_many_arguments)] @@ -1147,7 +1147,7 @@ pub(crate) trait DynContext: Debug + WasmNotSendSync { &self, pass_data: &mut crate::Data, index: u32, - bind_group_data: &crate::Data, + bind_group_data: Option<&crate::Data>, offsets: &[DynamicOffset], ); fn compute_pass_set_push_constants( @@ -1190,7 +1190,7 @@ pub(crate) trait DynContext: Debug + WasmNotSendSync { &self, encoder_data: &mut crate::Data, index: u32, - bind_group_data: &crate::Data, + bind_group_data: Option<&crate::Data>, offsets: &[DynamicOffset], ); #[allow(clippy::too_many_arguments)] @@ -1283,7 +1283,7 @@ pub(crate) trait DynContext: Debug + WasmNotSendSync { &self, pass_data: &mut crate::Data, index: u32, - bind_group_data: &crate::Data, + bind_group_data: Option<&crate::Data>, offsets: &[DynamicOffset], ); #[allow(clippy::too_many_arguments)] @@ -2239,12 +2239,12 @@ where &self, pass_data: &mut crate::Data, index: u32, - bind_group_data: &crate::Data, + bind_group_data: Option<&crate::Data>, offsets: &[DynamicOffset], ) { let pass_data = downcast_mut::(pass_data); - let bind_group_data = downcast_ref(bind_group_data); - Context::compute_pass_set_bind_group(self, pass_data, index, bind_group_data, offsets) + let bg = bind_group_data.map(downcast_ref); + Context::compute_pass_set_bind_group(self, pass_data, index, bg, offsets) } fn compute_pass_set_push_constants( @@ -2350,18 +2350,12 @@ where &self, encoder_data: &mut crate::Data, index: u32, - bind_group_data: &crate::Data, + bind_group_data: Option<&crate::Data>, offsets: &[DynamicOffset], ) { let encoder_data = downcast_mut::(encoder_data); - let bind_group_data = downcast_ref(bind_group_data); - Context::render_bundle_encoder_set_bind_group( - self, - encoder_data, - index, - bind_group_data, - offsets, - ) + let bg = bind_group_data.map(downcast_ref); + Context::render_bundle_encoder_set_bind_group(self, encoder_data, index, bg, offsets) } fn render_bundle_encoder_set_index_buffer( @@ -2566,12 +2560,12 @@ where &self, pass_data: &mut crate::Data, index: u32, - bind_group_data: &crate::Data, + bind_group_data: Option<&crate::Data>, offsets: &[DynamicOffset], ) { let pass_data = downcast_mut::(pass_data); - let bind_group_data = downcast_ref(bind_group_data); - Context::render_pass_set_bind_group(self, pass_data, index, bind_group_data, offsets) + let bg = bind_group_data.map(downcast_ref); + Context::render_pass_set_bind_group(self, pass_data, index, bg, offsets) } fn render_pass_set_index_buffer( diff --git a/wgpu/src/util/encoder.rs b/wgpu/src/util/encoder.rs index bef8fe9509..c6d42e3eba 100644 --- a/wgpu/src/util/encoder.rs +++ b/wgpu/src/util/encoder.rs @@ -10,7 +10,12 @@ pub trait RenderEncoder<'a> { /// in the active pipeline when any `draw()` function is called must match the layout of this bind group. /// /// If the bind group have dynamic offsets, provide them in order of their declaration. - fn set_bind_group(&mut self, index: u32, bind_group: &'a BindGroup, offsets: &[DynamicOffset]); + fn set_bind_group( + &mut self, + index: u32, + bind_group: Option<&'a BindGroup>, + offsets: &[DynamicOffset], + ); /// Sets the active render pipeline. /// @@ -101,7 +106,12 @@ pub trait RenderEncoder<'a> { impl<'a> RenderEncoder<'a> for RenderPass<'a> { #[inline(always)] - fn set_bind_group(&mut self, index: u32, bind_group: &'a BindGroup, offsets: &[DynamicOffset]) { + fn set_bind_group( + &mut self, + index: u32, + bind_group: Option<&'a BindGroup>, + offsets: &[DynamicOffset], + ) { Self::set_bind_group(self, index, bind_group, offsets); } @@ -152,7 +162,12 @@ impl<'a> RenderEncoder<'a> for RenderPass<'a> { impl<'a> RenderEncoder<'a> for RenderBundleEncoder<'a> { #[inline(always)] - fn set_bind_group(&mut self, index: u32, bind_group: &'a BindGroup, offsets: &[DynamicOffset]) { + fn set_bind_group( + &mut self, + index: u32, + bind_group: Option<&'a BindGroup>, + offsets: &[DynamicOffset], + ) { Self::set_bind_group(self, index, bind_group, offsets); }