From bb054c354d4e2ebb209b7c9ffe7ae799a47816fd Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Sun, 2 Mar 2025 19:56:35 -0800 Subject: [PATCH 1/2] Try to fix rendering if partially-bound binding arrays aren't supported --- crates/bevy_pbr/src/material_bind_groups.rs | 69 ++++++++++++++++++--- 1 file changed, 62 insertions(+), 7 deletions(-) diff --git a/crates/bevy_pbr/src/material_bind_groups.rs b/crates/bevy_pbr/src/material_bind_groups.rs index 74f5fcad18e6e..79a59ea5036f0 100644 --- a/crates/bevy_pbr/src/material_bind_groups.rs +++ b/crates/bevy_pbr/src/material_bind_groups.rs @@ -23,6 +23,7 @@ use bevy_render::{ UnpreparedBindGroup, WgpuSampler, WgpuTextureView, }, renderer::{RenderDevice, RenderQueue}, + settings::WgpuFeatures, texture::FallbackImage, }; use bevy_utils::default; @@ -803,6 +804,7 @@ where &self.fallback_buffers, fallback_image, &self.bindless_descriptor, + self.slab_capacity, ); } } @@ -1162,6 +1164,7 @@ where fallback_buffers: &HashMap, fallback_image: &FallbackImage, bindless_descriptor: &BindlessDescriptor, + slab_capacity: u32, ) { // Create the bindless index table buffer if needed. self.bindless_index_table.buffer.prepare(render_device); @@ -1179,6 +1182,7 @@ where fallback_buffers, fallback_image, bindless_descriptor, + slab_capacity, ); } @@ -1192,17 +1196,30 @@ where fallback_buffers: &HashMap, fallback_image: &FallbackImage, bindless_descriptor: &BindlessDescriptor, + slab_capacity: u32, ) { // If the bind group is clean, then do nothing. if self.bind_group.is_some() { return; } + // Determine whether we need to pad out our binding arrays with dummy + // resources. + let required_binding_array_size = if render_device + .features() + .contains(WgpuFeatures::PARTIALLY_BOUND_BINDING_ARRAY) + { + None + } else { + Some(slab_capacity) + }; + let binding_resource_arrays = self.create_binding_resource_arrays( fallback_bindless_resources, fallback_buffers, fallback_image, bindless_descriptor, + required_binding_array_size, ); let mut bind_group_entries = vec![BindGroupEntry { @@ -1273,6 +1290,7 @@ where fallback_buffers: &'a HashMap, fallback_image: &'a FallbackImage, bindless_descriptor: &'a BindlessDescriptor, + required_binding_array_size: Option, ) -> Vec<(&'a u32, BindingResourceArray<'a>)> { let mut binding_resource_arrays = vec![]; @@ -1280,16 +1298,22 @@ where self.create_sampler_binding_resource_arrays( &mut binding_resource_arrays, fallback_bindless_resources, + required_binding_array_size, ); // Build texture bindings. - self.create_texture_binding_resource_arrays(&mut binding_resource_arrays, fallback_image); + self.create_texture_binding_resource_arrays( + &mut binding_resource_arrays, + fallback_image, + required_binding_array_size, + ); // Build buffer bindings. self.create_buffer_binding_resource_arrays( &mut binding_resource_arrays, fallback_buffers, bindless_descriptor, + required_binding_array_size, ); binding_resource_arrays @@ -1301,6 +1325,7 @@ where &'a self, binding_resource_arrays: &'b mut Vec<(&'a u32, BindingResourceArray<'a>)>, fallback_bindless_resources: &'a FallbackBindlessResources, + required_binding_array_size: Option, ) { // We have one binding resource array per sampler type. for (bindless_resource_type, fallback_sampler) in [ @@ -1319,7 +1344,7 @@ where ] { match self.samplers.get(&bindless_resource_type) { Some(sampler_bindless_binding_array) => { - let sampler_bindings = sampler_bindless_binding_array + let mut sampler_bindings: Vec<_> = sampler_bindless_binding_array .bindings .iter() .map(|maybe_bindless_binding| match *maybe_bindless_binding { @@ -1327,6 +1352,13 @@ where None => &**fallback_sampler, }) .collect(); + + if let Some(required_binding_array_size) = required_binding_array_size { + while sampler_bindings.len() < required_binding_array_size as usize { + sampler_bindings.push(&**fallback_sampler); + } + } + binding_resource_arrays.push(( &*sampler_bindless_binding_array.binding_number, BindingResourceArray::Samplers(sampler_bindings), @@ -1354,6 +1386,7 @@ where &'a self, binding_resource_arrays: &'b mut Vec<(&'a u32, BindingResourceArray<'a>)>, fallback_image: &'a FallbackImage, + required_binding_array_size: Option, ) { for (bindless_resource_type, fallback_image) in [ (BindlessResourceType::Texture1d, &fallback_image.d1), @@ -1371,7 +1404,7 @@ where ] { match self.textures.get(&bindless_resource_type) { Some(texture_bindless_binding_array) => { - let texture_bindings = texture_bindless_binding_array + let mut texture_bindings: Vec<_> = texture_bindless_binding_array .bindings .iter() .map(|maybe_bindless_binding| match *maybe_bindless_binding { @@ -1379,6 +1412,13 @@ where None => &*fallback_image.texture_view, }) .collect(); + + if let Some(required_binding_array_size) = required_binding_array_size { + while texture_bindings.len() < required_binding_array_size as usize { + texture_bindings.push(&*fallback_image.texture_view); + } + } + binding_resource_arrays.push(( &*texture_bindless_binding_array.binding_number, BindingResourceArray::TextureViews(texture_bindings), @@ -1407,6 +1447,7 @@ where binding_resource_arrays: &'b mut Vec<(&'a u32, BindingResourceArray<'a>)>, fallback_buffers: &'a HashMap, bindless_descriptor: &'a BindlessDescriptor, + required_binding_array_size: Option, ) { for bindless_buffer_descriptor in bindless_descriptor.buffers.iter() { let Some(buffer_bindless_binding_array) = @@ -1417,14 +1458,17 @@ where // `BindlessDescriptor::resources`. continue; }; - let buffer_bindings = buffer_bindless_binding_array + + let fallback_buffer = fallback_buffers + .get(&bindless_buffer_descriptor.bindless_index) + .expect("Fallback buffer should exist"); + + let mut buffer_bindings: Vec<_> = buffer_bindless_binding_array .bindings .iter() .map(|maybe_bindless_binding| { let buffer = match *maybe_bindless_binding { - None => fallback_buffers - .get(&bindless_buffer_descriptor.bindless_index) - .expect("Fallback buffer should exist"), + None => fallback_buffer, Some(ref bindless_binding) => &bindless_binding.resource, }; BufferBinding { @@ -1434,6 +1478,17 @@ where } }) .collect(); + + if let Some(required_binding_array_size) = required_binding_array_size { + while buffer_bindings.len() < required_binding_array_size as usize { + buffer_bindings.push(BufferBinding { + buffer: fallback_buffer, + offset: 0, + size: None, + }); + } + } + binding_resource_arrays.push(( &*buffer_bindless_binding_array.binding_number, BindingResourceArray::Buffers(buffer_bindings), From 28a1f6a6fc9634d1a2d9c6647a5b104f7c7760ed Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Sun, 2 Mar 2025 22:04:47 -0800 Subject: [PATCH 2/2] Try to fix partially bound binding arrays harder --- crates/bevy_pbr/src/material_bind_groups.rs | 111 ++++++++++---------- 1 file changed, 56 insertions(+), 55 deletions(-) diff --git a/crates/bevy_pbr/src/material_bind_groups.rs b/crates/bevy_pbr/src/material_bind_groups.rs index 79a59ea5036f0..3a4fa8b38ad30 100644 --- a/crates/bevy_pbr/src/material_bind_groups.rs +++ b/crates/bevy_pbr/src/material_bind_groups.rs @@ -4,7 +4,7 @@ //! allocator manages each bind group, assigning slots to materials as //! appropriate. -use core::{marker::PhantomData, mem}; +use core::{iter, marker::PhantomData, mem}; use bevy_derive::{Deref, DerefMut}; use bevy_ecs::{ @@ -1342,41 +1342,41 @@ where &fallback_bindless_resources.comparison_sampler, ), ] { + let mut sampler_bindings = vec![]; + match self.samplers.get(&bindless_resource_type) { Some(sampler_bindless_binding_array) => { - let mut sampler_bindings: Vec<_> = sampler_bindless_binding_array - .bindings - .iter() - .map(|maybe_bindless_binding| match *maybe_bindless_binding { - Some(ref bindless_binding) => &bindless_binding.resource, - None => &**fallback_sampler, - }) - .collect(); - - if let Some(required_binding_array_size) = required_binding_array_size { - while sampler_bindings.len() < required_binding_array_size as usize { - sampler_bindings.push(&**fallback_sampler); + for maybe_bindless_binding in sampler_bindless_binding_array.bindings.iter() { + match *maybe_bindless_binding { + Some(ref bindless_binding) => { + sampler_bindings.push(&*bindless_binding.resource); + } + None => sampler_bindings.push(&**fallback_sampler), } } - - binding_resource_arrays.push(( - &*sampler_bindless_binding_array.binding_number, - BindingResourceArray::Samplers(sampler_bindings), - )); } None => { // Fill with a single fallback sampler. - let binding_number = bindless_resource_type - .binding_number() - .expect("Sampler bindless resource type must have a binding number"); - - binding_resource_arrays.push(( - &**binding_number, - BindingResourceArray::Samplers(vec![&**fallback_sampler]), - )); + sampler_bindings.push(&**fallback_sampler); } } + + if let Some(required_binding_array_size) = required_binding_array_size { + sampler_bindings.extend( + iter::repeat(&**fallback_sampler) + .take(required_binding_array_size as usize - sampler_bindings.len()), + ); + } + + let binding_number = bindless_resource_type + .binding_number() + .expect("Sampler bindless resource type must have a binding number"); + + binding_resource_arrays.push(( + &**binding_number, + BindingResourceArray::Samplers(sampler_bindings), + )); } } @@ -1402,41 +1402,41 @@ where &fallback_image.cube_array, ), ] { + let mut texture_bindings = vec![]; + + let binding_number = bindless_resource_type + .binding_number() + .expect("Texture bindless resource type must have a binding number"); + match self.textures.get(&bindless_resource_type) { Some(texture_bindless_binding_array) => { - let mut texture_bindings: Vec<_> = texture_bindless_binding_array - .bindings - .iter() - .map(|maybe_bindless_binding| match *maybe_bindless_binding { - Some(ref bindless_binding) => &*bindless_binding.resource, - None => &*fallback_image.texture_view, - }) - .collect(); - - if let Some(required_binding_array_size) = required_binding_array_size { - while texture_bindings.len() < required_binding_array_size as usize { - texture_bindings.push(&*fallback_image.texture_view); + for maybe_bindless_binding in texture_bindless_binding_array.bindings.iter() { + match *maybe_bindless_binding { + Some(ref bindless_binding) => { + texture_bindings.push(&*bindless_binding.resource); + } + None => texture_bindings.push(&*fallback_image.texture_view), } } - - binding_resource_arrays.push(( - &*texture_bindless_binding_array.binding_number, - BindingResourceArray::TextureViews(texture_bindings), - )); } None => { // Fill with a single fallback image. - let binding_number = bindless_resource_type - .binding_number() - .expect("Texture bindless resource type must have a binding number"); - - binding_resource_arrays.push(( - binding_number, - BindingResourceArray::TextureViews(vec![&*fallback_image.texture_view]), - )); + texture_bindings.push(&*fallback_image.texture_view); } } + + if let Some(required_binding_array_size) = required_binding_array_size { + texture_bindings.extend( + iter::repeat(&*fallback_image.texture_view) + .take(required_binding_array_size as usize - texture_bindings.len()), + ); + } + + binding_resource_arrays.push(( + binding_number, + BindingResourceArray::TextureViews(texture_bindings), + )); } } @@ -1480,13 +1480,14 @@ where .collect(); if let Some(required_binding_array_size) = required_binding_array_size { - while buffer_bindings.len() < required_binding_array_size as usize { - buffer_bindings.push(BufferBinding { + buffer_bindings.extend( + iter::repeat(BufferBinding { buffer: fallback_buffer, offset: 0, size: None, - }); - } + }) + .take(required_binding_array_size as usize - buffer_bindings.len()), + ); } binding_resource_arrays.push((