Static and cached marker components #11864
Closed
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
Bevy assumes all entities are entirely dynamic. This is a good default, because it encourages us to keep bevy scalable and efficient. Unfortunately this means we often waste some of our limited compute each frame re-exporting and re-processing data that hasn't actually changed.
There should be a way to mark entities that only need to be processed once without needing to rely on change detection (which is not efficient when the number of changes is small compared to the number of queried items).
Solution
Add two new table-backed marker components:
Static
andCached
.Bevy assumes that while an entity is marked as
Static
, it's properties will not change in any way visible to the user. You can basically think ofStatic
entities as being part of "the map" or "the game world". Bevy doesn't setStatic
on any entities by default; that is left to the end user. Static objects can be easily excluded from systems likepropagate_transforms
withWithout<Static>
.After the first frame in which a
Static
entity is view-visible, it is marked asCached
. Render extraction systems can simply remove aentity_map.clear()
and add aWithout<Cached>
query bound to retain extractedStatic
information.Cached
is removed automatically from entities that are notStatic
, and can also be manually unset in the main world to cause a cache flush.Static
andCached
are tabled-backed. This means there is a reasonably large fixed cost to adding or removing these components. But this also means that entities with these components get kicked off into their own archetypes, and so have no query-iteration overhead (unlikeChanged<T>
). This can lead to large performance gains in several schedules (but particularly in render extraction) when the vast majority of rendered objects areStatic
, andStatic
is only rarely added or removed.The current implementation is a prototype. I am still trying to identify other hot queries that could benefit from
Without<Cached>
.I have profiled this against
many_cubes
andmany_lights
. Both show a significant potential for improvement over main, but I'd like to hold off on posting any of my results until this is more complete.Here are some potential issues:
render_mesh_instances
are never cleared.Cached
controls when they are overwritten, and only visible entities are accessed. The memory cost is minimal compared to the time cost of clearing out-of-view cached items.Static
andCached
stuff. I plan to add this but it may require tweakingpropagate_transforms
.propagate_transforms
needs to visit every static node with children. Combining this approach with Parallelized transform propagation #11760 will significantly improve this issue.