From 592822b702d6ca0028aa5a8695b04f3ba2360016 Mon Sep 17 00:00:00 2001 From: charlotte Date: Mon, 31 Mar 2025 11:15:11 -0700 Subject: [PATCH] Remove entities from specialization caches when despawned. (#18627) # Objective Fixes #17872 ## Solution This should have basically no impact on static scenes. We can optimize more later if anything comes up. Needing to iterate the two level bin is a bit unfortunate but shouldn't matter for apps that use a single camera. --- crates/bevy_pbr/src/material.rs | 50 +++++++++++++++++++---- crates/bevy_sprite/src/mesh2d/material.rs | 30 ++++++++++---- 2 files changed, 66 insertions(+), 14 deletions(-) diff --git a/crates/bevy_pbr/src/material.rs b/crates/bevy_pbr/src/material.rs index 0cf6686b3e..1979e995e6 100644 --- a/crates/bevy_pbr/src/material.rs +++ b/crates/bevy_pbr/src/material.rs @@ -34,6 +34,7 @@ use bevy_platform_support::collections::{HashMap, HashSet}; use bevy_platform_support::hash::FixedHasher; use bevy_reflect::std_traits::ReflectDefault; use bevy_reflect::Reflect; +use bevy_render::camera::extract_cameras; use bevy_render::mesh::mark_3d_meshes_as_changed_if_their_assets_changed; use bevy_render::render_asset::prepare_assets; use bevy_render::renderer::RenderQueue; @@ -315,7 +316,7 @@ where ExtractSchedule, ( extract_mesh_materials::.before(ExtractMeshesSet), - extract_entities_needs_specialization::, + extract_entities_needs_specialization::.after(extract_cameras), ), ) .add_systems( @@ -707,6 +708,15 @@ fn extract_mesh_materials( pub fn extract_entities_needs_specialization( entities_needing_specialization: Extract>>, mut entity_specialization_ticks: ResMut>, + mut removed_mesh_material_components: Extract>>, + mut specialized_material_pipeline_cache: ResMut>, + mut specialized_prepass_material_pipeline_cache: Option< + ResMut>, + >, + mut specialized_shadow_material_pipeline_cache: Option< + ResMut>, + >, + views: Query<&ExtractedView>, ticks: SystemChangeTick, ) where M: Material, @@ -715,6 +725,29 @@ pub fn extract_entities_needs_specialization( // Update the entity's specialization tick with this run's tick entity_specialization_ticks.insert((*entity).into(), ticks.this_run()); } + // Clean up any despawned entities + for entity in removed_mesh_material_components.read() { + entity_specialization_ticks.remove(&MainEntity::from(entity)); + for view in views { + if let Some(cache) = + specialized_material_pipeline_cache.get_mut(&view.retained_view_entity) + { + cache.remove(&MainEntity::from(entity)); + } + if let Some(cache) = specialized_prepass_material_pipeline_cache + .as_mut() + .and_then(|c| c.get_mut(&view.retained_view_entity)) + { + cache.remove(&MainEntity::from(entity)); + } + if let Some(cache) = specialized_shadow_material_pipeline_cache + .as_mut() + .and_then(|c| c.get_mut(&view.retained_view_entity)) + { + cache.remove(&MainEntity::from(entity)); + } + } + } } #[derive(Resource, Deref, DerefMut, Clone, Debug)] @@ -789,12 +822,15 @@ impl Default for SpecializedMaterialViewPipelineCache { pub fn check_entities_needing_specialization( needs_specialization: Query< Entity, - Or<( - Changed, - AssetChanged, - Changed>, - AssetChanged>, - )>, + ( + Or<( + Changed, + AssetChanged, + Changed>, + AssetChanged>, + )>, + With>, + ), >, mut entities_needing_specialization: ResMut>, ) where diff --git a/crates/bevy_sprite/src/mesh2d/material.rs b/crates/bevy_sprite/src/mesh2d/material.rs index ce2803b261..a9401a8144 100644 --- a/crates/bevy_sprite/src/mesh2d/material.rs +++ b/crates/bevy_sprite/src/mesh2d/material.rs @@ -21,6 +21,7 @@ use bevy_ecs::{ use bevy_math::FloatOrd; use bevy_platform_support::collections::HashMap; use bevy_reflect::{prelude::ReflectDefault, Reflect}; +use bevy_render::camera::extract_cameras; use bevy_render::render_phase::{DrawFunctionId, InputUniformIndex}; use bevy_render::render_resource::CachedRenderPipelineId; use bevy_render::view::RenderVisibleEntities; @@ -286,7 +287,7 @@ where .add_systems( ExtractSchedule, ( - extract_entities_needs_specialization::, + extract_entities_needs_specialization::.after(extract_cameras), extract_mesh_materials_2d::, ), ) @@ -555,6 +556,9 @@ pub const fn tonemapping_pipeline_key(tonemapping: Tonemapping) -> Mesh2dPipelin pub fn extract_entities_needs_specialization( entities_needing_specialization: Extract>>, mut entity_specialization_ticks: ResMut>, + mut removed_mesh_material_components: Extract>>, + mut specialized_material2d_pipeline_cache: ResMut>, + views: Query<&MainEntity, With>, ticks: SystemChangeTick, ) where M: Material2d, @@ -563,6 +567,15 @@ pub fn extract_entities_needs_specialization( // Update the entity's specialization tick with this run's tick entity_specialization_ticks.insert((*entity).into(), ticks.this_run()); } + // Clean up any despawned entities + for entity in removed_mesh_material_components.read() { + entity_specialization_ticks.remove(&MainEntity::from(entity)); + for view in views { + if let Some(cache) = specialized_material2d_pipeline_cache.get_mut(view) { + cache.remove(&MainEntity::from(entity)); + } + } + } } #[derive(Clone, Resource, Deref, DerefMut, Debug)] @@ -637,12 +650,15 @@ impl Default for SpecializedMaterial2dViewPipelineCache { pub fn check_entities_needing_specialization( needs_specialization: Query< Entity, - Or<( - Changed, - AssetChanged, - Changed>, - AssetChanged>, - )>, + ( + Or<( + Changed, + AssetChanged, + Changed>, + AssetChanged>, + )>, + With>, + ), >, mut entities_needing_specialization: ResMut>, ) where