Skip to content

Commit

Permalink
update archetypes for run criterias
Browse files Browse the repository at this point in the history
  • Loading branch information
mockersf committed May 15, 2021
1 parent 883abbb commit a0803a4
Show file tree
Hide file tree
Showing 3 changed files with 124 additions and 6 deletions.
6 changes: 1 addition & 5 deletions crates/bevy_ecs/src/schedule/executor_parallel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -311,11 +311,7 @@ impl ParallelExecutor {

#[cfg(test)]
fn emit_event(&self, event: SchedulingEvent) {
self.events_sender
.as_ref()
.unwrap()
.try_send(event)
.unwrap();
self.events_sender.as_ref().unwrap().try_send(event);
}
}

Expand Down
49 changes: 48 additions & 1 deletion crates/bevy_ecs/src/schedule/run_criteria.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::{
archetype::{Archetype, ArchetypeComponentId},
archetype::{Archetype, ArchetypeComponentId, ArchetypeGeneration},
component::ComponentId,
query::Access,
schedule::{BoxedRunCriteriaLabel, GraphNode, RunCriteriaLabel},
Expand Down Expand Up @@ -47,13 +47,16 @@ pub enum ShouldRun {
pub(crate) struct BoxedRunCriteria {
criteria_system: Option<BoxedSystem<(), ShouldRun>>,
initialized: bool,
archetype_generation: ArchetypeGeneration,
}

impl Default for BoxedRunCriteria {
fn default() -> Self {
Self {
criteria_system: None,
initialized: false,
// MAX ensures access information will be initialized on first run.
archetype_generation: ArchetypeGeneration::new(usize::MAX),
}
}
}
Expand All @@ -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
Expand All @@ -93,6 +111,7 @@ pub(crate) struct RunCriteriaContainer {
pub label: Option<BoxedRunCriteriaLabel>,
pub before: Vec<BoxedRunCriteriaLabel>,
pub after: Vec<BoxedRunCriteriaLabel>,
archetype_generation: ArchetypeGeneration,
}

impl RunCriteriaContainer {
Expand All @@ -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),
}
}

Expand All @@ -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<BoxedRunCriteriaLabel> for RunCriteriaContainer {
Expand Down
75 changes: 75 additions & 0 deletions crates/bevy_ecs/src/schedule/stage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -777,6 +777,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 {
Expand Down Expand Up @@ -850,6 +851,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,
Expand Down Expand Up @@ -2096,4 +2098,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<Vec<usize>>) {
res.push(query.iter().len());
}

let mut world = World::new();
world.insert_resource(Vec::<usize>::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::<Vec<usize>>().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<Vec<usize>>) {
res.push(query.iter().len());
}

let mut world = World::new();
world.insert_resource(Vec::<usize>::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::<Vec<usize>>().unwrap(), vec![0, 2]);
}
}

0 comments on commit a0803a4

Please sign in to comment.