Skip to content

Commit

Permalink
System sets and parallel executor v2 (#1144)
Browse files Browse the repository at this point in the history
System sets and parallel executor v2
  • Loading branch information
Ratysz authored Feb 9, 2021
1 parent b71ada0 commit d5a7330
Show file tree
Hide file tree
Showing 45 changed files with 3,169 additions and 1,358 deletions.
5 changes: 2 additions & 3 deletions crates/bevy_app/src/app.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::app_builder::AppBuilder;
use bevy_ecs::{Resources, Schedule, World};
use bevy_ecs::{Resources, Schedule, Stage, World};
#[cfg(feature = "trace")]
use bevy_utils::tracing::info_span;

Expand Down Expand Up @@ -53,8 +53,7 @@ impl App {
}

pub fn update(&mut self) {
self.schedule
.initialize_and_run(&mut self.world, &mut self.resources);
self.schedule.run(&mut self.world, &mut self.resources);
}

pub fn run(mut self) {
Expand Down
84 changes: 41 additions & 43 deletions crates/bevy_app/src/app_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ use crate::{
stage, startup_stage, PluginGroup, PluginGroupBuilder,
};
use bevy_ecs::{
clear_trackers_system, FromResources, IntoSystem, Resource, Resources, RunOnce, Schedule,
Stage, StateStage, System, SystemStage, World,
clear_trackers_system, FromResources, IntoExclusiveSystem, IntoSystem, Resource, Resources,
RunOnce, Schedule, Stage, StateStage, SystemDescriptor, SystemStage, World,
};
use bevy_utils::tracing::debug;

Expand All @@ -24,7 +24,7 @@ impl Default for AppBuilder {
app_builder
.add_default_stages()
.add_event::<AppExit>()
.add_system_to_stage(stage::LAST, clear_trackers_system.system());
.add_system_to_stage(stage::LAST, clear_trackers_system.exclusive_system());
app_builder
}
}
Expand Down Expand Up @@ -125,60 +125,69 @@ impl AppBuilder {
self
}

pub fn add_system<S: System<In = (), Out = ()>>(&mut self, system: S) -> &mut Self {
pub fn add_system(&mut self, system: impl Into<SystemDescriptor>) -> &mut Self {
self.add_system_to_stage(stage::UPDATE, system)
}

pub fn on_state_enter<T: Clone + Resource, S: System<In = (), Out = ()>>(
pub fn add_system_to_stage(
&mut self,
stage_name: &'static str,
system: impl Into<SystemDescriptor>,
) -> &mut Self {
self.app.schedule.add_system_to_stage(stage_name, system);
self
}

pub fn add_startup_system(&mut self, system: impl Into<SystemDescriptor>) -> &mut Self {
self.add_startup_system_to_stage(startup_stage::STARTUP, system)
}

pub fn add_startup_system_to_stage(
&mut self,
stage_name: &'static str,
system: impl Into<SystemDescriptor>,
) -> &mut Self {
self.app
.schedule
.stage(stage::STARTUP, |schedule: &mut Schedule| {
schedule.add_system_to_stage(stage_name, system)
});
self
}

pub fn on_state_enter<T: Clone + Resource>(
&mut self,
stage: &str,
state: T,
system: S,
system: impl Into<SystemDescriptor>,
) -> &mut Self {
self.stage(stage, |stage: &mut StateStage<T>| {
stage.on_state_enter(state, system)
})
}

pub fn on_state_update<T: Clone + Resource, S: System<In = (), Out = ()>>(
pub fn on_state_update<T: Clone + Resource>(
&mut self,
stage: &str,
state: T,
system: S,
system: impl Into<SystemDescriptor>,
) -> &mut Self {
self.stage(stage, |stage: &mut StateStage<T>| {
stage.on_state_update(state, system)
})
}

pub fn on_state_exit<T: Clone + Resource, S: System<In = (), Out = ()>>(
pub fn on_state_exit<T: Clone + Resource>(
&mut self,
stage: &str,
state: T,
system: S,
system: impl Into<SystemDescriptor>,
) -> &mut Self {
self.stage(stage, |stage: &mut StateStage<T>| {
stage.on_state_exit(state, system)
})
}

pub fn add_startup_system_to_stage<S: System<In = (), Out = ()>>(
&mut self,
stage_name: &'static str,
system: S,
) -> &mut Self {
self.app
.schedule
.stage(stage::STARTUP, |schedule: &mut Schedule| {
schedule.add_system_to_stage(stage_name, system)
});
self
}

pub fn add_startup_system<S: System<In = (), Out = ()>>(&mut self, system: S) -> &mut Self {
self.add_startup_system_to_stage(startup_stage::STARTUP, system)
}

pub fn add_default_stages(&mut self) -> &mut Self {
self.add_stage(
stage::STARTUP,
Expand All @@ -197,15 +206,6 @@ impl AppBuilder {
.add_stage(stage::LAST, SystemStage::parallel())
}

pub fn add_system_to_stage<S: System<In = (), Out = ()>>(
&mut self,
stage_name: &'static str,
system: S,
) -> &mut Self {
self.app.schedule.add_system_to_stage(stage_name, system);
self
}

pub fn add_event<T>(&mut self) -> &mut Self
where
T: Send + Sync + 'static,
Expand All @@ -223,11 +223,11 @@ impl AppBuilder {
self
}

pub fn insert_thread_local_resource<T>(&mut self, resource: T) -> &mut Self
pub fn insert_non_send_resource<T>(&mut self, resource: T) -> &mut Self
where
T: 'static,
{
self.app.resources.insert_thread_local(resource);
self.app.resources.insert_non_send(resource);
self
}

Expand All @@ -242,20 +242,18 @@ impl AppBuilder {
let resource = R::from_resources(&self.resources());
self.insert_resource(resource);
}

self
}

pub fn init_thread_local_resource<R>(&mut self) -> &mut Self
pub fn init_non_send_resource<R>(&mut self) -> &mut Self
where
R: FromResources + 'static,
{
// See perf comment in init_resource
if self.app.resources.get_thread_local::<R>().is_none() {
if self.app.resources.get_non_send::<R>().is_none() {
let resource = R::from_resources(&self.app.resources);
self.app.resources.insert_thread_local(resource);
self.app.resources.insert_non_send(resource);
}

self
}

Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_audio/src/audio_output.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ where
<P as Decodable>::Decoder: rodio::Source + Send + Sync,
<<P as Decodable>::Decoder as Iterator>::Item: rodio::Sample + Send + Sync,
{
let audio_output = resources.get_thread_local::<AudioOutput<P>>().unwrap();
let audio_output = resources.get_non_send::<AudioOutput<P>>().unwrap();
let mut audio = resources.get_mut::<Audio<P>>().unwrap();

if let Some(audio_sources) = resources.get::<Assets<P>>() {
Expand Down
6 changes: 3 additions & 3 deletions crates/bevy_audio/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,21 @@ pub mod prelude {

use bevy_app::prelude::*;
use bevy_asset::AddAsset;
use bevy_ecs::IntoSystem;
use bevy_ecs::IntoExclusiveSystem;

/// Adds support for audio playback to an App
#[derive(Default)]
pub struct AudioPlugin;

impl Plugin for AudioPlugin {
fn build(&self, app: &mut AppBuilder) {
app.init_thread_local_resource::<AudioOutput<AudioSource>>()
app.init_non_send_resource::<AudioOutput<AudioSource>>()
.add_asset::<AudioSource>()
.init_asset_loader::<Mp3Loader>()
.init_resource::<Audio<AudioSource>>()
.add_system_to_stage(
stage::POST_UPDATE,
play_queued_audio_system::<AudioSource>.system(),
play_queued_audio_system::<AudioSource>.exclusive_system(),
);
}
}
31 changes: 16 additions & 15 deletions crates/bevy_core/src/label.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,13 +115,14 @@ pub(crate) fn entity_labels_system(
#[cfg(test)]
mod tests {
use super::*;
use bevy_ecs::Stage;

fn setup() -> (World, Resources, bevy_ecs::Schedule) {
let world = World::new();
let mut resources = Resources::default();
resources.insert(EntityLabels::default());
let mut schedule = bevy_ecs::Schedule::default();
schedule.add_stage("test", SystemStage::serial());
schedule.add_stage("test", SystemStage::single_threaded());
schedule.add_system_to_stage("test", entity_labels_system.system());
(world, resources, schedule)
}
Expand All @@ -139,7 +140,7 @@ mod tests {
let (mut world, mut resources, mut schedule) = setup();

let e1 = world.spawn((holy_cow(),));
schedule.initialize_and_run(&mut world, &mut resources);
schedule.run(&mut world, &mut resources);

let entity_labels = resources.get::<EntityLabels>().unwrap();
assert_eq!(entity_labels.get("holy"), &[e1], "holy");
Expand All @@ -151,10 +152,10 @@ mod tests {
fn add_labels() {
let (mut world, mut resources, mut schedule) = setup();
let e1 = world.spawn((holy_cow(),));
schedule.initialize_and_run(&mut world, &mut resources);
schedule.run(&mut world, &mut resources);

world.get_mut::<Labels>(e1).unwrap().insert("shalau");
schedule.initialize_and_run(&mut world, &mut resources);
schedule.run(&mut world, &mut resources);

let entity_labels = resources.get::<EntityLabels>().unwrap();
assert_eq!(entity_labels.get("holy"), &[e1], "holy");
Expand All @@ -166,10 +167,10 @@ mod tests {
fn remove_labels() {
let (mut world, mut resources, mut schedule) = setup();
let e1 = world.spawn((holy_cow(),));
schedule.initialize_and_run(&mut world, &mut resources);
schedule.run(&mut world, &mut resources);

world.get_mut::<Labels>(e1).unwrap().remove("holy");
schedule.initialize_and_run(&mut world, &mut resources);
schedule.run(&mut world, &mut resources);

let entity_labels = resources.get::<EntityLabels>().unwrap();
assert_eq!(entity_labels.get("holy"), &[], "holy");
Expand All @@ -181,10 +182,10 @@ mod tests {
fn removes_despawned_entity() {
let (mut world, mut resources, mut schedule) = setup();
let e1 = world.spawn((holy_cow(),));
schedule.initialize_and_run(&mut world, &mut resources);
schedule.run(&mut world, &mut resources);

world.despawn(e1).unwrap();
schedule.initialize_and_run(&mut world, &mut resources);
schedule.run(&mut world, &mut resources);

let entity_labels = resources.get::<EntityLabels>().unwrap();
assert_eq!(entity_labels.get("holy"), &[], "holy");
Expand All @@ -196,10 +197,10 @@ mod tests {
fn removes_labels_when_component_removed() {
let (mut world, mut resources, mut schedule) = setup();
let e1 = world.spawn((holy_cow(),));
schedule.initialize_and_run(&mut world, &mut resources);
schedule.run(&mut world, &mut resources);

world.remove_one::<Labels>(e1).unwrap();
schedule.initialize_and_run(&mut world, &mut resources);
schedule.run(&mut world, &mut resources);

let entity_labels = resources.get::<EntityLabels>().unwrap();
assert_eq!(entity_labels.get("holy"), &[], "holy");
Expand All @@ -211,10 +212,10 @@ mod tests {
fn adds_another_spawned_entity() {
let (mut world, mut resources, mut schedule) = setup();
let e1 = world.spawn((holy_cow(),));
schedule.initialize_and_run(&mut world, &mut resources);
schedule.run(&mut world, &mut resources);

let e2 = world.spawn((holy_shamoni(),));
schedule.initialize_and_run(&mut world, &mut resources);
schedule.run(&mut world, &mut resources);

let entity_labels = resources.get::<EntityLabels>().unwrap();
assert_eq!(entity_labels.get("holy"), &[e1, e2], "holy");
Expand All @@ -227,13 +228,13 @@ mod tests {
fn removes_despawned_entity_but_leaves_other() {
let (mut world, mut resources, mut schedule) = setup();
let e1 = world.spawn((holy_cow(),));
schedule.initialize_and_run(&mut world, &mut resources);
schedule.run(&mut world, &mut resources);

let e2 = world.spawn((holy_shamoni(),));
schedule.initialize_and_run(&mut world, &mut resources);
schedule.run(&mut world, &mut resources);

world.despawn(e1).unwrap();
schedule.initialize_and_run(&mut world, &mut resources);
schedule.run(&mut world, &mut resources);

let entity_labels = resources.get::<EntityLabels>().unwrap();
assert_eq!(entity_labels.get("holy"), &[e2], "holy");
Expand Down
22 changes: 14 additions & 8 deletions crates/bevy_core/src/time/fixed_timestep.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::Time;
use bevy_ecs::{ArchetypeComponent, ShouldRun, System, SystemId, ThreadLocalExecution, TypeAccess};
use bevy_ecs::{ArchetypeComponent, ShouldRun, System, SystemId, TypeAccess};
use bevy_utils::HashMap;
use std::{any::TypeId, borrow::Cow};

Expand Down Expand Up @@ -47,8 +47,9 @@ pub struct FixedTimestep {
looping: bool,
system_id: SystemId,
label: Option<String>, // TODO: consider making this a TypedLabel
resource_access: TypeAccess<TypeId>,
archetype_access: TypeAccess<ArchetypeComponent>,
component_access: TypeAccess<TypeId>,
resource_access: TypeAccess<TypeId>,
}

impl Default for FixedTimestep {
Expand All @@ -59,8 +60,9 @@ impl Default for FixedTimestep {
accumulator: 0.0,
looping: false,
label: None,
resource_access: Default::default(),
component_access: Default::default(),
archetype_access: Default::default(),
resource_access: Default::default(),
}
}
}
Expand Down Expand Up @@ -93,7 +95,7 @@ impl FixedTimestep {
if self.accumulator >= self.step {
self.accumulator -= self.step;
self.looping = true;
ShouldRun::YesAndLoop
ShouldRun::YesAndCheckAgain
} else {
self.looping = false;
ShouldRun::No
Expand All @@ -113,18 +115,22 @@ impl System for FixedTimestep {
self.system_id
}

fn update(&mut self, _world: &bevy_ecs::World) {}
fn update_access(&mut self, _world: &bevy_ecs::World) {}

fn archetype_component_access(&self) -> &TypeAccess<ArchetypeComponent> {
&self.archetype_access
}

fn component_access(&self) -> &TypeAccess<TypeId> {
&self.component_access
}

fn resource_access(&self) -> &TypeAccess<TypeId> {
&self.resource_access
}

fn thread_local_execution(&self) -> ThreadLocalExecution {
ThreadLocalExecution::Immediate
fn is_non_send(&self) -> bool {
false
}

unsafe fn run_unsafe(
Expand All @@ -145,7 +151,7 @@ impl System for FixedTimestep {
Some(result)
}

fn run_thread_local(
fn apply_buffers(
&mut self,
_world: &mut bevy_ecs::World,
_resources: &mut bevy_ecs::Resources,
Expand Down
Loading

0 comments on commit d5a7330

Please sign in to comment.