Faster FilteredEntity(Ref|Mut) and Entity(Ref|Mut)Except by borrowing Access
#20111
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Objective
Improve the performance of queries using
FilteredEntityRef,FilteredEntityMut,EntityRefExcept, andEntityMutExcept. In particular, this appears to speed upbevy_animation::animate_targetsby 10% in many-foxes.FilteredEntity(Ref|Mut)needs to store anAccessto determine which components may be accessed. Prior to #15396, this required cloning theAccessfor each instance. Now, we can borrow theAccessfrom the query state and make cheap pointer copies.Entity(Ref|Mut)Exceptavoided needing to clone anAccessby calling functions on theBundletrait. Unfortunately, that meant we needed to convert from a type to aComponentIdfor every component in the bundle on every check. Now, we can do those conversions up front and pass references to anAccess.Finally, fix a bug where
Entity(Ref|Mut)Exceptwould not initialize their components duringinit_state. I noticed this while updatinginit_stateand fixed it while I was there. That was normally harmless because the components would be registered elsewhere, but a system likefn system(_q1: Query<EntityMutExcept<C>>, _q2: Query<&mut C>) {}would fail to find theComponentIdforCand not exclude it from the access forq1, and then panic with conflicting access fromq2.Solution
Change
FilteredEntityRefandFilteredEntityMutto store&'s Accessinstead ofAccess, and changeEntityRefExceptandEntityMutExceptto store an extra&'s Access.This adds the
'slifetime to those four types, and most changes are adding lifetimes as appropriate.Change the
WorldQuery::StateforEntity(Ref|Mut)Exceptto store anAccessthat can be borrowed from, replacing theSmallVec<[ComponentId; 4]>that was used only to set the query access.To support the conversions from
EntityRefandEntityMut, we need to be able to create a&'static Accessfor read-all or write-all. I could not changefn read_all_components()to beconstbecause it called the non-constFixedBitSet::clear(), so I created separate constructor functions.Testing
Ran
cargo run --example many_foxes --features bevy/trace_tracy --releasebefore and after, and compared the results ofanimate_targets, since that is the only in-engine use ofEntityMutExceptand was the motivation for creating it.Yellow is this PR, red is main: