Fix transform propagation of orphaned entities#7264
Fix transform propagation of orphaned entities#7264james7132 merged 4 commits intobevyengine:mainfrom
Conversation
480ab13 to
0436c5f
Compare
crates/bevy_transform/src/systems.rs
Outdated
| 1, | ||
| |(entity, children, transform, mut global_transform)| { | ||
| let changed = transform.is_changed(); | ||
| let changed = transform.is_changed() || orphaned.binary_search(&entity).is_ok(); |
There was a problem hiding this comment.
It may actually be faster to do a sparse set contains check here than do the binary search. It'd also avoid the allocation and sort.
There was a problem hiding this comment.
How would this look? RemovedComponents only exposes the iter() method. all other fields private. I guess the best way would be to add a method on RemovedComponents to allow sparse set contains checks.
There was a problem hiding this comment.
Looks like the entities in World::removed_components are stored in a Vec. It's unlikely that it's possible to outperform sorting + binary search. I expect the Vec to be always relatively small and not spill out of cache.
The alternative is to create a method that exposes a Option<&[Entity]> in RemovedComponents, and iterate through it for each root entities.
Another option is to store orphaned in a Local to avoid allocation at each frame. Of course, since the iterator returned by RemovedComponents::iter is Cloned<slice::Iter<Entity>>, I don't expect it to allocate when it's empty. And storing the Vec in a Local smells memory leak.
There was a problem hiding this comment.
This is non-actionable. If performance is a concern, could you point to ways of benchmarking testing for regression?
There was a problem hiding this comment.
Another option is to store
orphanedin aLocalto avoid allocation at each frame. Of course, since the iterator returned byRemovedComponents::iterisCloned<slice::Iter<Entity>>, I don't expect it to allocate when it's empty. And storing theVecin aLocalsmells memory leak.
This would be a nice (but not necessary) optimization. It would just allow the system to reuse a single allocation, it shouldn't cause a memory leak or anything bad.
There was a problem hiding this comment.
My worry is that orphaning happens in bursts (think of unloading/loading scenes), so we end up with reserved memory for the worst case while the Vec is only fully used one frame every minutes/hours.
I think a cool thing bevy could provide is some sort of smart Local<Vec<T>> that clears intelligently. I think it would benefit the engine itself already.
I've added a Local<Vec<Entity>> to avoid the allocation, but see the two previous paragraphs.
0436c5f to
e59d44e
Compare
james7132
left a comment
There was a problem hiding this comment.
LGTM other than this one nit.
efa3c16 to
b63cbc8
Compare
|
It looks like your PR is a breaking change, but you didn't provide a migration guide. Could you add some context on what users should update when this change get released in a new version of Bevy? |
joseph-gio
left a comment
There was a problem hiding this comment.
Good fix, there's something I'm not sure about yet though.
crates/bevy_transform/src/systems.rs
Outdated
| 1, | ||
| |(entity, children, transform, mut global_transform)| { | ||
| let changed = transform.is_changed(); | ||
| let changed = transform.is_changed() || orphaned.binary_search(&entity).is_ok(); |
There was a problem hiding this comment.
Another option is to store
orphanedin aLocalto avoid allocation at each frame. Of course, since the iterator returned byRemovedComponents::iterisCloned<slice::Iter<Entity>>, I don't expect it to allocate when it's empty. And storing theVecin aLocalsmells memory leak.
This would be a nice (but not necessary) optimization. It would just allow the system to reuse a single allocation, it shouldn't cause a memory leak or anything bad.
Co-authored-by: vyb <vyb@users.noreply.github.com>
b63cbc8 to
d1af08a
Compare
Co-authored-by: JoJoJet <21144246+JoJoJet@users.noreply.github.com>
…tities query (#9518) # Objective `sync_simple_transforms` only checks for removed parents and doesn't filter for `Without<Parent>`, so it overwrites the `GlobalTransform` of non-orphan entities that were orphaned and then reparented since the last update. Introduced by #7264 ## Solution Filter for `Without<Parent>`. Fixes #9517, #9492 ## Changelog `sync_simple_transforms`: * Added a `Without<Parent>` filter to the orphaned entities query.
…tities query (bevyengine#9518) # Objective `sync_simple_transforms` only checks for removed parents and doesn't filter for `Without<Parent>`, so it overwrites the `GlobalTransform` of non-orphan entities that were orphaned and then reparented since the last update. Introduced by bevyengine#7264 ## Solution Filter for `Without<Parent>`. Fixes bevyengine#9517, bevyengine#9492 ## Changelog `sync_simple_transforms`: * Added a `Without<Parent>` filter to the orphaned entities query.
Objective
GlobalTransformdid not get updated whenParentwas removed #7263This has nothing to do with #7024. This is for the case where the
user opted to not keep the same global transform on update.
Solution
RemovedComponent<Parent>topropagate_transformsRemovedComponent<Parent>andLocal<Vec<Entity>>tosync_simple_transformsPerformance note
This should only incur a cost in cases where a parent is removed.
A minimal overhead (one look up in the
removed_componentssparse set) per root entities without children which transform didn't
change. A
Vecthe size of the largest number of entities removedwith a
Parentcomponent in a single frame, and a binary search ona
Vecper root entities.It could slow up considerably in situations where a lot of entities are
orphaned consistently during every frame, since
sync_simple_transformsis not parallel. But in this situation,it is likely that the overhead of archetype updates overwhelms everything.
Changelog
GlobalTransformnot getting updated whenParentis removedMigration Guide
bevy_transform::systems::sync_simple_transformsandbevy_transform::systems::propagate_transforms(which is not re-exported by bevy) you need to account for the additionalRemovedComponents<Parent>parameter.