mirror of
https://github.com/bevyengine/bevy
synced 2024-11-22 20:53:53 +00:00
Remove redundant table and sparse set component IDs from Archetype (#4927)
# Objective Archetype is a deceptively large type in memory. It stores metadata about which components are in which storage in multiple locations, which is only used when creating new Archetypes while moving entities. ## Solution Remove the redundant `Box<[ComponentId]>`s and iterate over the sparse set of component metadata instead. Reduces Archetype's size by 4 usizes (32 bytes on 64-bit systems), as well as the additional allocations for holding these slices. It'd seem like there's a downside that the origin archetype has it's component metadata iterated over twice when creating a new archetype, but this change also removes the extra `Vec<ArchetypeComponentId>` allocations when creating a new archetype which may amortize out to a net gain here. This change likely negatively impacts creating new archetypes with a large number of components, but that's a cost mitigated by the fact that these archetypal relationships are cached in Edges and is incurred only once for each edge created. ## Additional Context There are several other in-flight PRs that shrink Archetype: - #4800 merges the entities and rows Vecs together (shaves off 24 bytes per archetype) - #4809 removes unique_components and moves it to it's own dedicated storage (shaves off 72 bytes per archetype) --- ## Changelog Changed: `Archetype::table_components` and `Archetype::sparse_set_components` return iterators instead of slices. `Archetype::new` requires iterators instead of parallel slices/vecs. ## Migration Guide Do I still need to do this? I really hope people were not relying on the public facing APIs changed here.
This commit is contained in:
parent
51aab032ed
commit
11c544c29a
3 changed files with 39 additions and 48 deletions
|
@ -182,8 +182,6 @@ pub struct Archetype {
|
|||
table_id: TableId,
|
||||
edges: Edges,
|
||||
entities: Vec<ArchetypeEntity>,
|
||||
table_components: Box<[ComponentId]>,
|
||||
sparse_set_components: Box<[ComponentId]>,
|
||||
components: SparseSet<ComponentId, ArchetypeComponentInfo>,
|
||||
}
|
||||
|
||||
|
@ -191,18 +189,15 @@ impl Archetype {
|
|||
pub fn new(
|
||||
id: ArchetypeId,
|
||||
table_id: TableId,
|
||||
table_components: Box<[ComponentId]>,
|
||||
sparse_set_components: Box<[ComponentId]>,
|
||||
table_archetype_components: Vec<ArchetypeComponentId>,
|
||||
sparse_set_archetype_components: Vec<ArchetypeComponentId>,
|
||||
table_components: impl Iterator<Item = (ComponentId, ArchetypeComponentId)>,
|
||||
sparse_set_components: impl Iterator<Item = (ComponentId, ArchetypeComponentId)>,
|
||||
) -> Self {
|
||||
let mut components =
|
||||
SparseSet::with_capacity(table_components.len() + sparse_set_components.len());
|
||||
for (component_id, archetype_component_id) in
|
||||
table_components.iter().zip(table_archetype_components)
|
||||
{
|
||||
let (min_table, _) = table_components.size_hint();
|
||||
let (min_sparse, _) = sparse_set_components.size_hint();
|
||||
let mut components = SparseSet::with_capacity(min_table + min_sparse);
|
||||
for (component_id, archetype_component_id) in table_components {
|
||||
components.insert(
|
||||
*component_id,
|
||||
component_id,
|
||||
ArchetypeComponentInfo {
|
||||
storage_type: StorageType::Table,
|
||||
archetype_component_id,
|
||||
|
@ -210,12 +205,9 @@ impl Archetype {
|
|||
);
|
||||
}
|
||||
|
||||
for (component_id, archetype_component_id) in sparse_set_components
|
||||
.iter()
|
||||
.zip(sparse_set_archetype_components)
|
||||
{
|
||||
for (component_id, archetype_component_id) in sparse_set_components {
|
||||
components.insert(
|
||||
*component_id,
|
||||
component_id,
|
||||
ArchetypeComponentInfo {
|
||||
storage_type: StorageType::SparseSet,
|
||||
archetype_component_id,
|
||||
|
@ -225,10 +217,8 @@ impl Archetype {
|
|||
Self {
|
||||
id,
|
||||
table_id,
|
||||
entities: Vec::new(),
|
||||
components,
|
||||
table_components,
|
||||
sparse_set_components,
|
||||
entities: Default::default(),
|
||||
edges: Default::default(),
|
||||
}
|
||||
}
|
||||
|
@ -249,13 +239,19 @@ impl Archetype {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub fn table_components(&self) -> &[ComponentId] {
|
||||
&self.table_components
|
||||
pub fn table_components(&self) -> impl Iterator<Item = ComponentId> + '_ {
|
||||
self.components
|
||||
.iter()
|
||||
.filter(|(_, component)| component.storage_type == StorageType::Table)
|
||||
.map(|(id, _)| *id)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn sparse_set_components(&self) -> &[ComponentId] {
|
||||
&self.sparse_set_components
|
||||
pub fn sparse_set_components(&self) -> impl Iterator<Item = ComponentId> + '_ {
|
||||
self.components
|
||||
.iter()
|
||||
.filter(|(_, component)| component.storage_type == StorageType::SparseSet)
|
||||
.map(|(id, _)| *id)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -484,38 +480,33 @@ impl Archetypes {
|
|||
table_components: Vec<ComponentId>,
|
||||
sparse_set_components: Vec<ComponentId>,
|
||||
) -> ArchetypeId {
|
||||
let table_components = table_components.into_boxed_slice();
|
||||
let sparse_set_components = sparse_set_components.into_boxed_slice();
|
||||
let archetype_identity = ArchetypeIdentity {
|
||||
sparse_set_components: sparse_set_components.clone(),
|
||||
table_components: table_components.clone(),
|
||||
sparse_set_components: sparse_set_components.clone().into_boxed_slice(),
|
||||
table_components: table_components.clone().into_boxed_slice(),
|
||||
};
|
||||
|
||||
let archetypes = &mut self.archetypes;
|
||||
let archetype_component_count = &mut self.archetype_component_count;
|
||||
let mut next_archetype_component_id = move || {
|
||||
let id = ArchetypeComponentId(*archetype_component_count);
|
||||
*archetype_component_count += 1;
|
||||
id
|
||||
};
|
||||
*self
|
||||
.archetype_ids
|
||||
.entry(archetype_identity)
|
||||
.or_insert_with(move || {
|
||||
let id = ArchetypeId(archetypes.len());
|
||||
let table_archetype_components = (0..table_components.len())
|
||||
.map(|_| next_archetype_component_id())
|
||||
.collect();
|
||||
let sparse_set_archetype_components = (0..sparse_set_components.len())
|
||||
.map(|_| next_archetype_component_id())
|
||||
.collect();
|
||||
let table_start = *archetype_component_count;
|
||||
*archetype_component_count += table_components.len();
|
||||
let table_archetype_components =
|
||||
(table_start..*archetype_component_count).map(ArchetypeComponentId);
|
||||
let sparse_start = *archetype_component_count;
|
||||
*archetype_component_count += sparse_set_components.len();
|
||||
let sparse_set_archetype_components =
|
||||
(sparse_start..*archetype_component_count).map(ArchetypeComponentId);
|
||||
archetypes.push(Archetype::new(
|
||||
id,
|
||||
table_id,
|
||||
table_components,
|
||||
sparse_set_components,
|
||||
table_archetype_components,
|
||||
sparse_set_archetype_components,
|
||||
table_components.into_iter().zip(table_archetype_components),
|
||||
sparse_set_components
|
||||
.into_iter()
|
||||
.zip(sparse_set_archetype_components),
|
||||
));
|
||||
id
|
||||
})
|
||||
|
|
|
@ -461,7 +461,7 @@ impl BundleInfo {
|
|||
table_components = if new_table_components.is_empty() {
|
||||
// if there are no new table components, we can keep using this table
|
||||
table_id = current_archetype.table_id();
|
||||
current_archetype.table_components().to_vec()
|
||||
current_archetype.table_components().collect()
|
||||
} else {
|
||||
new_table_components.extend(current_archetype.table_components());
|
||||
// sort to ignore order while hashing
|
||||
|
@ -477,7 +477,7 @@ impl BundleInfo {
|
|||
};
|
||||
|
||||
sparse_set_components = if new_sparse_set_components.is_empty() {
|
||||
current_archetype.sparse_set_components().to_vec()
|
||||
current_archetype.sparse_set_components().collect()
|
||||
} else {
|
||||
new_sparse_set_components.extend(current_archetype.sparse_set_components());
|
||||
// sort to ignore order while hashing
|
||||
|
|
|
@ -505,7 +505,7 @@ impl<'w> EntityMut<'w> {
|
|||
table_row = remove_result.table_row;
|
||||
|
||||
for component_id in archetype.sparse_set_components() {
|
||||
let sparse_set = world.storages.sparse_sets.get_mut(*component_id).unwrap();
|
||||
let sparse_set = world.storages.sparse_sets.get_mut(component_id).unwrap();
|
||||
sparse_set.remove(self.entity);
|
||||
}
|
||||
// SAFETY: table rows stored in archetypes always exist
|
||||
|
@ -843,8 +843,8 @@ unsafe fn remove_bundle_from_archetype(
|
|||
// components are already sorted
|
||||
removed_table_components.sort();
|
||||
removed_sparse_set_components.sort();
|
||||
next_table_components = current_archetype.table_components().to_vec();
|
||||
next_sparse_set_components = current_archetype.sparse_set_components().to_vec();
|
||||
next_table_components = current_archetype.table_components().collect();
|
||||
next_sparse_set_components = current_archetype.sparse_set_components().collect();
|
||||
sorted_remove(&mut next_table_components, &removed_table_components);
|
||||
sorted_remove(
|
||||
&mut next_sparse_set_components,
|
||||
|
|
Loading…
Reference in a new issue