Skip to content

Avoid performance pitfalls in update_previous_global_transform system #18618

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: main
Choose a base branch
from

Conversation

alice-i-cecile
Copy link
Member

@alice-i-cecile alice-i-cecile commented Mar 30, 2025

Objective

@aevyrie saw this system showing up in his big_space traces.

image

Upon investigation, this system is using commands to unconditionally mutate a component. That's slow!

Apparently this fixes #14681.

Solution

  1. Don't use commands.
  2. Move the should_run guard statement into an actual run condition.
  3. Throw together some simple docs.
  4. Make it parallel.
  5. Use required components to reduce archetype moves (and bugs).

I'm going to avoid parallelizing for now; let's take the free wins here first.

but good news, it is down to 3ms from 115ms on main

Casual 38x perf improvement.

Requests for reviewers

  1. I am not sure where this is used: what should I be testing?
    2. @aevyrie I'd be interested in a fresh bench on this, but this is so clearly better that I don't care if we skip it.
    3. Should I swap to using required components here and avoid ever inserting?

@alice-i-cecile alice-i-cecile added A-Rendering Drawing game state to the screen C-Performance A change motivated by improving speed, memory usage or compile times A-Transform Translations, rotations and scales D-Straightforward Simple bug fixes and API improvements, docs, test and examples S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Mar 30, 2025
@alice-i-cecile alice-i-cecile requested review from aevyrie and JMS55 March 30, 2025 07:06
@alice-i-cecile alice-i-cecile added this to the 0.16 milestone Mar 30, 2025
));
))
// This can't be an attribute on the mesh types due to the shape of our dependency graph
.register_required_components::<Mesh3d, PreviousGlobalTransform>();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure that this is something we want.

PreviousGlobalTransform is intentionally not required by Mesh3d, and it's not due to dependencies (I've talked about wanting to move PreviousGlobalTransform into bevy_transform before).

If you're making a game without temporal effects (TAA/DLSS/RT/motion blur/etc), then there's no need for PreviousGlobalTransform. It's only required for Mesh3d if at least one camera has MotionVectorPrepass.

I think we're better off:

  1. Moving PreviousGlobalTransform to bevy_transform
  2. Having a system in bevy_transform to update PreviousGlobalTransform, no filters based on mesh or whatever
  3. Have a new system in bevy_pbr/bevy_core_pipeline that when there's at least one camera with a MotionVectorPrepass, query for Mesh3d entities without a PreviousGlobalTransform component and insert a dummy one. Order this before the system from 2.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could also do something like add a cargo feature for this, and say using MotionVectorPrepass requires turning the flag on, and then use cfg_attr to require PreviousGlobalTransform.


//
#[cfg(feature = "meshlet")]
app.register_required_components::<MeshletMesh3d, PreviousGlobalTransform>();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not needed, MeshletMesh3d already requires PreviousGlobalTransform.

Co-authored-by: François Mockers <francois.mockers@vleue.com>
@@ -265,24 +275,18 @@ type PreviousMeshFilter = With<Mesh3d>;
#[cfg(feature = "meshlet")]
type PreviousMeshFilter = Or<(With<Mesh3d>, With<MeshletMesh3d>)>;

/// A run condition for [`update_mesh_previous_global_transforms`] that checks if any camera is active.
pub fn any_camera_active(views: Query<&Camera, Or<(With<Camera3d>, With<ShadowView>)>>) -> bool {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have somewhere to have common run conditions? I feel like this could be useful for more than just the prepass module

@aevyrie
Copy link
Member

aevyrie commented Mar 30, 2025

This is an alternative/sibling PR that only addresses perf within functions, so might be less controversial. #18632

@alice-i-cecile alice-i-cecile added S-Waiting-on-Author The author needs to make changes or address concerns before this can be merged and removed S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Mar 31, 2025
@alice-i-cecile alice-i-cecile modified the milestones: 0.16, 0.17 Mar 31, 2025
@alice-i-cecile
Copy link
Member Author

Moving this out of the milestone in favor of #18632. I'll clean this up once that's merged: there's some smaller quality issues to address still.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-Rendering Drawing game state to the screen A-Transform Translations, rotations and scales C-Performance A change motivated by improving speed, memory usage or compile times D-Straightforward Simple bug fixes and API improvements, docs, test and examples S-Waiting-on-Author The author needs to make changes or address concerns before this can be merged
Projects
Status: No status
Development

Successfully merging this pull request may close these issues.

Improve update_mesh_previous_global_transforms() performance
5 participants