diff --git a/crates/bevy_app/src/app.rs b/crates/bevy_app/src/app.rs index 428dac0fd54ca..34d36ed0814a7 100644 --- a/crates/bevy_app/src/app.rs +++ b/crates/bevy_app/src/app.rs @@ -76,22 +76,27 @@ struct SubApp { runner: Box, } -impl Default for App { - fn default() -> Self { - let mut app = App::empty(); - #[cfg(feature = "bevy_reflect")] - app.init_resource::(); - - app.add_default_stages() - .add_event::() - .add_system_to_stage(CoreStage::Last, World::clear_trackers.exclusive_system()); +/// Option for [`App::add_default_stages`] that sets the stages to be single or multi threaded. +pub enum DefaultStagesThreading { + /// run app single threaded + Single, + /// run app multi threaded + Multi, +} - #[cfg(feature = "bevy_ci_testing")] - { - crate::ci_testing::setup_app(&mut app); +impl DefaultStagesThreading { + /// Gets a new instance of [`SystemStage`] for the corresponding value of [`DefaultStagesThreading`] + pub fn get_stage(&self) -> SystemStage { + match self { + DefaultStagesThreading::Multi => SystemStage::parallel(), + DefaultStagesThreading::Single => SystemStage::single_threaded(), } + } +} - app +impl Default for App { + fn default() -> Self { + App::multi_threaded() } } @@ -114,6 +119,33 @@ impl App { } } + /// Creates a new [`App`] with some default structure with all default stages set to use single threaded system executor. + pub fn single_threaded() -> App { + App::new_with_threading_option(DefaultStagesThreading::Single) + } + + /// Creates a new [`App`] with some default structure with all default stages set to use multithreaded system executor. + pub fn multi_threaded() -> App { + App::new_with_threading_option(DefaultStagesThreading::Multi) + } + + fn new_with_threading_option(threading: DefaultStagesThreading) -> App { + let mut app = App::empty(); + #[cfg(feature = "bevy_reflect")] + app.init_resource::(); + + app.add_default_stages(threading) + .add_event::() + .add_system_to_stage(CoreStage::Last, World::clear_trackers.exclusive_system()); + + #[cfg(feature = "bevy_ci_testing")] + { + crate::ci_testing::setup_app(&mut app); + } + + app + } + /// Advances the execution of the [`Schedule`] by one cycle. /// /// This method also updates sub apps. @@ -581,6 +613,8 @@ impl App { /// done by default by calling `App::default`, which is in turn called by /// [`App::new`]. /// + /// Use [`DefaultStagesThreading`] to specify the threading model to be used by the default stages. + /// /// # The stages /// /// All the added stages, with the exception of the startup stage, run every time the @@ -606,23 +640,24 @@ impl App { /// /// ``` /// # use bevy_app::prelude::*; + /// # use bevy_app::DefaultStagesThreading; /// # - /// let app = App::empty().add_default_stages(); + /// let app = App::empty().add_default_stages(DefaultStagesThreading::Multi); /// ``` - pub fn add_default_stages(&mut self) -> &mut Self { - self.add_stage(CoreStage::First, SystemStage::parallel()) + pub fn add_default_stages(&mut self, threading: DefaultStagesThreading) -> &mut Self { + self.add_stage(CoreStage::First, threading.get_stage()) .add_stage( StartupSchedule, Schedule::default() .with_run_criteria(ShouldRun::once) - .with_stage(StartupStage::PreStartup, SystemStage::parallel()) - .with_stage(StartupStage::Startup, SystemStage::parallel()) - .with_stage(StartupStage::PostStartup, SystemStage::parallel()), + .with_stage(StartupStage::PreStartup, threading.get_stage()) + .with_stage(StartupStage::Startup, threading.get_stage()) + .with_stage(StartupStage::PostStartup, threading.get_stage()), ) - .add_stage(CoreStage::PreUpdate, SystemStage::parallel()) - .add_stage(CoreStage::Update, SystemStage::parallel()) - .add_stage(CoreStage::PostUpdate, SystemStage::parallel()) - .add_stage(CoreStage::Last, SystemStage::parallel()) + .add_stage(CoreStage::PreUpdate, threading.get_stage()) + .add_stage(CoreStage::Update, threading.get_stage()) + .add_stage(CoreStage::PostUpdate, threading.get_stage()) + .add_stage(CoreStage::Last, threading.get_stage()) } /// Setup the application to manage events of type `T`.