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,
|
table_id: TableId,
|
||||||
edges: Edges,
|
edges: Edges,
|
||||||
entities: Vec<ArchetypeEntity>,
|
entities: Vec<ArchetypeEntity>,
|
||||||
table_components: Box<[ComponentId]>,
|
|
||||||
sparse_set_components: Box<[ComponentId]>,
|
|
||||||
components: SparseSet<ComponentId, ArchetypeComponentInfo>,
|
components: SparseSet<ComponentId, ArchetypeComponentInfo>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -191,18 +189,15 @@ impl Archetype {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
id: ArchetypeId,
|
id: ArchetypeId,
|
||||||
table_id: TableId,
|
table_id: TableId,
|
||||||
table_components: Box<[ComponentId]>,
|
table_components: impl Iterator<Item = (ComponentId, ArchetypeComponentId)>,
|
||||||
sparse_set_components: Box<[ComponentId]>,
|
sparse_set_components: impl Iterator<Item = (ComponentId, ArchetypeComponentId)>,
|
||||||
table_archetype_components: Vec<ArchetypeComponentId>,
|
|
||||||
sparse_set_archetype_components: Vec<ArchetypeComponentId>,
|
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let mut components =
|
let (min_table, _) = table_components.size_hint();
|
||||||
SparseSet::with_capacity(table_components.len() + sparse_set_components.len());
|
let (min_sparse, _) = sparse_set_components.size_hint();
|
||||||
for (component_id, archetype_component_id) in
|
let mut components = SparseSet::with_capacity(min_table + min_sparse);
|
||||||
table_components.iter().zip(table_archetype_components)
|
for (component_id, archetype_component_id) in table_components {
|
||||||
{
|
|
||||||
components.insert(
|
components.insert(
|
||||||
*component_id,
|
component_id,
|
||||||
ArchetypeComponentInfo {
|
ArchetypeComponentInfo {
|
||||||
storage_type: StorageType::Table,
|
storage_type: StorageType::Table,
|
||||||
archetype_component_id,
|
archetype_component_id,
|
||||||
|
@ -210,12 +205,9 @@ impl Archetype {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (component_id, archetype_component_id) in sparse_set_components
|
for (component_id, archetype_component_id) in sparse_set_components {
|
||||||
.iter()
|
|
||||||
.zip(sparse_set_archetype_components)
|
|
||||||
{
|
|
||||||
components.insert(
|
components.insert(
|
||||||
*component_id,
|
component_id,
|
||||||
ArchetypeComponentInfo {
|
ArchetypeComponentInfo {
|
||||||
storage_type: StorageType::SparseSet,
|
storage_type: StorageType::SparseSet,
|
||||||
archetype_component_id,
|
archetype_component_id,
|
||||||
|
@ -225,10 +217,8 @@ impl Archetype {
|
||||||
Self {
|
Self {
|
||||||
id,
|
id,
|
||||||
table_id,
|
table_id,
|
||||||
entities: Vec::new(),
|
|
||||||
components,
|
components,
|
||||||
table_components,
|
entities: Default::default(),
|
||||||
sparse_set_components,
|
|
||||||
edges: Default::default(),
|
edges: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -249,13 +239,19 @@ impl Archetype {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn table_components(&self) -> &[ComponentId] {
|
pub fn table_components(&self) -> impl Iterator<Item = ComponentId> + '_ {
|
||||||
&self.table_components
|
self.components
|
||||||
|
.iter()
|
||||||
|
.filter(|(_, component)| component.storage_type == StorageType::Table)
|
||||||
|
.map(|(id, _)| *id)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn sparse_set_components(&self) -> &[ComponentId] {
|
pub fn sparse_set_components(&self) -> impl Iterator<Item = ComponentId> + '_ {
|
||||||
&self.sparse_set_components
|
self.components
|
||||||
|
.iter()
|
||||||
|
.filter(|(_, component)| component.storage_type == StorageType::SparseSet)
|
||||||
|
.map(|(id, _)| *id)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -484,38 +480,33 @@ impl Archetypes {
|
||||||
table_components: Vec<ComponentId>,
|
table_components: Vec<ComponentId>,
|
||||||
sparse_set_components: Vec<ComponentId>,
|
sparse_set_components: Vec<ComponentId>,
|
||||||
) -> ArchetypeId {
|
) -> ArchetypeId {
|
||||||
let table_components = table_components.into_boxed_slice();
|
|
||||||
let sparse_set_components = sparse_set_components.into_boxed_slice();
|
|
||||||
let archetype_identity = ArchetypeIdentity {
|
let archetype_identity = ArchetypeIdentity {
|
||||||
sparse_set_components: sparse_set_components.clone(),
|
sparse_set_components: sparse_set_components.clone().into_boxed_slice(),
|
||||||
table_components: table_components.clone(),
|
table_components: table_components.clone().into_boxed_slice(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let archetypes = &mut self.archetypes;
|
let archetypes = &mut self.archetypes;
|
||||||
let archetype_component_count = &mut self.archetype_component_count;
|
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
|
*self
|
||||||
.archetype_ids
|
.archetype_ids
|
||||||
.entry(archetype_identity)
|
.entry(archetype_identity)
|
||||||
.or_insert_with(move || {
|
.or_insert_with(move || {
|
||||||
let id = ArchetypeId(archetypes.len());
|
let id = ArchetypeId(archetypes.len());
|
||||||
let table_archetype_components = (0..table_components.len())
|
let table_start = *archetype_component_count;
|
||||||
.map(|_| next_archetype_component_id())
|
*archetype_component_count += table_components.len();
|
||||||
.collect();
|
let table_archetype_components =
|
||||||
let sparse_set_archetype_components = (0..sparse_set_components.len())
|
(table_start..*archetype_component_count).map(ArchetypeComponentId);
|
||||||
.map(|_| next_archetype_component_id())
|
let sparse_start = *archetype_component_count;
|
||||||
.collect();
|
*archetype_component_count += sparse_set_components.len();
|
||||||
|
let sparse_set_archetype_components =
|
||||||
|
(sparse_start..*archetype_component_count).map(ArchetypeComponentId);
|
||||||
archetypes.push(Archetype::new(
|
archetypes.push(Archetype::new(
|
||||||
id,
|
id,
|
||||||
table_id,
|
table_id,
|
||||||
table_components,
|
table_components.into_iter().zip(table_archetype_components),
|
||||||
sparse_set_components,
|
sparse_set_components
|
||||||
table_archetype_components,
|
.into_iter()
|
||||||
sparse_set_archetype_components,
|
.zip(sparse_set_archetype_components),
|
||||||
));
|
));
|
||||||
id
|
id
|
||||||
})
|
})
|
||||||
|
|
|
@ -461,7 +461,7 @@ impl BundleInfo {
|
||||||
table_components = if new_table_components.is_empty() {
|
table_components = if new_table_components.is_empty() {
|
||||||
// if there are no new table components, we can keep using this table
|
// if there are no new table components, we can keep using this table
|
||||||
table_id = current_archetype.table_id();
|
table_id = current_archetype.table_id();
|
||||||
current_archetype.table_components().to_vec()
|
current_archetype.table_components().collect()
|
||||||
} else {
|
} else {
|
||||||
new_table_components.extend(current_archetype.table_components());
|
new_table_components.extend(current_archetype.table_components());
|
||||||
// sort to ignore order while hashing
|
// sort to ignore order while hashing
|
||||||
|
@ -477,7 +477,7 @@ impl BundleInfo {
|
||||||
};
|
};
|
||||||
|
|
||||||
sparse_set_components = if new_sparse_set_components.is_empty() {
|
sparse_set_components = if new_sparse_set_components.is_empty() {
|
||||||
current_archetype.sparse_set_components().to_vec()
|
current_archetype.sparse_set_components().collect()
|
||||||
} else {
|
} else {
|
||||||
new_sparse_set_components.extend(current_archetype.sparse_set_components());
|
new_sparse_set_components.extend(current_archetype.sparse_set_components());
|
||||||
// sort to ignore order while hashing
|
// sort to ignore order while hashing
|
||||||
|
|
|
@ -505,7 +505,7 @@ impl<'w> EntityMut<'w> {
|
||||||
table_row = remove_result.table_row;
|
table_row = remove_result.table_row;
|
||||||
|
|
||||||
for component_id in archetype.sparse_set_components() {
|
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);
|
sparse_set.remove(self.entity);
|
||||||
}
|
}
|
||||||
// SAFETY: table rows stored in archetypes always exist
|
// SAFETY: table rows stored in archetypes always exist
|
||||||
|
@ -843,8 +843,8 @@ unsafe fn remove_bundle_from_archetype(
|
||||||
// components are already sorted
|
// components are already sorted
|
||||||
removed_table_components.sort();
|
removed_table_components.sort();
|
||||||
removed_sparse_set_components.sort();
|
removed_sparse_set_components.sort();
|
||||||
next_table_components = current_archetype.table_components().to_vec();
|
next_table_components = current_archetype.table_components().collect();
|
||||||
next_sparse_set_components = current_archetype.sparse_set_components().to_vec();
|
next_sparse_set_components = current_archetype.sparse_set_components().collect();
|
||||||
sorted_remove(&mut next_table_components, &removed_table_components);
|
sorted_remove(&mut next_table_components, &removed_table_components);
|
||||||
sorted_remove(
|
sorted_remove(
|
||||||
&mut next_sparse_set_components,
|
&mut next_sparse_set_components,
|
||||||
|
|
Loading…
Reference in a new issue