Skip to content

Commit

Permalink
Optimize observer unregistration (#15150)
Browse files Browse the repository at this point in the history
# Objective

Fixes #14980

## Solution

Only iterate over archetypes containing the component.

## Alternatives

Additionally, for each archetype, cache how many observers are watching
one of its components & use this to speed up the check for each affected
archetype ([implemented
here](55c89aa)).
Benchmarking showed this to lead only to a minor speedup.

## Testing

There's both already a test checking that observers don't run after
being despawned as well as a regression test for the bug that
necessitates the check this PR optimizes.
  • Loading branch information
SpecificProtagonist authored Sep 13, 2024
1 parent c454db8 commit f570f52
Show file tree
Hide file tree
Showing 2 changed files with 12 additions and 9 deletions.
2 changes: 1 addition & 1 deletion crates/bevy_ecs/src/archetype.rs
Original file line number Diff line number Diff line change
Expand Up @@ -766,7 +766,7 @@ pub struct Archetypes {
/// find the archetype id by the archetype's components
by_components: HashMap<ArchetypeComponents, ArchetypeId>,
/// find all the archetypes that contain a component
by_component: ComponentIndex,
pub(crate) by_component: ComponentIndex,
}

/// Metadata about how a component is stored in an [`Archetype`].
Expand Down
19 changes: 11 additions & 8 deletions crates/bevy_ecs/src/observer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -456,14 +456,17 @@ impl World {
if observers.map.is_empty() && observers.entity_map.is_empty() {
cache.component_observers.remove(component);
if let Some(flag) = Observers::is_archetype_cached(event_type) {
for archetype in &mut archetypes.archetypes {
if archetype.contains(*component) {
let no_longer_observed = archetype
.components()
.all(|id| !cache.component_observers.contains_key(&id));

if no_longer_observed {
archetype.flags.set(flag, false);
if let Some(by_component) = archetypes.by_component.get(component) {
for archetype in by_component.keys() {
let archetype = &mut archetypes.archetypes[archetype.index()];
if archetype.contains(*component) {
let no_longer_observed = archetype
.components()
.all(|id| !cache.component_observers.contains_key(&id));

if no_longer_observed {
archetype.flags.set(flag, false);
}
}
}
}
Expand Down

0 comments on commit f570f52

Please sign in to comment.