diff --git a/crates/bevy_ecs/src/into_system.rs b/crates/bevy_ecs/src/into_system.rs index 754009d07d..e09c8c11b5 100644 --- a/crates/bevy_ecs/src/into_system.rs +++ b/crates/bevy_ecs/src/into_system.rs @@ -1,7 +1,6 @@ use crate::{ - executor::ArchetypeAccess, resource_query::{FetchResource, ResourceQuery, UnsafeClone}, - system::{System, SystemId, ThreadLocalExecution}, + system::{ArchetypeAccess, System, SystemId, ThreadLocalExecution}, Commands, Resources, }; use core::marker::PhantomData; @@ -27,7 +26,8 @@ where pub set_archetype_access: SetArchetypeAccess, } -impl System for SystemFn +impl System + for SystemFn where F: FnMut(&World, &Resources) + Send + Sync, ThreadLocalF: FnMut(&mut World, &mut Resources) + Send + Sync, @@ -294,7 +294,10 @@ pub trait IntoThreadLocalSystem { fn thread_local_system(self) -> Box; } -impl IntoThreadLocalSystem for F where F: ThreadLocalSystemFn { +impl IntoThreadLocalSystem for F +where + F: ThreadLocalSystemFn, +{ fn thread_local_system(mut self) -> Box { Box::new(SystemFn { thread_local_func: move |world, resources| { @@ -322,4 +325,4 @@ where fn run(&mut self, world: &mut World, resources: &mut Resources) { self(world, resources); } -} \ No newline at end of file +} diff --git a/crates/bevy_ecs/src/lib.rs b/crates/bevy_ecs/src/lib.rs index 01e30efdf8..4aad2160d0 100644 --- a/crates/bevy_ecs/src/lib.rs +++ b/crates/bevy_ecs/src/lib.rs @@ -1,7 +1,7 @@ pub use hecs::{Query as HecsQuery, *}; mod commands; -mod executor; +mod parallel_executor; mod into_system; #[cfg(feature = "profiler")] pub mod profiler; @@ -16,6 +16,6 @@ pub use into_system::{IntoForEachSystem, IntoQuerySystem, IntoThreadLocalSystem, pub use resource_query::{FetchResource, Local, Res, ResMut, ResourceQuery}; pub use resources::{FromResources, Resource, Resources}; pub use schedule::Schedule; -pub use executor::Executor; +pub use parallel_executor::ParallelExecutor; pub use system::{System, SystemId}; pub use world_builder::{WorldBuilder, WorldBuilderSource}; diff --git a/crates/bevy_ecs/src/executor.rs b/crates/bevy_ecs/src/parallel_executor.rs similarity index 90% rename from crates/bevy_ecs/src/executor.rs rename to crates/bevy_ecs/src/parallel_executor.rs index f68153c926..8488f3bdbc 100644 --- a/crates/bevy_ecs/src/executor.rs +++ b/crates/bevy_ecs/src/parallel_executor.rs @@ -1,16 +1,16 @@ -use crate::{system::ThreadLocalExecution, Resources, Schedule, System}; +use crate::{system::{ArchetypeAccess, ThreadLocalExecution}, Resources, Schedule, System}; use crossbeam_channel::{Receiver, Sender}; use fixedbitset::FixedBitSet; -use hecs::{Access, Query, World}; +use hecs::{World}; use rayon::ScopeFifo; use std::sync::{Arc, Mutex}; #[derive(Default)] -pub struct Executor { +pub struct ParallelExecutor { stages: Vec, } -impl Executor { +impl ParallelExecutor { pub fn prepare(&mut self, schedule: &mut Schedule, world: &World) { // TODO: if world archetype generation hasnt changed, dont update here @@ -27,6 +27,7 @@ impl Executor { } pub fn run(&mut self, schedule: &mut Schedule, world: &mut World, resources: &mut Resources) { + self.prepare(schedule, world); for (stage_name, executor_stage) in schedule.stage_order.iter().zip(self.stages.iter_mut()) { if let Some(stage_systems) = schedule.stages.get_mut(stage_name) { @@ -265,49 +266,9 @@ impl ExecutorStage { } } -// credit to Ratysz from the Yaks codebase -#[derive(Default)] -pub struct ArchetypeAccess { - pub immutable: FixedBitSet, - pub mutable: FixedBitSet, -} - -impl ArchetypeAccess { - pub fn is_compatible(&self, other: &ArchetypeAccess) -> bool { - self.mutable.is_disjoint(&other.mutable) - && self.mutable.is_disjoint(&other.immutable) - && self.immutable.is_disjoint(&other.mutable) - } - - pub fn union(&mut self, other: &ArchetypeAccess) { - self.mutable.union_with(&other.mutable); - self.immutable.union_with(&other.immutable); - } - - pub fn set_access_for_query(&mut self, world: &World) - where - Q: Query, - { - self.immutable.clear(); - self.mutable.clear(); - let iterator = world.archetypes(); - let bits = iterator.len(); - self.immutable.grow(bits); - self.mutable.grow(bits); - iterator - .enumerate() - .filter_map(|(index, archetype)| archetype.access::().map(|access| (index, access))) - .for_each(|(archetype, access)| match access { - Access::Read => self.immutable.set(archetype, true), - Access::Write => self.mutable.set(archetype, true), - Access::Iterate => (), - }); - } -} - #[cfg(test)] mod tests { - use super::Executor; + use super::ParallelExecutor; use crate::{IntoQuerySystem, IntoThreadLocalSystem, Query, Res, Resources, Schedule, World}; use fixedbitset::FixedBitSet; use std::sync::{Arc, Mutex}; @@ -403,14 +364,14 @@ mod tests { schedule.add_system_to_stage("B", thread_local_system.thread_local_system()); schedule.add_system_to_stage("B", write_f32.system()); - let mut executor = Executor::default(); + let mut executor = ParallelExecutor::default(); run_executor_and_validate(&mut executor, &mut schedule, &mut world, &mut resources); // run again (with counter reset) to ensure executor works correctly across runs *resources.get::().unwrap().count.lock().unwrap() = 0; run_executor_and_validate(&mut executor, &mut schedule, &mut world, &mut resources); } - fn run_executor_and_validate(executor: &mut Executor, schedule: &mut Schedule, world: &mut World, resources: &mut Resources) { + fn run_executor_and_validate(executor: &mut ParallelExecutor, schedule: &mut Schedule, world: &mut World, resources: &mut Resources) { executor.prepare(schedule, world); assert_eq!( diff --git a/crates/bevy_ecs/src/system.rs b/crates/bevy_ecs/src/system.rs index 7471123392..abeac2ff37 100644 --- a/crates/bevy_ecs/src/system.rs +++ b/crates/bevy_ecs/src/system.rs @@ -1,5 +1,7 @@ -use crate::{Resources, World, executor::ArchetypeAccess}; +use crate::{Resources, World}; use std::borrow::Cow; +use fixedbitset::FixedBitSet; +use hecs::{Query, Access}; #[derive(Copy, Clone)] pub enum ThreadLocalExecution { @@ -26,3 +28,43 @@ pub trait System: Send + Sync { fn run_thread_local(&mut self, world: &mut World, resources: &mut Resources); fn initialize(&mut self, _resources: &mut Resources) {} } + +// credit to Ratysz from the Yaks codebase +#[derive(Default)] +pub struct ArchetypeAccess { + pub immutable: FixedBitSet, + pub mutable: FixedBitSet, +} + +impl ArchetypeAccess { + pub fn is_compatible(&self, other: &ArchetypeAccess) -> bool { + self.mutable.is_disjoint(&other.mutable) + && self.mutable.is_disjoint(&other.immutable) + && self.immutable.is_disjoint(&other.mutable) + } + + pub fn union(&mut self, other: &ArchetypeAccess) { + self.mutable.union_with(&other.mutable); + self.immutable.union_with(&other.immutable); + } + + pub fn set_access_for_query(&mut self, world: &World) + where + Q: Query, + { + self.immutable.clear(); + self.mutable.clear(); + let iterator = world.archetypes(); + let bits = iterator.len(); + self.immutable.grow(bits); + self.mutable.grow(bits); + iterator + .enumerate() + .filter_map(|(index, archetype)| archetype.access::().map(|access| (index, access))) + .for_each(|(archetype, access)| match access { + Access::Read => self.immutable.set(archetype, true), + Access::Write => self.mutable.set(archetype, true), + Access::Iterate => (), + }); + } +} \ No newline at end of file