bevyengine / bevy

A refreshingly simple data-driven game engine built in Rust
https://bevyengine.org
Apache License 2.0
34.23k stars 3.35k forks source link

Opprotunistically use dense iteration when an archetype and its table are 1:1 #12381

Open james7132 opened 4 months ago

james7132 commented 4 months ago

What problem does this solve or what need does it fill?

We currently force sparse iteration if any of the target components in the data or filter part of a query is a sparse set component. This is suboptimal given the random access pattern forced by archetypal iteration.

If an archetype and its table have the same entity count, we should be able to assume that they target the same set of entities, which should make it safe to use dense iteration.

What solution would you like?

Extend all iteration methods to opportunistically use dense iteration if the fetched archetype and table have the same length.

What alternative(s) have you considered?

Leave it as is, this may notably complicate the safety story for query iteration.

Additional context

Related: #2144.

alice-i-cecile commented 4 months ago

If an archetype and its table have the same entity count

Isn't it possible for them to have the same entity count by coincidence?

james7132 commented 4 months ago

An archetype can only have one table mapped to it. If they have the same entity count, the archetype and table should map to the same entities. If we add a new sparse set component to any of those entities, we still write to the same table, but fragment the archetype instead, which would disable this opportunistic optimization.

cBournhonesque commented 3 weeks ago

Why is iterating through archetypes slower? Are the entities in archetype.entities() not sorted in the same order as the table entities?

re0312 commented 3 weeks ago

Why is iterating through archetypes slower? Are the entities in archetype.entities() not sorted in the same order as the table entities?

yeah , assume we have two distinct archetypes, let's call them A and B: Archetype A: [ TableComponent, SparseComponent ] Archetype B: [ TableComponent ]

Both archetypes share the same table_id. When entities in Archetype B are despawned, could potentially disrupting the order of entities in Archetype A. Furthermore, the archetype iteration retrieves every entity from archetype.entities(), which may hinder certain compiler optimizations.