Replies: 3 comments 4 replies
-
One potential alternative to |
Beta Was this translation helpful? Give feedback.
-
One thing that isn't mentioned is how this will impact archetypal query iteration. Dense iteration will likely still remain unchanged, but higher archetype fragmentation will negatively affect any query with a sparse set component in it. |
Beta Was this translation helpful? Give feedback.
-
The unused MSB flag in the target portion of the relation pair could be used to indicate wildcard targets. The actual ID portion could then be used to store the ID to a "rule" entity? If we were to go about rules in that fashion. Rules allow expressing relations in terms of relations for those who don't know prolog. |
Beta Was this translation helpful? Give feedback.
-
Was asked to document this somewhere.
For people wanting to implement flecs-like fragmenting relations in bevy, currently
bevy_ecs
isn't well-equipped to efficiently handle an arbitrarily large number of archetypes. This is a quick summary of changes that I think will fix that and let someone trial an implemantion.Improve Worst-Case
Query
Construction TimeConstructing and updating queries involves iterating all archetypes (that the query has not yet seen). A more efficient solution would be for the
Archetypes
structure to have aHashMap<ComponentId, HashMap<ArchetypeId, ArchetypeComponentInfo>>
. Then queries can simply iterate their components and find the intersection of their archetypes.This map would also enable removing archetypes when a particular relation can no longer exist.
Improve Worst-Case
Access
Iteration TimeAccess
is the main primitive used to check queries and systems for conflicts at runtime. Internally, it makes use ofFixedBitSet
instances (I assume because they're very small). Iterating aFixedBitSet
is much faster than iterating a simpleVec<bool>
when the 1s (true
values) are sparse. But that iteration time will grow linearly with the number of (archetype, component) pairs that exist, not just the ones that match.I don't know at what point
FixedBitSet
would start to fall behind, but my suggestion would be replace thoseFixedBitSet
s withHashSet
s.Edit: To greatly reduce the number of matched elements, queries and systems could ignore the "target" of any relation pair and only look at the "relation kind". In other words, their
Access
would have anArchetypeComponentId
for (archetype, relation kind). That would limit parallelism, but it might be worth the tradeoff.Telling Relation Pairs and Entities Apart
If our relations are identified as
(entity.index(), entity.index())
pairs like in flecs, we might have to change the underlying bit pattern ofEntity
to have a way to reliably tell them apart from pairs. The simplest form of this would be aflag
bit, withflag == 0
meaning entity andflag == 1
meaning pair.Naively, this would reduce the hypothetical maximum number of entities from 4 billion to 2 billion. That isn't a big deal, but it might be avoidable. Entity and target indices could continue to use the full
u32
range if the "relation kind" is restricted to component ids and we arbitrarily limit component ids to a smaller range of indices.However, if there's no need for untyped methods, we can maybe avoid the flag bit.
Components as Entities
The last change is making
ComponentId
values use indices from theEntity
address space. This has nothing to do with performance, but it would let components take advantage of everything we have for normal entities.We would need to modify
World::init_component<T>
to account for this by spawning anEntity
to representT
.One other thing we might want is to do is reserve a nice power-of-two number of
Entity
values upfront for normal components (maybe 256?). That way, we can still use aVec
for most of them, with aHashMap
for the bulk of the relation pairs. Might still be premature optimization at this point, though.Beta Was this translation helpful? Give feedback.
All reactions