Material, mesh, skin extraction optimization (#17976)

# Objective

The extraction systems for materials, meshes, and skins previously
iterated over `RemovedComponents<ViewVisibility>` in addition to more
specific variants like `RemovedComponents<MeshMaterial3d<M>>`. This
caused each system to loop through and check many irrelevant despawned
entities—sometimes multiple times. With many material types, this
overhead added up and became noticeable in frames with many despawns.

<img width="1091" alt="Screenshot 2025-02-21 at 10 28 01 AM"
src="https://github.com/user-attachments/assets/63fec1c9-232c-45f6-9150-daf8751ecf85"
/>

## Solution

This PR removes superfluous `RemovedComponents` iteration for
`ViewVisibility` and `GlobalTransform`, ensuring that we only iterate
over the most specific `RemovedComponents` relevant to the system (e.g.,
material components, mesh components). This is guaranteed to match what
the system originally collected.

### Before (red) / After (yellow):
<img width="838" alt="Screenshot 2025-02-21 at 10 46 17 AM"
src="https://github.com/user-attachments/assets/0e06b06d-7e91-4da5-a919-b843eb442a72"
/>
Log plot to highlight the long tail that this PR is addressing.
This commit is contained in:
Brian Reavis 2025-07-08 23:23:44 -07:00 committed by GitHub
parent 6fc4bc126d
commit d40c5b54ae
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 5 additions and 19 deletions

View File

@ -746,11 +746,11 @@ fn early_sweep_material_instances<M>(
/// preparation for a new frame.
pub(crate) fn late_sweep_material_instances(
mut material_instances: ResMut<RenderMaterialInstances>,
mut removed_visibilities_query: Extract<RemovedComponents<ViewVisibility>>,
mut removed_meshes_query: Extract<RemovedComponents<Mesh3d>>,
) {
let last_change_tick = material_instances.current_change_tick;
for entity in removed_visibilities_query.read() {
for entity in removed_meshes_query.read() {
if let Entry::Occupied(occupied_entry) = material_instances.instances.entry(entity.into()) {
// Only sweep the entry if it wasn't updated this frame. It's
// possible that a `ViewVisibility` component was removed and

View File

@ -1452,8 +1452,6 @@ pub fn extract_meshes_for_gpu_building(
>,
>,
all_meshes_query: Extract<Query<GpuMeshExtractionQuery>>,
mut removed_visibilities_query: Extract<RemovedComponents<ViewVisibility>>,
mut removed_global_transforms_query: Extract<RemovedComponents<GlobalTransform>>,
mut removed_meshes_query: Extract<RemovedComponents<Mesh3d>>,
gpu_culling_query: Extract<Query<(), (With<Camera>, Without<NoIndirectDrawing>)>>,
meshes_to_reextract_next_frame: ResMut<MeshesToReextractNextFrame>,
@ -1509,11 +1507,7 @@ pub fn extract_meshes_for_gpu_building(
}
// Also record info about each mesh that became invisible.
for entity in removed_visibilities_query
.read()
.chain(removed_global_transforms_query.read())
.chain(removed_meshes_query.read())
{
for entity in removed_meshes_query.read() {
// Only queue a mesh for removal if we didn't pick it up above.
// It's possible that a necessary component was removed and re-added in
// the same frame.

View File

@ -309,7 +309,6 @@ pub fn extract_skins(
skinned_mesh_inverse_bindposes: Extract<Res<Assets<SkinnedMeshInverseBindposes>>>,
changed_transforms: Extract<Query<(Entity, &GlobalTransform), Changed<GlobalTransform>>>,
joints: Extract<Query<&GlobalTransform>>,
mut removed_visibilities_query: Extract<RemovedComponents<ViewVisibility>>,
mut removed_skinned_meshes_query: Extract<RemovedComponents<SkinnedMesh>>,
) {
let skin_uniforms = skin_uniforms.into_inner();
@ -335,10 +334,7 @@ pub fn extract_skins(
);
// Delete skins that became invisible.
for skinned_mesh_entity in removed_visibilities_query
.read()
.chain(removed_skinned_meshes_query.read())
{
for skinned_mesh_entity in removed_skinned_meshes_query.read() {
// Only remove a skin if we didn't pick it up in `add_or_delete_skins`.
// It's possible that a necessary component was removed and re-added in
// the same frame.

View File

@ -331,7 +331,6 @@ pub fn extract_mesh_materials_2d<M: Material2d>(
Or<(Changed<ViewVisibility>, Changed<MeshMaterial2d<M>>)>,
>,
>,
mut removed_visibilities_query: Extract<RemovedComponents<ViewVisibility>>,
mut removed_materials_query: Extract<RemovedComponents<MeshMaterial2d<M>>>,
) {
for (entity, view_visibility, material) in &changed_meshes_query {
@ -342,10 +341,7 @@ pub fn extract_mesh_materials_2d<M: Material2d>(
}
}
for entity in removed_visibilities_query
.read()
.chain(removed_materials_query.read())
{
for entity in removed_materials_query.read() {
// Only queue a mesh for removal if we didn't pick it up above.
// It's possible that a necessary component was removed and re-added in
// the same frame.