mirror of
https://github.com/bevyengine/bevy
synced 2024-12-22 11:03:06 +00:00
2fcd8a3fb0
Based on #1910 This shrinks breakout from 310k to 293k. Most of the win is in outlining the drop glue of `App`. The other two commits save about 800 bytes total when using two empty systems and two simple resources. After this PR the full disassembly for ```rust fn main() { App::build().run(); } ``` is about as minimal as it gets, so pretty much all other costs scale linear in the amount of resources, systems, etc. ```asm 0000000000001100 <_ZN4core3ptr54drop_in_place$LT$bevy_app..app_builder..AppBuilder$GT$17h76850422c20653deE>: 1100: ff 25 52 21 00 00 jmpq *0x2152(%rip) # 3258 <_ZN60_$LT$bevy_app..app..App$u20$as$u20$core..ops..drop..Drop$GT$4drop17h67d177ae549d917bE@Base> 1106: cc int3 1107: cc int3 1108: cc int3 1109: cc int3 110a: cc int3 110b: cc int3 110c: cc int3 110d: cc int3 110e: cc int3 110f: cc int3 0000000000001110 <_ZN8breakout4main17h7cbe07b319de1042E>: 1110: 53 push %rbx 1111: 48 81 ec 00 03 00 00 sub $0x300,%rsp 1118: 48 8d 5c 24 08 lea 0x8(%rsp),%rbx 111d: 48 89 df mov %rbx,%rdi 1120: ff 15 3a 21 00 00 callq *0x213a(%rip) # 3260 <_ZN8bevy_app3app3App5build17h8b0ea6be9050d6ccE@Base> 1126: 48 89 df mov %rbx,%rdi 1129: ff 15 39 21 00 00 callq *0x2139(%rip) # 3268 <_ZN8bevy_app11app_builder10AppBuilder3run17hfc8cf50692acdbdeE@Base> 112f: 48 8d 7c 24 08 lea 0x8(%rsp),%rdi 1134: ff 15 1e 21 00 00 callq *0x211e(%rip) # 3258 <_ZN60_$LT$bevy_app..app..App$u20$as$u20$core..ops..drop..Drop$GT$4drop17h67d177ae549d917bE@Base> 113a: 48 81 c4 00 03 00 00 add $0x300,%rsp 1141: 5b pop %rbx 1142: c3 retq 1143: 48 89 c3 mov %rax,%rbx 1146: 48 8d 7c 24 08 lea 0x8(%rsp),%rdi 114b: e8 b0 ff ff ff callq 1100 <_ZN4core3ptr54drop_in_place$LT$bevy_app..app_builder..AppBuilder$GT$17h76850422c20653deE> 1150: 48 89 df mov %rbx,%rdi 1153: e8 18 01 00 00 callq 1270 <_Unwind_Resume@plt> 1158: 0f 0b ud2 115a: cc int3 115b: cc int3 115c: cc int3 115d: cc int3 115e: cc int3 115f: cc int3 0000000000001160 <main>: 1160: 48 83 ec 08 sub $0x8,%rsp 1164: 48 89 f1 mov %rsi,%rcx 1167: 48 63 d7 movslq %edi,%rdx 116a: 48 8d 05 9f ff ff ff lea -0x61(%rip),%rax # 1110 <_ZN8breakout4main17h7cbe07b319de1042E> 1171: 48 89 04 24 mov %rax,(%rsp) 1175: 48 8d 35 94 1e 00 00 lea 0x1e94(%rip),%rsi # 3010 <__init_array_end> 117c: 48 89 e7 mov %rsp,%rdi 117f: ff 15 eb 20 00 00 callq *0x20eb(%rip) # 3270 <_ZN3std2rt19lang_start_internal17he77194431b0ee4a2E@Base> 1185: 59 pop %rcx 1186: c3 retq 1187: cc int3 1188: cc int3 1189: cc int3 118a: cc int3 118b: cc int3 118c: cc int3 118d: cc int3 118e: cc int3 118f: cc int3 0000000000001190 <_ZN3std2rt10lang_start28_$u7b$$u7b$closure$u7d$$u7d$17h83a5b8d55f23dff8E.llvm.909376793398482062>: 1190: 48 83 ec 08 sub $0x8,%rsp 1194: 48 8b 3f mov (%rdi),%rdi 1197: e8 54 ff ff ff callq 10f0 <_ZN3std10sys_common9backtrace28__rust_begin_short_backtrace17h6e238af75680eb28E> 119c: 31 c0 xor %eax,%eax 119e: 59 pop %rcx 119f: c3 retq 00000000000011a0 <_ZN4core3ops8function6FnOnce40call_once$u7b$$u7b$vtable.shim$u7d$$u7d$17hb05d591cd29dea4fE.llvm.909376793398482062>: 11a0: 48 83 ec 08 sub $0x8,%rsp 11a4: 48 8b 3f mov (%rdi),%rdi 11a7: e8 44 ff ff ff callq 10f0 <_ZN3std10sys_common9backtrace28__rust_begin_short_backtrace17h6e238af75680eb28E> 11ac: 31 c0 xor %eax,%eax 11ae: 59 pop %rcx 11af: c3 retq 00000000000011b0 <_ZN4core3ptr85drop_in_place$LT$std..rt..lang_start$LT$$LP$$RP$$GT$..$u7b$$u7b$closure$u7d$$u7d$$GT$17he9aeeba375093b99E.llvm.909376793398482062>: 11b0: c3 retq 11b1: cc int3 11b2: cc int3 11b3: cc int3 11b4: cc int3 11b5: cc int3 11b6: cc int3 11b7: cc int3 11b8: cc int3 11b9: cc int3 11ba: cc int3 11bb: cc int3 11bc: cc int3 11bd: cc int3 11be: cc int3 11bf: cc int3 ```
238 lines
6.9 KiB
Rust
238 lines
6.9 KiB
Rust
mod executor;
|
|
mod executor_parallel;
|
|
pub mod graph_utils;
|
|
mod label;
|
|
mod run_criteria;
|
|
mod stage;
|
|
mod state;
|
|
mod system_container;
|
|
mod system_descriptor;
|
|
mod system_set;
|
|
|
|
pub use executor::*;
|
|
pub use executor_parallel::*;
|
|
pub use graph_utils::GraphNode;
|
|
pub use label::*;
|
|
pub use run_criteria::*;
|
|
pub use stage::*;
|
|
pub use state::*;
|
|
pub use system_container::*;
|
|
pub use system_descriptor::*;
|
|
pub use system_set::*;
|
|
|
|
use std::fmt::Debug;
|
|
|
|
use crate::{
|
|
system::{IntoSystem, System},
|
|
world::World,
|
|
};
|
|
use bevy_utils::HashMap;
|
|
|
|
#[derive(Default)]
|
|
pub struct Schedule {
|
|
stages: HashMap<BoxedStageLabel, Box<dyn Stage>>,
|
|
stage_order: Vec<BoxedStageLabel>,
|
|
run_criteria: BoxedRunCriteria,
|
|
}
|
|
|
|
impl Schedule {
|
|
pub fn with_stage<S: Stage>(mut self, label: impl StageLabel, stage: S) -> Self {
|
|
self.add_stage(label, stage);
|
|
self
|
|
}
|
|
|
|
pub fn with_stage_after<S: Stage>(
|
|
mut self,
|
|
target: impl StageLabel,
|
|
label: impl StageLabel,
|
|
stage: S,
|
|
) -> Self {
|
|
self.add_stage_after(target, label, stage);
|
|
self
|
|
}
|
|
|
|
pub fn with_stage_before<S: Stage>(
|
|
mut self,
|
|
target: impl StageLabel,
|
|
label: impl StageLabel,
|
|
stage: S,
|
|
) -> Self {
|
|
self.add_stage_before(target, label, stage);
|
|
self
|
|
}
|
|
|
|
pub fn with_run_criteria<S: System<In = (), Out = ShouldRun>>(mut self, system: S) -> Self {
|
|
self.set_run_criteria(system);
|
|
self
|
|
}
|
|
|
|
pub fn with_system_in_stage(
|
|
mut self,
|
|
stage_label: impl StageLabel,
|
|
system: impl Into<SystemDescriptor>,
|
|
) -> Self {
|
|
self.add_system_to_stage(stage_label, system);
|
|
self
|
|
}
|
|
|
|
pub fn set_run_criteria<S: System<In = (), Out = ShouldRun>>(
|
|
&mut self,
|
|
system: S,
|
|
) -> &mut Self {
|
|
self.run_criteria.set(Box::new(system.system()));
|
|
self
|
|
}
|
|
|
|
pub fn add_stage<S: Stage>(&mut self, label: impl StageLabel, stage: S) -> &mut Self {
|
|
let label: Box<dyn StageLabel> = Box::new(label);
|
|
self.stage_order.push(label.clone());
|
|
let prev = self.stages.insert(label.clone(), Box::new(stage));
|
|
if prev.is_some() {
|
|
panic!("Stage already exists: {:?}.", label);
|
|
}
|
|
self
|
|
}
|
|
|
|
pub fn add_stage_after<S: Stage>(
|
|
&mut self,
|
|
target: impl StageLabel,
|
|
label: impl StageLabel,
|
|
stage: S,
|
|
) -> &mut Self {
|
|
let label: Box<dyn StageLabel> = Box::new(label);
|
|
let target = &target as &dyn StageLabel;
|
|
let target_index = self
|
|
.stage_order
|
|
.iter()
|
|
.enumerate()
|
|
.find(|(_i, stage_label)| &***stage_label == target)
|
|
.map(|(i, _)| i)
|
|
.unwrap_or_else(|| panic!("Target stage does not exist: {:?}.", target));
|
|
|
|
self.stage_order.insert(target_index + 1, label.clone());
|
|
let prev = self.stages.insert(label.clone(), Box::new(stage));
|
|
if prev.is_some() {
|
|
panic!("Stage already exists: {:?}.", label);
|
|
}
|
|
self
|
|
}
|
|
|
|
pub fn add_stage_before<S: Stage>(
|
|
&mut self,
|
|
target: impl StageLabel,
|
|
label: impl StageLabel,
|
|
stage: S,
|
|
) -> &mut Self {
|
|
let label: Box<dyn StageLabel> = Box::new(label);
|
|
let target = &target as &dyn StageLabel;
|
|
let target_index = self
|
|
.stage_order
|
|
.iter()
|
|
.enumerate()
|
|
.find(|(_i, stage_label)| &***stage_label == target)
|
|
.map(|(i, _)| i)
|
|
.unwrap_or_else(|| panic!("Target stage does not exist: {:?}.", target));
|
|
|
|
self.stage_order.insert(target_index, label.clone());
|
|
let prev = self.stages.insert(label.clone(), Box::new(stage));
|
|
if prev.is_some() {
|
|
panic!("Stage already exists: {:?}.", label);
|
|
}
|
|
self
|
|
}
|
|
|
|
pub fn add_system_to_stage(
|
|
&mut self,
|
|
stage_label: impl StageLabel,
|
|
system: impl Into<SystemDescriptor>,
|
|
) -> &mut Self {
|
|
// Use a function instead of a closure to ensure that it is codegend inside bevy_ecs instead
|
|
// of the game. Closures inherit generic parameters from their enclosing function.
|
|
#[cold]
|
|
fn stage_not_found(stage_label: &dyn Debug) -> ! {
|
|
panic!(
|
|
"Stage '{:?}' does not exist or is not a SystemStage",
|
|
stage_label
|
|
)
|
|
}
|
|
|
|
let stage = self
|
|
.get_stage_mut::<SystemStage>(&stage_label)
|
|
.unwrap_or_else(move || stage_not_found(&stage_label));
|
|
stage.add_system(system);
|
|
self
|
|
}
|
|
|
|
pub fn add_system_set_to_stage(
|
|
&mut self,
|
|
stage_label: impl StageLabel,
|
|
system_set: SystemSet,
|
|
) -> &mut Self {
|
|
self.stage(stage_label, |stage: &mut SystemStage| {
|
|
stage.add_system_set(system_set)
|
|
})
|
|
}
|
|
|
|
pub fn stage<T: Stage, F: FnOnce(&mut T) -> &mut T>(
|
|
&mut self,
|
|
label: impl StageLabel,
|
|
func: F,
|
|
) -> &mut Self {
|
|
let stage = self.get_stage_mut::<T>(&label).unwrap_or_else(move || {
|
|
panic!("stage '{:?}' does not exist or is the wrong type", label)
|
|
});
|
|
func(stage);
|
|
self
|
|
}
|
|
|
|
pub fn get_stage<T: Stage>(&self, label: &dyn StageLabel) -> Option<&T> {
|
|
self.stages
|
|
.get(label)
|
|
.and_then(|stage| stage.downcast_ref::<T>())
|
|
}
|
|
|
|
pub fn get_stage_mut<T: Stage>(&mut self, label: &dyn StageLabel) -> Option<&mut T> {
|
|
self.stages
|
|
.get_mut(label)
|
|
.and_then(|stage| stage.downcast_mut::<T>())
|
|
}
|
|
|
|
pub fn run_once(&mut self, world: &mut World) {
|
|
for label in self.stage_order.iter() {
|
|
#[cfg(feature = "trace")]
|
|
let stage_span =
|
|
bevy_utils::tracing::info_span!("stage", name = &format!("{:?}", label) as &str);
|
|
#[cfg(feature = "trace")]
|
|
let _stage_guard = stage_span.enter();
|
|
let stage = self.stages.get_mut(label).unwrap();
|
|
stage.run(world);
|
|
}
|
|
}
|
|
|
|
/// Iterates over all of schedule's stages and their labels, in execution order.
|
|
pub fn iter_stages(&self) -> impl Iterator<Item = (&dyn StageLabel, &dyn Stage)> {
|
|
self.stage_order
|
|
.iter()
|
|
.map(move |label| (&**label, &*self.stages[label]))
|
|
}
|
|
}
|
|
|
|
impl Stage for Schedule {
|
|
fn run(&mut self, world: &mut World) {
|
|
loop {
|
|
match self.run_criteria.should_run(world) {
|
|
ShouldRun::No => return,
|
|
ShouldRun::Yes => {
|
|
self.run_once(world);
|
|
return;
|
|
}
|
|
ShouldRun::YesAndCheckAgain => {
|
|
self.run_once(world);
|
|
}
|
|
ShouldRun::NoAndCheckAgain => {
|
|
panic!("`NoAndCheckAgain` would loop infinitely in this situation.")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|