From d7b8364ce91e3711d86b79edcad9b631402e647b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Mockers?= Date: Sun, 16 May 2021 01:12:08 +0200 Subject: [PATCH 1/3] update archetypes for run criterias --- .../src/schedule/executor_parallel.rs | 6 +- crates/bevy_ecs/src/schedule/run_criteria.rs | 49 +++++++++++- crates/bevy_ecs/src/schedule/stage.rs | 75 +++++++++++++++++++ 3 files changed, 124 insertions(+), 6 deletions(-) diff --git a/crates/bevy_ecs/src/schedule/executor_parallel.rs b/crates/bevy_ecs/src/schedule/executor_parallel.rs index af989ef9eecc1..1a4baf38fbb34 100644 --- a/crates/bevy_ecs/src/schedule/executor_parallel.rs +++ b/crates/bevy_ecs/src/schedule/executor_parallel.rs @@ -301,11 +301,7 @@ impl ParallelExecutor { #[cfg(test)] fn emit_event(&self, event: SchedulingEvent) { - self.events_sender - .as_ref() - .unwrap() - .try_send(event) - .unwrap(); + let _ = self.events_sender.as_ref().unwrap().try_send(event); } } diff --git a/crates/bevy_ecs/src/schedule/run_criteria.rs b/crates/bevy_ecs/src/schedule/run_criteria.rs index 5ea8fab4d1e5f..2b9ea3847dd22 100644 --- a/crates/bevy_ecs/src/schedule/run_criteria.rs +++ b/crates/bevy_ecs/src/schedule/run_criteria.rs @@ -1,5 +1,5 @@ use crate::{ - archetype::{Archetype, ArchetypeComponentId}, + archetype::{Archetype, ArchetypeComponentId, ArchetypeGeneration}, component::ComponentId, query::Access, schedule::{BoxedRunCriteriaLabel, GraphNode, RunCriteriaLabel}, @@ -47,6 +47,7 @@ pub enum ShouldRun { pub(crate) struct BoxedRunCriteria { criteria_system: Option>, initialized: bool, + archetype_generation: ArchetypeGeneration, } impl Default for BoxedRunCriteria { @@ -54,6 +55,8 @@ impl Default for BoxedRunCriteria { Self { criteria_system: None, initialized: false, + // MAX ensures access information will be initialized on first run. + archetype_generation: ArchetypeGeneration::new(usize::MAX), } } } @@ -70,6 +73,21 @@ impl BoxedRunCriteria { run_criteria.initialize(world); self.initialized = true; } + let archetypes = world.archetypes(); + let old_generation = self.archetype_generation; + let new_generation = archetypes.generation(); + if old_generation != new_generation { + let archetype_index_range = if old_generation.value() == usize::MAX { + 0..archetypes.len() + } else { + old_generation.value()..archetypes.len() + }; + for archetype in archetypes.archetypes[archetype_index_range].iter() { + run_criteria.new_archetype(archetype); + } + + self.archetype_generation = new_generation; + } let should_run = run_criteria.run((), world); run_criteria.apply_buffers(world); should_run @@ -93,6 +111,7 @@ pub(crate) struct RunCriteriaContainer { pub label: Option, pub before: Vec, pub after: Vec, + archetype_generation: ArchetypeGeneration, } impl RunCriteriaContainer { @@ -106,6 +125,8 @@ impl RunCriteriaContainer { label: descriptor.label, before: descriptor.before, after: descriptor.after, + // MAX ensures access information will be initialized on first run. + archetype_generation: ArchetypeGeneration::new(usize::MAX), } } @@ -122,6 +143,32 @@ impl RunCriteriaContainer { RunCriteriaInner::Piped { system, .. } => system.initialize(world), } } + + pub fn update_archetypes(&mut self, world: &World) { + let archetypes = world.archetypes(); + let old_generation = self.archetype_generation; + let new_generation = archetypes.generation(); + if old_generation == new_generation { + return; + } + let archetype_index_range = if old_generation.value() == usize::MAX { + 0..archetypes.len() + } else { + old_generation.value()..archetypes.len() + }; + for archetype in archetypes.archetypes[archetype_index_range].iter() { + match &mut self.inner { + RunCriteriaInner::Single(system) => { + system.new_archetype(archetype); + } + + RunCriteriaInner::Piped { system, .. } => { + system.new_archetype(archetype); + } + } + } + self.archetype_generation = new_generation; + } } impl GraphNode for RunCriteriaContainer { diff --git a/crates/bevy_ecs/src/schedule/stage.rs b/crates/bevy_ecs/src/schedule/stage.rs index 9cd49f828c61f..cb264c66e980d 100644 --- a/crates/bevy_ecs/src/schedule/stage.rs +++ b/crates/bevy_ecs/src/schedule/stage.rs @@ -775,6 +775,7 @@ impl Stage for SystemStage { for index in 0..self.run_criteria.len() { let (run_criteria, tail) = self.run_criteria.split_at_mut(index); let mut criteria = &mut tail[0]; + criteria.update_archetypes(world); match &mut criteria.inner { RunCriteriaInner::Single(system) => criteria.should_run = system.run((), world), RunCriteriaInner::Piped { @@ -848,6 +849,7 @@ impl Stage for SystemStage { for index in 0..run_criteria.len() { let (run_criteria, tail) = run_criteria.split_at_mut(index); let criteria = &mut tail[0]; + criteria.update_archetypes(world); match criteria.should_run { ShouldRun::No => (), ShouldRun::Yes => criteria.should_run = ShouldRun::No, @@ -2094,4 +2096,77 @@ mod tests { ); } } + + #[test] + fn run_criteria_with_query() { + struct Foo; + + fn even_number_of_entities_critiera(query: Query<&Foo>) -> ShouldRun { + if query.iter().len() % 2 == 0 { + ShouldRun::Yes + } else { + ShouldRun::No + } + } + + fn spawn_entity(mut commands: crate::prelude::Commands) { + commands.spawn().insert(Foo); + } + + fn count_entities(query: Query<&Foo>, mut res: ResMut>) { + res.push(query.iter().len()); + } + + let mut world = World::new(); + world.insert_resource(Vec::::new()); + let mut stage = SystemStage::parallel() + .with_system(spawn_entity.system().label("spawn")) + .with_system_set( + SystemSet::new() + .with_run_criteria(even_number_of_entities_critiera.system()) + .with_system(count_entities.system().before("spawn")), + ); + stage.run(&mut world); + stage.run(&mut world); + stage.run(&mut world); + stage.run(&mut world); + assert_eq!(*world.get_resource::>().unwrap(), vec![0, 2]); + } + + #[test] + fn stage_run_criteria_with_query() { + struct Foo; + + fn even_number_of_entities_critiera(query: Query<&Foo>) -> ShouldRun { + if query.iter().len() % 2 == 0 { + ShouldRun::Yes + } else { + ShouldRun::No + } + } + + fn spawn_entity(mut commands: crate::prelude::Commands) { + commands.spawn().insert(Foo); + } + + fn count_entities(query: Query<&Foo>, mut res: ResMut>) { + res.push(query.iter().len()); + } + + let mut world = World::new(); + world.insert_resource(Vec::::new()); + let mut stage_spawn = SystemStage::parallel().with_system(spawn_entity.system()); + let mut stage_count = SystemStage::parallel() + .with_run_criteria(even_number_of_entities_critiera.system()) + .with_system(count_entities.system()); + stage_count.run(&mut world); + stage_spawn.run(&mut world); + stage_count.run(&mut world); + stage_spawn.run(&mut world); + stage_count.run(&mut world); + stage_spawn.run(&mut world); + stage_count.run(&mut world); + stage_spawn.run(&mut world); + assert_eq!(*world.get_resource::>().unwrap(), vec![0, 2]); + } } From ea6801d529eaf51b2edba2a77103eeb8296d9936 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Mockers?= Date: Tue, 18 May 2021 22:12:02 +0200 Subject: [PATCH 2/3] update for generation change --- crates/bevy_ecs/src/schedule/run_criteria.rs | 33 ++++++-------------- 1 file changed, 9 insertions(+), 24 deletions(-) diff --git a/crates/bevy_ecs/src/schedule/run_criteria.rs b/crates/bevy_ecs/src/schedule/run_criteria.rs index 2b9ea3847dd22..9d31fe1a55b4c 100644 --- a/crates/bevy_ecs/src/schedule/run_criteria.rs +++ b/crates/bevy_ecs/src/schedule/run_criteria.rs @@ -55,8 +55,7 @@ impl Default for BoxedRunCriteria { Self { criteria_system: None, initialized: false, - // MAX ensures access information will be initialized on first run. - archetype_generation: ArchetypeGeneration::new(usize::MAX), + archetype_generation: ArchetypeGeneration::initial(), } } } @@ -74,20 +73,14 @@ impl BoxedRunCriteria { self.initialized = true; } let archetypes = world.archetypes(); - let old_generation = self.archetype_generation; let new_generation = archetypes.generation(); - if old_generation != new_generation { - let archetype_index_range = if old_generation.value() == usize::MAX { - 0..archetypes.len() - } else { - old_generation.value()..archetypes.len() - }; - for archetype in archetypes.archetypes[archetype_index_range].iter() { - run_criteria.new_archetype(archetype); - } + let old_generation = std::mem::replace(&mut self.archetype_generation, new_generation); + let archetype_index_range = old_generation.value()..new_generation.value(); - self.archetype_generation = new_generation; + for archetype in archetypes.archetypes[archetype_index_range].iter() { + run_criteria.new_archetype(archetype); } + let should_run = run_criteria.run((), world); run_criteria.apply_buffers(world); should_run @@ -125,8 +118,7 @@ impl RunCriteriaContainer { label: descriptor.label, before: descriptor.before, after: descriptor.after, - // MAX ensures access information will be initialized on first run. - archetype_generation: ArchetypeGeneration::new(usize::MAX), + archetype_generation: ArchetypeGeneration::initial(), } } @@ -146,16 +138,9 @@ impl RunCriteriaContainer { pub fn update_archetypes(&mut self, world: &World) { let archetypes = world.archetypes(); - let old_generation = self.archetype_generation; let new_generation = archetypes.generation(); - if old_generation == new_generation { - return; - } - let archetype_index_range = if old_generation.value() == usize::MAX { - 0..archetypes.len() - } else { - old_generation.value()..archetypes.len() - }; + let old_generation = std::mem::replace(&mut self.archetype_generation, new_generation); + let archetype_index_range = old_generation.value()..new_generation.value(); for archetype in archetypes.archetypes[archetype_index_range].iter() { match &mut self.inner { RunCriteriaInner::Single(system) => { From 632851292069df6cec4e6e1e06975b309c3950a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Mockers?= Date: Tue, 13 Jul 2021 00:18:44 +0200 Subject: [PATCH 3/3] add archetype update for exclusive systems --- .../bevy_ecs/src/system/exclusive_system.rs | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/crates/bevy_ecs/src/system/exclusive_system.rs b/crates/bevy_ecs/src/system/exclusive_system.rs index ea7c6d8c1ada9..10364375f71ef 100644 --- a/crates/bevy_ecs/src/system/exclusive_system.rs +++ b/crates/bevy_ecs/src/system/exclusive_system.rs @@ -1,4 +1,5 @@ use crate::{ + archetype::ArchetypeGeneration, system::{check_system_change_tick, BoxedSystem, IntoSystem, SystemId}, world::World, }; @@ -74,6 +75,7 @@ where pub struct ExclusiveSystemCoerced { system: BoxedSystem<(), ()>, + archetype_generation: ArchetypeGeneration, } impl ExclusiveSystem for ExclusiveSystemCoerced { @@ -86,6 +88,15 @@ impl ExclusiveSystem for ExclusiveSystemCoerced { } fn run(&mut self, world: &mut World) { + let archetypes = world.archetypes(); + let new_generation = archetypes.generation(); + let old_generation = std::mem::replace(&mut self.archetype_generation, new_generation); + let archetype_index_range = old_generation.value()..new_generation.value(); + + for archetype in archetypes.archetypes[archetype_index_range].iter() { + self.system.new_archetype(archetype); + } + self.system.run((), world); self.system.apply_buffers(world); } @@ -106,6 +117,7 @@ where fn exclusive_system(self) -> ExclusiveSystemCoerced { ExclusiveSystemCoerced { system: Box::new(self.system()), + archetype_generation: ArchetypeGeneration::initial(), } } } @@ -148,4 +160,26 @@ mod tests { stage.run(&mut world); assert_eq!(*world.get_resource::().unwrap(), 1); } + + #[test] + fn update_archetype_for_exclusive_system_coerced() { + struct Foo; + + fn spawn_entity(mut commands: crate::prelude::Commands) { + commands.spawn().insert(Foo); + } + + fn count_entities(query: Query<&Foo>, mut res: ResMut>) { + res.push(query.iter().len()); + } + + let mut world = World::new(); + world.insert_resource(Vec::::new()); + let mut stage = SystemStage::parallel() + .with_system(spawn_entity.system()) + .with_system(count_entities.exclusive_system()); + stage.run(&mut world); + stage.run(&mut world); + assert_eq!(*world.get_resource::>().unwrap(), vec![0, 1]); + } }