Skip to content

Conversation

@chescock
Copy link
Contributor

Objective

Improve the performance of queries using FilteredEntityRef, FilteredEntityMut, EntityRefExcept, and EntityMutExcept. In particular, this appears to speed up bevy_animation::animate_targets by 10% in many-foxes.

FilteredEntity(Ref|Mut) needs to store an Access to determine which components may be accessed. Prior to #15396, this required cloning the Access for each instance. Now, we can borrow the Access from the query state and make cheap pointer copies.

Entity(Ref|Mut)Except avoided needing to clone an Access by calling functions on the Bundle trait. Unfortunately, that meant we needed to convert from a type to a ComponentId for every component in the bundle on every check. Now, we can do those conversions up front and pass references to an Access.

Finally, fix a bug where Entity(Ref|Mut)Except would not initialize their components during init_state. I noticed this while updating init_state and fixed it while I was there. That was normally harmless because the components would be registered elsewhere, but a system like fn system(_q1: Query<EntityMutExcept<C>>, _q2: Query<&mut C>) {} would fail to find the ComponentId for C and not exclude it from the access for q1, and then panic with conflicting access from q2.

Solution

Change FilteredEntityRef and FilteredEntityMut to store &'s Access instead of Access, and change EntityRefExcept and EntityMutExcept to store an extra &'s Access.

This adds the 's lifetime to those four types, and most changes are adding lifetimes as appropriate.

Change the WorldQuery::State for Entity(Ref|Mut)Except to store an Access that can be borrowed from, replacing the SmallVec<[ComponentId; 4]> that was used only to set the query access.

To support the conversions from EntityRef and EntityMut, we need to be able to create a &'static Access for read-all or write-all. I could not change fn read_all_components() to be const because it called the non-const FixedBitSet::clear(), so I created separate constructor functions.

Testing

Ran cargo run --example many_foxes --features bevy/trace_tracy --release before and after, and compared the results of animate_targets, since that is the only in-engine use of EntityMutExcept and was the motivation for creating it.

Yellow is this PR, red is main:

image

@chescock chescock added A-ECS Entities, components, systems, and events C-Performance A change motivated by improving speed, memory usage or compile times S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Jul 13, 2025
Copy link
Contributor

@hymm hymm left a comment

Choose a reason for hiding this comment

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

The changes make sense to me and the code feels a bit cleaner now too. Nice trick to make a const access for the conversions. I wouldn't of thought to do that.

Could you add a test for the bug you found? We've had issues with init_state before and it's easy for this stuff to get messed up in refactors.

Copy link

@PhantomMorrigan PhantomMorrigan left a comment

Choose a reason for hiding this comment

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

Cleaner and faster! Looks all good.

@JaySpruce JaySpruce added S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it and removed S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Jul 19, 2025
@alice-i-cecile alice-i-cecile added this pull request to the merge queue Jul 21, 2025
Merged via the queue into bevyengine:main with commit 0dce905 Jul 21, 2025
34 checks passed
@Shatur Shatur mentioned this pull request Jul 15, 2025
4 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-ECS Entities, components, systems, and events C-Performance A change motivated by improving speed, memory usage or compile times S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants