From 698da92ed168d7a6b27c123bb879a2ab3f6f4053 Mon Sep 17 00:00:00 2001 From: Aevyrie Roessler Date: Sun, 30 Mar 2025 00:13:27 -0700 Subject: [PATCH 1/7] Fix prev gt calc perf --- crates/bevy_pbr/src/prepass/mod.rs | 18 ++++++++++-------- examples/tools/scene_viewer/main.rs | 8 +++++++- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/crates/bevy_pbr/src/prepass/mod.rs b/crates/bevy_pbr/src/prepass/mod.rs index 7b70df38aab70..a13a5487da969 100644 --- a/crates/bevy_pbr/src/prepass/mod.rs +++ b/crates/bevy_pbr/src/prepass/mod.rs @@ -268,20 +268,22 @@ type PreviousMeshFilter = Or<(With, With)>; pub fn update_mesh_previous_global_transforms( mut commands: Commands, views: Query<&Camera, Or<(With, With)>>, - meshes: Query<(Entity, &GlobalTransform, Option<&PreviousGlobalTransform>), PreviousMeshFilter>, + new_meshes: Query< + (Entity, &GlobalTransform), + (PreviousMeshFilter, Without), + >, + mut meshes: Query<(&GlobalTransform, &mut PreviousGlobalTransform), PreviousMeshFilter>, ) { let should_run = views.iter().any(|camera| camera.is_active); if should_run { - for (entity, transform, old_previous_transform) in &meshes { + for (entity, transform) in &new_meshes { let new_previous_transform = PreviousGlobalTransform(transform.affine()); - // Make sure not to trigger change detection on - // `PreviousGlobalTransform` if the previous transform hasn't - // changed. - if old_previous_transform != Some(&new_previous_transform) { - commands.entity(entity).try_insert(new_previous_transform); - } + commands.entity(entity).try_insert(new_previous_transform); } + meshes.par_iter_mut().for_each(|(transform, mut previous)| { + previous.set_if_neq(PreviousGlobalTransform(transform.affine())); + }); } } diff --git a/examples/tools/scene_viewer/main.rs b/examples/tools/scene_viewer/main.rs index 0266a22ee0a06..279d7ee5fa51c 100644 --- a/examples/tools/scene_viewer/main.rs +++ b/examples/tools/scene_viewer/main.rs @@ -18,6 +18,7 @@ use bevy::{ primitives::{Aabb, Sphere}, }, }; +use futures_lite::StreamExt; #[path = "../../helpers/camera_controller.rs"] mod camera_controller; @@ -82,7 +83,8 @@ fn main() { )) .insert_resource(args) .add_systems(Startup, setup) - .add_systems(PreUpdate, setup_scene_after_load); + .add_systems(PreUpdate, setup_scene_after_load) + .add_systems(Update, count_t); // If deferred shading was requested, turn it on. if deferred == Some(true) { @@ -95,6 +97,10 @@ fn main() { app.run(); } +fn count_t(q: Query<(), With>) { + dbg!(q.iter().len()); +} + fn parse_scene(scene_path: String) -> (String, usize) { if scene_path.contains('#') { let gltf_and_scene = scene_path.split('#').collect::>(); From 27d922f54e4fb918d22945772ab9c1e2c485d2f6 Mon Sep 17 00:00:00 2001 From: Aevyrie Roessler Date: Sun, 30 Mar 2025 00:33:24 -0700 Subject: [PATCH 2/7] Mesh specialization parallelization --- crates/bevy_pbr/src/material.rs | 11 ++++++++--- crates/bevy_sprite/src/mesh2d/material.rs | 11 ++++++++--- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/crates/bevy_pbr/src/material.rs b/crates/bevy_pbr/src/material.rs index 0cf6686b3e9a6..f1a6f06498f42 100644 --- a/crates/bevy_pbr/src/material.rs +++ b/crates/bevy_pbr/src/material.rs @@ -51,6 +51,7 @@ use bevy_render::{ }; use bevy_render::{mesh::allocator::MeshAllocator, sync_world::MainEntityHashMap}; use bevy_render::{texture::FallbackImage, view::RenderVisibleEntities}; +use bevy_utils::Parallel; use core::{hash::Hash, marker::PhantomData}; use tracing::error; @@ -796,14 +797,18 @@ pub fn check_entities_needing_specialization( AssetChanged>, )>, >, + mut par_local: Local>>, mut entities_needing_specialization: ResMut>, ) where M: Material, { entities_needing_specialization.clear(); - for entity in &needs_specialization { - entities_needing_specialization.push(entity); - } + + needs_specialization + .par_iter() + .for_each(|entity| par_local.borrow_local_mut().push(entity)); + + par_local.drain_into(&mut entities_needing_specialization); } pub fn specialize_material_meshes( diff --git a/crates/bevy_sprite/src/mesh2d/material.rs b/crates/bevy_sprite/src/mesh2d/material.rs index ce2803b261680..ac67972c81331 100644 --- a/crates/bevy_sprite/src/mesh2d/material.rs +++ b/crates/bevy_sprite/src/mesh2d/material.rs @@ -44,6 +44,7 @@ use bevy_render::{ view::{ExtractedView, ViewVisibility}, Extract, ExtractSchedule, Render, RenderApp, RenderSet, }; +use bevy_utils::Parallel; use core::{hash::Hash, marker::PhantomData}; use derive_more::derive::From; use tracing::error; @@ -644,14 +645,18 @@ pub fn check_entities_needing_specialization( AssetChanged>, )>, >, + mut par_local: Local>>, mut entities_needing_specialization: ResMut>, ) where M: Material2d, { entities_needing_specialization.clear(); - for entity in &needs_specialization { - entities_needing_specialization.push(entity); - } + + needs_specialization + .par_iter() + .for_each(|entity| par_local.borrow_local_mut().push(entity)); + + par_local.drain_into(&mut entities_needing_specialization); } pub fn specialize_material2d_meshes( From de71b4d224766b8e7accd5483b703fdf725e38a3 Mon Sep 17 00:00:00 2001 From: Aevyrie Roessler Date: Sun, 30 Mar 2025 01:25:50 -0700 Subject: [PATCH 3/7] Parallelize visibility range checks --- .../bevy_render/src/view/visibility/range.rs | 53 +++++++++++-------- 1 file changed, 30 insertions(+), 23 deletions(-) diff --git a/crates/bevy_render/src/view/visibility/range.rs b/crates/bevy_render/src/view/visibility/range.rs index 5a6728337b611..85eb4e39b74a1 100644 --- a/crates/bevy_render/src/view/visibility/range.rs +++ b/crates/bevy_render/src/view/visibility/range.rs @@ -15,13 +15,13 @@ use bevy_ecs::{ removal_detection::RemovedComponents, resource::Resource, schedule::IntoScheduleConfigs as _, - system::{Query, Res, ResMut}, + system::{Local, Query, Res, ResMut}, }; use bevy_math::{vec4, FloatOrd, Vec4}; use bevy_platform_support::collections::HashMap; use bevy_reflect::Reflect; use bevy_transform::components::GlobalTransform; -use bevy_utils::prelude::default; +use bevy_utils::{prelude::default, Parallel}; use nonmax::NonMaxU16; use wgpu::{BufferBindingType, BufferUsages}; @@ -385,6 +385,7 @@ impl VisibleEntityRanges { pub fn check_visibility_ranges( mut visible_entity_ranges: ResMut, view_query: Query<(Entity, &GlobalTransform), With>, + mut par_local: Local>>, mut entity_query: Query<(Entity, &GlobalTransform, Option<&Aabb>, &VisibilityRange)>, ) { visible_entity_ranges.clear(); @@ -404,29 +405,35 @@ pub fn check_visibility_ranges( // Check each entity/view pair. Only consider entities with // [`VisibilityRange`] components. - for (entity, entity_transform, maybe_model_aabb, visibility_range) in entity_query.iter_mut() { - let mut visibility = 0; - for (view_index, &(_, view_position)) in views.iter().enumerate() { - // If instructed to use the AABB and the model has one, use its - // center as the model position. Otherwise, use the model's - // translation. - let model_position = match (visibility_range.use_aabb, maybe_model_aabb) { - (true, Some(model_aabb)) => entity_transform - .affine() - .transform_point3a(model_aabb.center), - _ => entity_transform.translation_vec3a(), - }; - - if visibility_range.is_visible_at_all((view_position - model_position).length()) { - visibility |= 1 << view_index; + entity_query.par_iter().for_each( + |(entity, entity_transform, maybe_model_aabb, visibility_range)| { + let mut visibility = 0; + for (view_index, &(_, view_position)) in views.iter().enumerate() { + // If instructed to use the AABB and the model has one, use its + // center as the model position. Otherwise, use the model's + // translation. + let model_position = match (visibility_range.use_aabb, maybe_model_aabb) { + (true, Some(model_aabb)) => entity_transform + .affine() + .transform_point3a(model_aabb.center), + _ => entity_transform.translation_vec3a(), + }; + + if visibility_range.is_visible_at_all((view_position - model_position).length()) { + visibility |= 1 << view_index; + } } - } - // Invisible entities have no entry at all in the hash map. This speeds - // up checks slightly in this common case. - if visibility != 0 { - visible_entity_ranges.entities.insert(entity, visibility); - } + // Invisible entities have no entry at all in the hash map. This speeds + // up checks slightly in this common case. + if visibility != 0 { + par_local.borrow_local_mut().push((entity, visibility)); + } + }, + ); + + for (entity, visibility) in par_local.drain() { + visible_entity_ranges.entities.insert(entity, visibility); } } From b5266a462f2edb62f257815d76778770fd9a323c Mon Sep 17 00:00:00 2001 From: Aevyrie Roessler Date: Sun, 30 Mar 2025 15:03:53 -0700 Subject: [PATCH 4/7] Revert changes to scene viewer --- examples/tools/scene_viewer/main.rs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/examples/tools/scene_viewer/main.rs b/examples/tools/scene_viewer/main.rs index 279d7ee5fa51c..0266a22ee0a06 100644 --- a/examples/tools/scene_viewer/main.rs +++ b/examples/tools/scene_viewer/main.rs @@ -18,7 +18,6 @@ use bevy::{ primitives::{Aabb, Sphere}, }, }; -use futures_lite::StreamExt; #[path = "../../helpers/camera_controller.rs"] mod camera_controller; @@ -83,8 +82,7 @@ fn main() { )) .insert_resource(args) .add_systems(Startup, setup) - .add_systems(PreUpdate, setup_scene_after_load) - .add_systems(Update, count_t); + .add_systems(PreUpdate, setup_scene_after_load); // If deferred shading was requested, turn it on. if deferred == Some(true) { @@ -97,10 +95,6 @@ fn main() { app.run(); } -fn count_t(q: Query<(), With>) { - dbg!(q.iter().len()); -} - fn parse_scene(scene_path: String) -> (String, usize) { if scene_path.contains('#') { let gltf_and_scene = scene_path.split('#').collect::>(); From f1b27bfa4ed8bd48def2b7e47805b4ed9dcc91d5 Mon Sep 17 00:00:00 2001 From: Aevyrie Roessler Date: Sun, 30 Mar 2025 15:08:03 -0700 Subject: [PATCH 5/7] Remove existing unused `mut` keyword --- crates/bevy_render/src/view/visibility/range.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_render/src/view/visibility/range.rs b/crates/bevy_render/src/view/visibility/range.rs index befcb92e5e416..66a08a934f514 100644 --- a/crates/bevy_render/src/view/visibility/range.rs +++ b/crates/bevy_render/src/view/visibility/range.rs @@ -386,7 +386,7 @@ pub fn check_visibility_ranges( mut visible_entity_ranges: ResMut, view_query: Query<(Entity, &GlobalTransform), With>, mut par_local: Local>>, - mut entity_query: Query<(Entity, &GlobalTransform, Option<&Aabb>, &VisibilityRange)>, + entity_query: Query<(Entity, &GlobalTransform, Option<&Aabb>, &VisibilityRange)>, ) { visible_entity_ranges.clear(); From 0bfbbcf40daeb7ebd71f928222167b46f132bf3c Mon Sep 17 00:00:00 2001 From: Aevyrie Roessler Date: Sun, 30 Mar 2025 20:45:21 -0700 Subject: [PATCH 6/7] Review feedback: avoid allocation. --- crates/bevy_render/src/view/visibility/range.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/crates/bevy_render/src/view/visibility/range.rs b/crates/bevy_render/src/view/visibility/range.rs index 66a08a934f514..0338ab7f88ffd 100644 --- a/crates/bevy_render/src/view/visibility/range.rs +++ b/crates/bevy_render/src/view/visibility/range.rs @@ -432,9 +432,7 @@ pub fn check_visibility_ranges( }, ); - for (entity, visibility) in par_local.drain() { - visible_entity_ranges.entities.insert(entity, visibility); - } + visible_entity_ranges.entities.extend(par_local.drain()) } /// Extracts all [`VisibilityRange`] components from the main world to the From 211a541d3d5fa4a454c68c9c05fd6e14c398fe33 Mon Sep 17 00:00:00 2001 From: Aevyrie Date: Sun, 30 Mar 2025 21:53:30 -0700 Subject: [PATCH 7/7] Update crates/bevy_render/src/view/visibility/range.rs Co-authored-by: Zachary Harrold --- crates/bevy_render/src/view/visibility/range.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_render/src/view/visibility/range.rs b/crates/bevy_render/src/view/visibility/range.rs index 0338ab7f88ffd..74ac212bf34dd 100644 --- a/crates/bevy_render/src/view/visibility/range.rs +++ b/crates/bevy_render/src/view/visibility/range.rs @@ -432,7 +432,7 @@ pub fn check_visibility_ranges( }, ); - visible_entity_ranges.entities.extend(par_local.drain()) + visible_entity_ranges.entities.extend(par_local.drain()); } /// Extracts all [`VisibilityRange`] components from the main world to the