Skip to content

Commit

Permalink
Parallel Transform Propagation (#17840)
Browse files Browse the repository at this point in the history
# Objective

- Make transform propagation faster.

## Solution

- Work sharing worker threads
- Parallel tree traversal excluding leaves
- Second cache friendly wide pass over all leaves
- 3-10x faster than main

## Testing

- Tracy
- Caldera hotel is showing 3-7x faster on my M4 Max. Timing for bevy's
existing transform system shifts wildly run to run, so I don't know that
I would advertise a particular number. But this implementation is faster
in a... statistically significant way.

![image](https://github.com/user-attachments/assets/b4a48fc6-86b8-4b9c-8c5e-5b746c1d163b)

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: François Mockers <mockersf@gmail.com>
  • Loading branch information
3 people authored Feb 23, 2025
1 parent e4e70a7 commit dba1f7a
Show file tree
Hide file tree
Showing 5 changed files with 578 additions and 115 deletions.
32 changes: 31 additions & 1 deletion crates/bevy_transform/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,11 @@ keywords = ["bevy"]
# bevy
bevy_app = { path = "../bevy_app", version = "0.16.0-dev", default-features = false, optional = true }
bevy_ecs = { path = "../bevy_ecs", version = "0.16.0-dev", default-features = false, optional = true }
bevy_log = { path = "../bevy_log", version = "0.16.0-dev", default-features = false, optional = true }
bevy_math = { path = "../bevy_math", version = "0.16.0-dev", default-features = false }
bevy_reflect = { path = "../bevy_reflect", version = "0.16.0-dev", default-features = false, optional = true }
bevy_tasks = { path = "../bevy_tasks", version = "0.16.0-dev", default-features = false, optional = true }
bevy_utils = { path = "../bevy_utils", version = "0.16.0-dev", default-features = false, optional = true }
serde = { version = "1", default-features = false, features = [
"derive",
], optional = true }
Expand All @@ -30,7 +33,7 @@ approx = "0.5.1"
[features]
# Turning off default features leaves you with a barebones
# definition of transform.
default = ["std", "bevy-support", "bevy_reflect"]
default = ["std", "bevy-support", "bevy_reflect", "async_executor"]

# Functionality

Expand All @@ -52,6 +55,21 @@ bevy_reflect = [
"bevy_app/bevy_reflect",
]

# Executor Backend

## Uses `async-executor` as a task execution backend.
## This backend is incompatible with `no_std` targets.
async_executor = [
"std",
"dep:bevy_tasks",
"dep:bevy_utils",
"bevy_tasks/async_executor",
]

## Uses `edge-executor` as a task execution backend.
## Use this instead of `async-executor` if working on a `no_std` target.
edge_executor = ["dep:bevy_tasks", "bevy_tasks/edge_executor"]

# Platform Compatibility

## Allows access to the `std` crate. Enabling this feature will prevent compilation
Expand All @@ -60,12 +78,24 @@ bevy_reflect = [
std = [
"alloc",
"bevy_app?/std",
"bevy_log",
"bevy_ecs?/std",
"bevy_math/std",
"bevy_reflect?/std",
"bevy_tasks?/std",
"bevy_utils?/std",
"serde?/std",
]

## `critical-section` provides the building blocks for synchronization primitives
## on all platforms, including `no_std`.
critical-section = [
"bevy_app?/critical-section",
"bevy_ecs?/critical-section",
"bevy_tasks?/critical-section",
"bevy_reflect?/critical-section",
]

## Allows access to the `alloc` crate.
alloc = ["serde?/alloc"]

Expand Down
29 changes: 15 additions & 14 deletions crates/bevy_transform/src/plugins.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use crate::systems::{propagate_transforms, sync_simple_transforms};
use crate::systems::{
compute_transform_leaves, propagate_parent_transforms, sync_simple_transforms,
};
use bevy_app::{App, Plugin, PostStartup, PostUpdate};
use bevy_ecs::schedule::{IntoSystemConfigs, IntoSystemSetConfigs, SystemSet};

Expand Down Expand Up @@ -32,14 +34,12 @@ impl Plugin for TransformPlugin {
.add_systems(
PostStartup,
(
sync_simple_transforms
.in_set(TransformSystem::TransformPropagate)
// FIXME: https://github.com/bevyengine/bevy/issues/4381
// These systems cannot access the same entities,
// due to subtle query filtering that is not yet correctly computed in the ambiguity detector
.ambiguous_with(PropagateTransformsSet),
propagate_transforms.in_set(PropagateTransformsSet),
),
propagate_parent_transforms,
(compute_transform_leaves, sync_simple_transforms)
.ambiguous_with(TransformSystem::TransformPropagate),
)
.chain()
.in_set(PropagateTransformsSet),
)
.configure_sets(
PostUpdate,
Expand All @@ -48,11 +48,12 @@ impl Plugin for TransformPlugin {
.add_systems(
PostUpdate,
(
sync_simple_transforms
.in_set(TransformSystem::TransformPropagate)
.ambiguous_with(PropagateTransformsSet),
propagate_transforms.in_set(PropagateTransformsSet),
),
propagate_parent_transforms,
(compute_transform_leaves, sync_simple_transforms) // TODO: Adjust the internal parallel queries to make these parallel systems more efficiently share and fill CPU time.
.ambiguous_with(TransformSystem::TransformPropagate),
)
.chain()
.in_set(PropagateTransformsSet),
);
}
}
Loading

0 comments on commit dba1f7a

Please sign in to comment.