Remove archetype_component_access from QueryState (#12474)
# Objective `QueryState::archetype_component_access` is only really ever used to extend `SystemMeta`'s. It can be removed to save some memory for every `Query` in an app. ## Solution * Remove it. * Have `new_archetype` pass in a `&mut Access<ArchetypeComponentId>` instead and pull it from `SystemMeta` directly. * Split `QueryState::new` from `QueryState::new_with_access` and a common `QueryState::new_uninitialized`. * Split `new_archetype` into an internal and public version. Call the internal version in `update_archetypes`. This should make it faster to construct new QueryStates, and by proxy lenses and joins as well. `matched_tables` also similarly is only used to deduplicate inserting into `matched_table_ids`. If we can find another efficient way to do so, it might also be worth removing. The [generated assembly](https://github.com/james7132/bevy_asm_tests/compare/main...remove-query-state-archetype-component-access#diff-496530101f0b16e495b7e9b77c0e906ae3068c8adb69ed36c92d5a1be5a9efbe) reflects this well, with all of the access related updates in `QueryState` being removed. --- ## Changelog Removed: `QueryState::archetype_component_access`. Changed: `QueryState::new_archetype` now takes a `&mut Access<ArchetypeComponentId>` argument, which will be updated with the new accesses. Changed: `QueryState::update_archetype_component_access` now takes a `&mut Access<ArchetypeComponentId>` argument, which will be updated with the new accesses. ## Migration Guide TODO
This commit is contained in:
parent
8327ce85d8
commit
eebf3d61ec
@ -31,7 +31,6 @@ pub struct QueryState<D: QueryData, F: QueryFilter = ()> {
|
||||
pub(crate) archetype_generation: ArchetypeGeneration,
|
||||
pub(crate) matched_tables: FixedBitSet,
|
||||
pub(crate) matched_archetypes: FixedBitSet,
|
||||
pub(crate) archetype_component_access: Access<ArchetypeComponentId>,
|
||||
pub(crate) component_access: FilteredAccess<ComponentId>,
|
||||
// NOTE: we maintain both a TableId bitset and a vec because iterating the vec is faster
|
||||
pub(crate) matched_table_ids: Vec<TableId>,
|
||||
@ -96,11 +95,6 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
||||
&*ptr::from_ref(self).cast::<QueryState<NewD, NewF>>()
|
||||
}
|
||||
|
||||
/// Returns the archetype components accessed by this query.
|
||||
pub fn archetype_component_access(&self) -> &Access<ArchetypeComponentId> {
|
||||
&self.archetype_component_access
|
||||
}
|
||||
|
||||
/// Returns the components accessed by this query.
|
||||
pub fn component_access(&self) -> &FilteredAccess<ComponentId> {
|
||||
&self.component_access
|
||||
@ -120,6 +114,31 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
||||
impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
||||
/// Creates a new [`QueryState`] from a given [`World`] and inherits the result of `world.id()`.
|
||||
pub fn new(world: &mut World) -> Self {
|
||||
let mut state = Self::new_uninitialized(world);
|
||||
state.update_archetypes(world);
|
||||
state
|
||||
}
|
||||
|
||||
/// Identical to `new`, but it populates the provided `access` with the matched results.
|
||||
pub(crate) fn new_with_access(
|
||||
world: &mut World,
|
||||
access: &mut Access<ArchetypeComponentId>,
|
||||
) -> Self {
|
||||
let mut state = Self::new_uninitialized(world);
|
||||
for archetype in world.archetypes.iter() {
|
||||
if state.new_archetype_internal(archetype) {
|
||||
state.update_archetype_component_access(archetype, access);
|
||||
}
|
||||
}
|
||||
state.archetype_generation = world.archetypes.generation();
|
||||
state
|
||||
}
|
||||
|
||||
/// Creates a new [`QueryState`] but does not populate it with the matched results from the World yet
|
||||
///
|
||||
/// `new_archetype` and it's variants must be called on all of the World's archetypes before the
|
||||
/// state can return valid query results.
|
||||
fn new_uninitialized(world: &mut World) -> Self {
|
||||
let fetch_state = D::init_state(world);
|
||||
let filter_state = F::init_state(world);
|
||||
|
||||
@ -136,7 +155,7 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
||||
// properly considered in a global "cross-query" context (both within systems and across systems).
|
||||
component_access.extend(&filter_component_access);
|
||||
|
||||
let mut state = Self {
|
||||
Self {
|
||||
world_id: world.id(),
|
||||
archetype_generation: ArchetypeGeneration::initial(),
|
||||
matched_table_ids: Vec::new(),
|
||||
@ -146,16 +165,13 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
||||
component_access,
|
||||
matched_tables: Default::default(),
|
||||
matched_archetypes: Default::default(),
|
||||
archetype_component_access: Default::default(),
|
||||
#[cfg(feature = "trace")]
|
||||
par_iter_span: bevy_utils::tracing::info_span!(
|
||||
"par_for_each",
|
||||
query = std::any::type_name::<D>(),
|
||||
filter = std::any::type_name::<F>(),
|
||||
),
|
||||
};
|
||||
state.update_archetypes(world);
|
||||
state
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new [`QueryState`] from a given [`QueryBuilder`] and inherits it's [`FilteredAccess`].
|
||||
@ -174,7 +190,6 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
||||
component_access: builder.access().clone(),
|
||||
matched_tables: Default::default(),
|
||||
matched_archetypes: Default::default(),
|
||||
archetype_component_access: Default::default(),
|
||||
#[cfg(feature = "trace")]
|
||||
par_iter_span: bevy_utils::tracing::info_span!(
|
||||
"par_for_each",
|
||||
@ -276,7 +291,7 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
||||
std::mem::replace(&mut self.archetype_generation, archetypes.generation());
|
||||
|
||||
for archetype in &archetypes[old_generation..] {
|
||||
self.new_archetype(archetype);
|
||||
self.new_archetype_internal(archetype);
|
||||
}
|
||||
}
|
||||
|
||||
@ -303,13 +318,23 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
||||
|
||||
/// Update the current [`QueryState`] with information from the provided [`Archetype`]
|
||||
/// (if applicable, i.e. if the archetype has any intersecting [`ComponentId`] with the current [`QueryState`]).
|
||||
pub fn new_archetype(&mut self, archetype: &Archetype) {
|
||||
///
|
||||
/// The passed in `access` will be updated with any new accesses introduced by the new archetype.
|
||||
pub fn new_archetype(
|
||||
&mut self,
|
||||
archetype: &Archetype,
|
||||
access: &mut Access<ArchetypeComponentId>,
|
||||
) {
|
||||
if self.new_archetype_internal(archetype) {
|
||||
self.update_archetype_component_access(archetype, access);
|
||||
}
|
||||
}
|
||||
|
||||
fn new_archetype_internal(&mut self, archetype: &Archetype) -> bool {
|
||||
if D::matches_component_set(&self.fetch_state, &|id| archetype.contains(id))
|
||||
&& F::matches_component_set(&self.filter_state, &|id| archetype.contains(id))
|
||||
&& self.matches_component_set(&|id| archetype.contains(id))
|
||||
{
|
||||
self.update_archetype_component_access(archetype);
|
||||
|
||||
let archetype_index = archetype.id().index();
|
||||
if !self.matched_archetypes.contains(archetype_index) {
|
||||
self.matched_archetypes.grow_and_insert(archetype_index);
|
||||
@ -320,6 +345,9 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
||||
self.matched_tables.grow_and_insert(table_index);
|
||||
self.matched_table_ids.push(archetype.table_id());
|
||||
}
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
@ -337,15 +365,21 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
||||
}
|
||||
|
||||
/// For the given `archetype`, adds any component accessed used by this query's underlying [`FilteredAccess`] to `access`.
|
||||
pub fn update_archetype_component_access(&mut self, archetype: &Archetype) {
|
||||
///
|
||||
/// The passed in `access` will be updated with any new accesses introduced by the new archetype.
|
||||
pub fn update_archetype_component_access(
|
||||
&mut self,
|
||||
archetype: &Archetype,
|
||||
access: &mut Access<ArchetypeComponentId>,
|
||||
) {
|
||||
self.component_access.access.reads().for_each(|id| {
|
||||
if let Some(id) = archetype.get_archetype_component_id(id) {
|
||||
self.archetype_component_access.add_read(id);
|
||||
access.add_read(id);
|
||||
}
|
||||
});
|
||||
self.component_access.access.writes().for_each(|id| {
|
||||
if let Some(id) = archetype.get_archetype_component_id(id) {
|
||||
self.archetype_component_access.add_write(id);
|
||||
access.add_write(id);
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -397,7 +431,6 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
||||
component_access: self.component_access.clone(),
|
||||
matched_tables: self.matched_tables.clone(),
|
||||
matched_archetypes: self.matched_archetypes.clone(),
|
||||
archetype_component_access: self.archetype_component_access.clone(),
|
||||
#[cfg(feature = "trace")]
|
||||
par_iter_span: bevy_utils::tracing::info_span!(
|
||||
"par_for_each",
|
||||
@ -505,7 +538,6 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
||||
component_access: joined_component_access,
|
||||
matched_tables,
|
||||
matched_archetypes,
|
||||
archetype_component_access: self.archetype_component_access.clone(),
|
||||
#[cfg(feature = "trace")]
|
||||
par_iter_span: bevy_utils::tracing::info_span!(
|
||||
"par_for_each",
|
||||
|
||||
@ -193,7 +193,7 @@ unsafe impl<D: QueryData + 'static, F: QueryFilter + 'static> SystemParam for Qu
|
||||
type Item<'w, 's> = Query<'w, 's, D, F>;
|
||||
|
||||
fn init_state(world: &mut World, system_meta: &mut SystemMeta) -> Self::State {
|
||||
let state = QueryState::new(world);
|
||||
let state = QueryState::new_with_access(world, &mut system_meta.archetype_component_access);
|
||||
assert_component_access_compatibility(
|
||||
&system_meta.name,
|
||||
std::any::type_name::<D>(),
|
||||
@ -205,17 +205,11 @@ unsafe impl<D: QueryData + 'static, F: QueryFilter + 'static> SystemParam for Qu
|
||||
system_meta
|
||||
.component_access_set
|
||||
.add(state.component_access.clone());
|
||||
system_meta
|
||||
.archetype_component_access
|
||||
.extend(&state.archetype_component_access);
|
||||
state
|
||||
}
|
||||
|
||||
fn new_archetype(state: &mut Self::State, archetype: &Archetype, system_meta: &mut SystemMeta) {
|
||||
state.new_archetype(archetype);
|
||||
system_meta
|
||||
.archetype_component_access
|
||||
.extend(&state.archetype_component_access);
|
||||
state.new_archetype(archetype, &mut system_meta.archetype_component_access);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
||||
Loading…
Reference in New Issue
Block a user