From aab22b93e11d32977fe3708aa609d5d07e2c6ce6 Mon Sep 17 00:00:00 2001 From: Elabajaba Date: Wed, 29 Nov 2023 18:11:12 -0500 Subject: [PATCH] Fix prepass binding issues causing crashes when not all prepass bindings are used (#10788) # Objective Fixes https://github.com/bevyengine/bevy/issues/10786 ## Solution The bind_group_layout entries for the prepass were wrong when not all 4 prepass textures were used, as it just zipped [17, 18, 19, 20] with the smallvec of prepass `bind_group_layout` entries that potentially didn't contain 4 entries. (eg. if you had a depth and motion vector prepass but no normal prepass, then depth would be correct but the entry for the motion vector prepass would be 18 (normal prepass' spot) instead of 19). Change the prepass `get_bind_group_layout_entries` function to return an array of `[Option; 4]` and only add the layout entry if it exists. --- .../bevy_pbr/src/prepass/prepass_bindings.rs | 59 +++++++++---------- .../bevy_pbr/src/render/mesh_view_bindings.rs | 4 +- 2 files changed, 30 insertions(+), 33 deletions(-) diff --git a/crates/bevy_pbr/src/prepass/prepass_bindings.rs b/crates/bevy_pbr/src/prepass/prepass_bindings.rs index 52ea02c1f5d206..77398ce6e587b3 100644 --- a/crates/bevy_pbr/src/prepass/prepass_bindings.rs +++ b/crates/bevy_pbr/src/prepass/prepass_bindings.rs @@ -7,58 +7,53 @@ use bevy_render::render_resource::{ TextureViewDescriptor, }; use bevy_utils::default; -use smallvec::SmallVec; use crate::MeshPipelineViewLayoutKey; pub fn get_bind_group_layout_entries( layout_key: MeshPipelineViewLayoutKey, -) -> SmallVec<[BindGroupLayoutEntryBuilder; 4]> { - let mut result = SmallVec::<[BindGroupLayoutEntryBuilder; 4]>::new(); +) -> [Option; 4] { + let mut entries: [Option; 4] = [None; 4]; let multisampled = layout_key.contains(MeshPipelineViewLayoutKey::MULTISAMPLED); if layout_key.contains(MeshPipelineViewLayoutKey::DEPTH_PREPASS) { - result.push( - // Depth texture - if multisampled { - texture_depth_2d_multisampled() - } else { - texture_depth_2d() - }, - ); + // Depth texture + entries[0] = if multisampled { + Some(texture_depth_2d_multisampled()) + } else { + Some(texture_depth_2d()) + }; } if layout_key.contains(MeshPipelineViewLayoutKey::NORMAL_PREPASS) { - result.push( - // Normal texture - if multisampled { - texture_2d_multisampled(TextureSampleType::Float { filterable: false }) - } else { - texture_2d(TextureSampleType::Float { filterable: false }) - }, - ); + // Normal texture + entries[1] = if multisampled { + Some(texture_2d_multisampled(TextureSampleType::Float { + filterable: false, + })) + } else { + Some(texture_2d(TextureSampleType::Float { filterable: false })) + }; } if layout_key.contains(MeshPipelineViewLayoutKey::MOTION_VECTOR_PREPASS) { - result.push( - // Motion Vectors texture - if multisampled { - texture_2d_multisampled(TextureSampleType::Float { filterable: false }) - } else { - texture_2d(TextureSampleType::Float { filterable: false }) - }, - ); + // Motion Vectors texture + entries[2] = if multisampled { + Some(texture_2d_multisampled(TextureSampleType::Float { + filterable: false, + })) + } else { + Some(texture_2d(TextureSampleType::Float { filterable: false })) + }; } if layout_key.contains(MeshPipelineViewLayoutKey::DEFERRED_PREPASS) { - result.push( - // Deferred texture - texture_2d(TextureSampleType::Uint), - ); + // Deferred texture + entries[3] = Some(texture_2d(TextureSampleType::Uint)); } - result + entries } pub fn get_bindings(prepass_textures: Option<&ViewPrepassTextures>) -> [Option; 4] { diff --git a/crates/bevy_pbr/src/render/mesh_view_bindings.rs b/crates/bevy_pbr/src/render/mesh_view_bindings.rs index cbd0e982a460eb..015f43542454ba 100644 --- a/crates/bevy_pbr/src/render/mesh_view_bindings.rs +++ b/crates/bevy_pbr/src/render/mesh_view_bindings.rs @@ -274,7 +274,9 @@ fn layout_entries( .iter() .zip([17, 18, 19, 20]) { - entries = entries.extend_with_indices(((binding as u32, *entry),)); + if let Some(entry) = entry { + entries = entries.extend_with_indices(((binding as u32, *entry),)); + } } }