Skip to content

Commit cba6698

Browse files
aevyriebushrat011899
authored andcommitted
Parallelize bevy 0.16-rc bottlenecks (#18632)
# Objective - Found stuttering and performance degradation while updating big_space stress tests. ## Solution - Identify and fix slow spots using tracy. Patch to verify fixes. ## Testing - Tracy - Before: ![image](https://github.com/user-attachments/assets/ab7f440d-88c1-4ad9-9ad9-dca127c9421f) - prev_gt parallelization and mutating instead of component insertion: ![image](https://github.com/user-attachments/assets/9279a663-c0ba-4529-b709-d0f81f2a1d8b) - parallelize visibility ranges and mesh specialization ![image](https://github.com/user-attachments/assets/25b70e7c-5d30-48ab-9bb2-79211d4d672f) --------- Co-authored-by: Zachary Harrold <zac@harrold.com.au>
1 parent d5c5de2 commit cba6698

File tree

4 files changed

+56
-39
lines changed

4 files changed

+56
-39
lines changed

crates/bevy_pbr/src/material.rs

+8-3
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ use bevy_render::{
5252
};
5353
use bevy_render::{mesh::allocator::MeshAllocator, sync_world::MainEntityHashMap};
5454
use bevy_render::{texture::FallbackImage, view::RenderVisibleEntities};
55+
use bevy_utils::Parallel;
5556
use core::{hash::Hash, marker::PhantomData};
5657
use tracing::error;
5758

@@ -832,14 +833,18 @@ pub fn check_entities_needing_specialization<M>(
832833
With<MeshMaterial3d<M>>,
833834
),
834835
>,
836+
mut par_local: Local<Parallel<Vec<Entity>>>,
835837
mut entities_needing_specialization: ResMut<EntitiesNeedingSpecialization<M>>,
836838
) where
837839
M: Material,
838840
{
839841
entities_needing_specialization.clear();
840-
for entity in &needs_specialization {
841-
entities_needing_specialization.push(entity);
842-
}
842+
843+
needs_specialization
844+
.par_iter()
845+
.for_each(|entity| par_local.borrow_local_mut().push(entity));
846+
847+
par_local.drain_into(&mut entities_needing_specialization);
843848
}
844849

845850
pub fn specialize_material_meshes<M: Material>(

crates/bevy_pbr/src/prepass/mod.rs

+10-8
Original file line numberDiff line numberDiff line change
@@ -268,20 +268,22 @@ type PreviousMeshFilter = Or<(With<Mesh3d>, With<MeshletMesh3d>)>;
268268
pub fn update_mesh_previous_global_transforms(
269269
mut commands: Commands,
270270
views: Query<&Camera, Or<(With<Camera3d>, With<ShadowView>)>>,
271-
meshes: Query<(Entity, &GlobalTransform, Option<&PreviousGlobalTransform>), PreviousMeshFilter>,
271+
new_meshes: Query<
272+
(Entity, &GlobalTransform),
273+
(PreviousMeshFilter, Without<PreviousGlobalTransform>),
274+
>,
275+
mut meshes: Query<(&GlobalTransform, &mut PreviousGlobalTransform), PreviousMeshFilter>,
272276
) {
273277
let should_run = views.iter().any(|camera| camera.is_active);
274278

275279
if should_run {
276-
for (entity, transform, old_previous_transform) in &meshes {
280+
for (entity, transform) in &new_meshes {
277281
let new_previous_transform = PreviousGlobalTransform(transform.affine());
278-
// Make sure not to trigger change detection on
279-
// `PreviousGlobalTransform` if the previous transform hasn't
280-
// changed.
281-
if old_previous_transform != Some(&new_previous_transform) {
282-
commands.entity(entity).try_insert(new_previous_transform);
283-
}
282+
commands.entity(entity).try_insert(new_previous_transform);
284283
}
284+
meshes.par_iter_mut().for_each(|(transform, mut previous)| {
285+
previous.set_if_neq(PreviousGlobalTransform(transform.affine()));
286+
});
285287
}
286288
}
287289

crates/bevy_render/src/view/visibility/range.rs

+30-25
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,13 @@ use bevy_ecs::{
1515
removal_detection::RemovedComponents,
1616
resource::Resource,
1717
schedule::IntoScheduleConfigs as _,
18-
system::{Query, Res, ResMut},
18+
system::{Local, Query, Res, ResMut},
1919
};
2020
use bevy_math::{vec4, FloatOrd, Vec4};
2121
use bevy_platform_support::collections::HashMap;
2222
use bevy_reflect::Reflect;
2323
use bevy_transform::components::GlobalTransform;
24-
use bevy_utils::prelude::default;
24+
use bevy_utils::{prelude::default, Parallel};
2525
use nonmax::NonMaxU16;
2626
use wgpu::{BufferBindingType, BufferUsages};
2727

@@ -385,7 +385,8 @@ impl VisibleEntityRanges {
385385
pub fn check_visibility_ranges(
386386
mut visible_entity_ranges: ResMut<VisibleEntityRanges>,
387387
view_query: Query<(Entity, &GlobalTransform), With<Camera>>,
388-
mut entity_query: Query<(Entity, &GlobalTransform, Option<&Aabb>, &VisibilityRange)>,
388+
mut par_local: Local<Parallel<Vec<(Entity, u32)>>>,
389+
entity_query: Query<(Entity, &GlobalTransform, Option<&Aabb>, &VisibilityRange)>,
389390
) {
390391
visible_entity_ranges.clear();
391392

@@ -404,30 +405,34 @@ pub fn check_visibility_ranges(
404405

405406
// Check each entity/view pair. Only consider entities with
406407
// [`VisibilityRange`] components.
407-
for (entity, entity_transform, maybe_model_aabb, visibility_range) in entity_query.iter_mut() {
408-
let mut visibility = 0;
409-
for (view_index, &(_, view_position)) in views.iter().enumerate() {
410-
// If instructed to use the AABB and the model has one, use its
411-
// center as the model position. Otherwise, use the model's
412-
// translation.
413-
let model_position = match (visibility_range.use_aabb, maybe_model_aabb) {
414-
(true, Some(model_aabb)) => entity_transform
415-
.affine()
416-
.transform_point3a(model_aabb.center),
417-
_ => entity_transform.translation_vec3a(),
418-
};
419-
420-
if visibility_range.is_visible_at_all((view_position - model_position).length()) {
421-
visibility |= 1 << view_index;
408+
entity_query.par_iter().for_each(
409+
|(entity, entity_transform, maybe_model_aabb, visibility_range)| {
410+
let mut visibility = 0;
411+
for (view_index, &(_, view_position)) in views.iter().enumerate() {
412+
// If instructed to use the AABB and the model has one, use its
413+
// center as the model position. Otherwise, use the model's
414+
// translation.
415+
let model_position = match (visibility_range.use_aabb, maybe_model_aabb) {
416+
(true, Some(model_aabb)) => entity_transform
417+
.affine()
418+
.transform_point3a(model_aabb.center),
419+
_ => entity_transform.translation_vec3a(),
420+
};
421+
422+
if visibility_range.is_visible_at_all((view_position - model_position).length()) {
423+
visibility |= 1 << view_index;
424+
}
422425
}
423-
}
424426

425-
// Invisible entities have no entry at all in the hash map. This speeds
426-
// up checks slightly in this common case.
427-
if visibility != 0 {
428-
visible_entity_ranges.entities.insert(entity, visibility);
429-
}
430-
}
427+
// Invisible entities have no entry at all in the hash map. This speeds
428+
// up checks slightly in this common case.
429+
if visibility != 0 {
430+
par_local.borrow_local_mut().push((entity, visibility));
431+
}
432+
},
433+
);
434+
435+
visible_entity_ranges.entities.extend(par_local.drain());
431436
}
432437

433438
/// Extracts all [`VisibilityRange`] components from the main world to the

crates/bevy_sprite/src/mesh2d/material.rs

+8-3
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ use bevy_render::{
4545
view::{ExtractedView, ViewVisibility},
4646
Extract, ExtractSchedule, Render, RenderApp, RenderSet,
4747
};
48+
use bevy_utils::Parallel;
4849
use core::{hash::Hash, marker::PhantomData};
4950
use derive_more::derive::From;
5051
use tracing::error;
@@ -660,14 +661,18 @@ pub fn check_entities_needing_specialization<M>(
660661
With<MeshMaterial2d<M>>,
661662
),
662663
>,
664+
mut par_local: Local<Parallel<Vec<Entity>>>,
663665
mut entities_needing_specialization: ResMut<EntitiesNeedingSpecialization<M>>,
664666
) where
665667
M: Material2d,
666668
{
667669
entities_needing_specialization.clear();
668-
for entity in &needs_specialization {
669-
entities_needing_specialization.push(entity);
670-
}
670+
671+
needs_specialization
672+
.par_iter()
673+
.for_each(|entity| par_local.borrow_local_mut().push(entity));
674+
675+
par_local.drain_into(&mut entities_needing_specialization);
671676
}
672677

673678
pub fn specialize_material2d_meshes<M: Material2d>(

0 commit comments

Comments
 (0)