From 4d51922f7673cd686c6574705bcb01e3a2c6b4fe Mon Sep 17 00:00:00 2001 From: Luo Zhiaho Date: Tue, 8 Sep 2026 20:16:49 +0800 Subject: [PATCH 1/2] Catch RenderLayers changes in GPU mesh extraction change detection Pure render-layer changes on a mesh never reached `RenderGpuCulledEntities::update()` because `extract_meshes_for_gpu_building` only iterates entities it considers changed, and `RenderLayers` wasn't part of its change filter. A static mesh whose only change is its render layers would therefore keep a stale layer relevance in all views forever, and the `changed_layers` list would only be populated when a mesh happened to be re-extracted for some other reason. Add `Changed` and `RemovedComponents` to the change detection. --- crates/bevy_pbr/src/render/mesh.rs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/crates/bevy_pbr/src/render/mesh.rs b/crates/bevy_pbr/src/render/mesh.rs index 39f5a7a70183b..4cb5198d8fdf4 100644 --- a/crates/bevy_pbr/src/render/mesh.rs +++ b/crates/bevy_pbr/src/render/mesh.rs @@ -1754,6 +1754,12 @@ impl RenderGpuCulledEntities { /// /// The `render_layers` argument specifies the set of render layers that the /// entity belongs to. + /// + /// Note that this method is only called for entities that the extraction + /// systems picked up this frame, so the extraction change detection must be + /// configured to catch render layer changes (see + /// `extract_meshes_for_gpu_building`) in order for layer changes on + /// GPU-culled meshes to propagate. pub fn update( &mut self, new_entity: MainEntity, @@ -1763,7 +1769,7 @@ impl RenderGpuCulledEntities { match self.entities.entry(new_entity) { Entry::Occupied(mut occupied_entry) => { if no_cpu_culling { - if occupied_entry.get().ne(&render_layers) { + if *occupied_entry.get() != render_layers { self.changed_layers.push(new_entity); } @@ -1961,6 +1967,7 @@ pub fn extract_meshes_for_gpu_building( )>, Changed, Changed, + Changed, )>, >, >, @@ -1977,6 +1984,7 @@ pub fn extract_meshes_for_gpu_building( mut removed_no_cpu_culling_query, mut removed_visibility_range_query, mut removed_skinned_mesh_query, + mut removed_render_layers_query, ): ( Extract>, Extract>, @@ -1990,6 +1998,7 @@ pub fn extract_meshes_for_gpu_building( Extract>, Extract>, Extract>, + Extract>, ), all_meshes_query: Extract>, mut removed_meshes_query: Extract>, @@ -2029,7 +2038,8 @@ pub fn extract_meshes_for_gpu_building( .chain(removed_no_automatic_batching_query.read()) .chain(removed_no_cpu_culling_query.read()) .chain(removed_visibility_range_query.read()) - .chain(removed_skinned_mesh_query.read()), + .chain(removed_skinned_mesh_query.read()) + .chain(removed_render_layers_query.read()), ); // We have to skip the meshes in the potential reextraction set if we From 672fa54951a0db7a64987e021be42d2a03e51341 Mon Sep 17 00:00:00 2001 From: Luo Zhiaho Date: Tue, 8 Sep 2026 20:19:19 +0800 Subject: [PATCH 2/2] Remove unused RenderVisibleEntitiesClass::add_entity() Its only callers were already converted to direct `added_entities` pushes, leaving it as dead code; update `sort_added_entities`' doc accordingly. (Its removal was deferred to a follow-up PR during the #25670 review.) --- crates/bevy_render/src/view/visibility/mod.rs | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/crates/bevy_render/src/view/visibility/mod.rs b/crates/bevy_render/src/view/visibility/mod.rs index 887d3bdc4ae47..51b466a5a7a7d 100644 --- a/crates/bevy_render/src/view/visibility/mod.rs +++ b/crates/bevy_render/src/view/visibility/mod.rs @@ -250,15 +250,6 @@ impl RenderVisibleEntitiesClass { } } - /// Adds a new entity to the [`Self::added_entities`] list. - /// - /// After calling this method one or more times, you must call - /// [`Self::sort_added_entities`] to ensure the [`Self::added_entities`] - /// list is sorted. - pub fn add_entity(&mut self, pair: (Entity, MainEntity)) { - self.added_entities.push(pair); - } - /// Returns the list of newly-added entities. pub fn added_entities(&self) -> &[(Entity, MainEntity)] { &self.added_entities @@ -297,8 +288,8 @@ impl RenderVisibleEntitiesClass { /// Sorts the [`Self::added_entities`] list. /// - /// You must call this after adding entities to the list via - /// [`Self::add_entity`]. + /// You must call this after pushing entities onto the list, as the + /// `DirtySpecializations` iterator will binary search it. pub fn sort_added_entities(&mut self) { self.added_entities .sort_unstable_by_key(|(_, main_entity)| *main_entity);