update archetypes if needed before running system in SingleThreadedExecutor (#1586)
fixes #1585 I copied most of the logic from the `ParallelSystemExecutor` impl, simplifying it a little as systems can't run in parallel
This commit is contained in:
		
							parent
							
								
									2a3a32b66f
								
							
						
					
					
						commit
						dabf419095
					
				@ -1,4 +1,4 @@
 | 
				
			|||||||
use crate::{schedule::ParallelSystemContainer, world::World};
 | 
					use crate::{archetype::ArchetypeGeneration, schedule::ParallelSystemContainer, world::World};
 | 
				
			||||||
use downcast_rs::{impl_downcast, Downcast};
 | 
					use downcast_rs::{impl_downcast, Downcast};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub trait ParallelSystemExecutor: Downcast + Send + Sync {
 | 
					pub trait ParallelSystemExecutor: Downcast + Send + Sync {
 | 
				
			||||||
@ -10,13 +10,25 @@ pub trait ParallelSystemExecutor: Downcast + Send + Sync {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
impl_downcast!(ParallelSystemExecutor);
 | 
					impl_downcast!(ParallelSystemExecutor);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Default)]
 | 
					pub struct SingleThreadedExecutor {
 | 
				
			||||||
pub struct SingleThreadedExecutor;
 | 
					    /// Last archetypes generation observed by parallel systems.
 | 
				
			||||||
 | 
					    archetype_generation: ArchetypeGeneration,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Default for SingleThreadedExecutor {
 | 
				
			||||||
 | 
					    fn default() -> Self {
 | 
				
			||||||
 | 
					        Self {
 | 
				
			||||||
 | 
					            // MAX ensures access information will be initialized on first run.
 | 
				
			||||||
 | 
					            archetype_generation: ArchetypeGeneration::new(usize::MAX),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
impl ParallelSystemExecutor for SingleThreadedExecutor {
 | 
					impl ParallelSystemExecutor for SingleThreadedExecutor {
 | 
				
			||||||
    fn rebuild_cached_data(&mut self, _: &[ParallelSystemContainer]) {}
 | 
					    fn rebuild_cached_data(&mut self, _: &[ParallelSystemContainer]) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn run_systems(&mut self, systems: &mut [ParallelSystemContainer], world: &mut World) {
 | 
					    fn run_systems(&mut self, systems: &mut [ParallelSystemContainer], world: &mut World) {
 | 
				
			||||||
 | 
					        self.update_archetypes(systems, world);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for system in systems {
 | 
					        for system in systems {
 | 
				
			||||||
            if system.should_run() {
 | 
					            if system.should_run() {
 | 
				
			||||||
                system.system_mut().run((), world);
 | 
					                system.system_mut().run((), world);
 | 
				
			||||||
@ -24,3 +36,30 @@ impl ParallelSystemExecutor for SingleThreadedExecutor {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl SingleThreadedExecutor {
 | 
				
			||||||
 | 
					    /// Calls system.new_archetype() for each archetype added since the last call to [update_archetypes] and
 | 
				
			||||||
 | 
					    /// updates cached archetype_component_access.
 | 
				
			||||||
 | 
					    fn update_archetypes(&mut self, systems: &mut [ParallelSystemContainer], 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() {
 | 
				
			||||||
 | 
					            for container in systems.iter_mut() {
 | 
				
			||||||
 | 
					                let system = container.system_mut();
 | 
				
			||||||
 | 
					                system.new_archetype(archetype);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.archetype_generation = new_generation;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1528,4 +1528,49 @@ mod tests {
 | 
				
			|||||||
        stage.run(&mut world_a);
 | 
					        stage.run(&mut world_a);
 | 
				
			||||||
        stage.run(&mut world_b);
 | 
					        stage.run(&mut world_b);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn archetype_update_single_executor() {
 | 
				
			||||||
 | 
					        fn query_count_system(
 | 
				
			||||||
 | 
					            mut entity_count: ResMut<usize>,
 | 
				
			||||||
 | 
					            query: Query<crate::entity::Entity>,
 | 
				
			||||||
 | 
					        ) {
 | 
				
			||||||
 | 
					            *entity_count = query.iter().count();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let mut world = World::new();
 | 
				
			||||||
 | 
					        world.insert_resource(0_usize);
 | 
				
			||||||
 | 
					        let mut stage = SystemStage::single(query_count_system.system());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let entity = world.spawn().insert_bundle(()).id();
 | 
				
			||||||
 | 
					        stage.run(&mut world);
 | 
				
			||||||
 | 
					        assert_eq!(*world.get_resource::<usize>().unwrap(), 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        world.get_entity_mut(entity).unwrap().insert(1);
 | 
				
			||||||
 | 
					        stage.run(&mut world);
 | 
				
			||||||
 | 
					        assert_eq!(*world.get_resource::<usize>().unwrap(), 1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn archetype_update_parallel_executor() {
 | 
				
			||||||
 | 
					        fn query_count_system(
 | 
				
			||||||
 | 
					            mut entity_count: ResMut<usize>,
 | 
				
			||||||
 | 
					            query: Query<crate::entity::Entity>,
 | 
				
			||||||
 | 
					        ) {
 | 
				
			||||||
 | 
					            *entity_count = query.iter().count();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let mut world = World::new();
 | 
				
			||||||
 | 
					        world.insert_resource(0_usize);
 | 
				
			||||||
 | 
					        let mut stage = SystemStage::parallel();
 | 
				
			||||||
 | 
					        stage.add_system(query_count_system.system());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let entity = world.spawn().insert_bundle(()).id();
 | 
				
			||||||
 | 
					        stage.run(&mut world);
 | 
				
			||||||
 | 
					        assert_eq!(*world.get_resource::<usize>().unwrap(), 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        world.get_entity_mut(entity).unwrap().insert(1);
 | 
				
			||||||
 | 
					        stage.run(&mut world);
 | 
				
			||||||
 | 
					        assert_eq!(*world.get_resource::<usize>().unwrap(), 1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user