diff --git a/crates/bevy_app/Cargo.toml b/crates/bevy_app/Cargo.toml index be1b36a05fc73..6eaf8874b9ca2 100644 --- a/crates/bevy_app/Cargo.toml +++ b/crates/bevy_app/Cargo.toml @@ -25,6 +25,7 @@ bevy_utils = { path = "../bevy_utils", version = "0.4.0" } # other serde = { version = "1.0", features = ["derive"] } +parking_lot = "0.11" [target.'cfg(target_arch = "wasm32")'.dependencies] wasm-bindgen = { version = "0.2" } diff --git a/crates/bevy_app/src/app_builder.rs b/crates/bevy_app/src/app_builder.rs index 36bb74953fe82..c4626396f9465 100644 --- a/crates/bevy_app/src/app_builder.rs +++ b/crates/bevy_app/src/app_builder.rs @@ -228,7 +228,7 @@ impl AppBuilder { T: Component, { self.insert_resource(Events::::default()) - .add_system_to_stage(CoreStage::First, Events::::update_system.system()) + .add_system_to_stage(CoreStage::Last, Events::::update_system.system()) } /// Inserts a resource to the current [App] and overwrites any resource previously added of the diff --git a/crates/bevy_app/src/event.rs b/crates/bevy_app/src/event.rs index d123b27d289e1..788ea3fd0f43b 100644 --- a/crates/bevy_app/src/event.rs +++ b/crates/bevy_app/src/event.rs @@ -1,8 +1,14 @@ +use bevy_ecs::system::{SystemParamFetch, SystemParamState, SystemState}; +use bevy_ecs::world::World; use bevy_ecs::{ component::Component, - system::{Local, Res, ResMut, SystemParam}, + system::{Res, ResMut, SystemParam}, }; use bevy_utils::tracing::trace; +use bevy_utils::HashMap; +use parking_lot::RwLock; +use std::cmp::min; +use std::ops::{Deref, DerefMut}; use std::{ fmt::{self}, hash::Hash, @@ -49,12 +55,6 @@ struct EventInstance { pub event: T, } -#[derive(Debug)] -enum State { - A, - B, -} - /// An event collection that represents the events that occurred within the last two /// [`Events::update`] calls. /// Events can be written to using an [`EventWriter`] @@ -84,7 +84,7 @@ enum State { /// /// // setup /// let mut events = Events::::default(); -/// let mut reader = events.get_reader(); +/// let reader = events.get_reader("unique_id"); /// /// // run this once per update/frame /// events.update(); @@ -93,12 +93,12 @@ enum State { /// events.send(MyEvent { value: 1 }); /// /// // somewhere else: read the events -/// for event in reader.iter(&events) { +/// for event in reader.iter() { /// assert_eq!(event.value, 1) /// } /// /// // events are only processed once per reader -/// assert_eq!(reader.iter(&events).count(), 0); +/// assert_eq!(reader.iter().count(), 0); /// ``` /// /// # Details @@ -117,23 +117,21 @@ enum State { /// but can be done by adding your event as a resource instead of using [`AppBuilder::add_event`]. #[derive(Debug)] pub struct Events { - events_a: Vec>, - events_b: Vec>, - a_start_event_count: usize, - b_start_event_count: usize, + buffer: Vec>, + subscriber_last_counts: RwLock>, + manual_subscriber_ids: RwLock>, event_count: usize, - state: State, + event_offset: usize, } impl Default for Events { fn default() -> Self { Events { - a_start_event_count: 0, - b_start_event_count: 0, + buffer: Vec::new(), + subscriber_last_counts: RwLock::default(), + manual_subscriber_ids: Default::default(), event_count: 0, - events_a: Vec::new(), - events_b: Vec::new(), - state: State::A, + event_offset: 0, } } } @@ -146,10 +144,59 @@ fn map_instance_event(event_instance: &EventInstance) -> &T { &event_instance.event } +pub struct SubscriberId<'a, T: Component>(&'a mut (usize, PhantomData)); + +impl<'a, T: Component> Deref for SubscriberId<'a, T> { + type Target = usize; + + #[inline] + fn deref(&self) -> &Self::Target { + &self.0 .0 + } +} + +impl<'a, T: Component> DerefMut for SubscriberId<'a, T> { + #[inline] + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 .0 + } +} + +pub struct SubscriberIdState((usize, PhantomData)); + +impl<'a, T: Component> SystemParam for SubscriberId<'a, T> { + type Fetch = SubscriberIdState; +} + +// SAFE: only local state is accessed +unsafe impl SystemParamState for SubscriberIdState { + type Config = Option; + + fn init(world: &mut World, _system_state: &mut SystemState, _config: Self::Config) -> Self { + let events = world.get_resource::>().unwrap(); + let subscription_id = events.add_subscriber(); + Self((subscription_id, PhantomData::::default())) + } +} + +impl<'a, T: Component> SystemParamFetch<'a> for SubscriberIdState { + type Item = SubscriberId<'a, T>; + + #[inline] + unsafe fn get_param( + state: &'a mut Self, + _system_state: &'a SystemState, + _world: &'a World, + _change_tick: u32, + ) -> Self::Item { + SubscriberId(&mut state.0) + } +} + /// Reads events of type `T` in order and tracks which events have already been read. #[derive(SystemParam)] pub struct EventReader<'a, T: Component> { - last_event_count: Local<'a, (usize, PhantomData)>, + subscriber_id: SubscriberId<'a, T>, events: Res<'a, Events>, } @@ -169,32 +216,28 @@ impl<'a, T: Component> EventWriter<'a, T> { } } -pub struct ManualEventReader { - last_event_count: usize, - _marker: PhantomData, -} - -impl Default for ManualEventReader { - fn default() -> Self { - ManualEventReader { - last_event_count: 0, - _marker: Default::default(), - } - } +pub struct ManualEventReader<'a, T> { + subscriber_id: usize, + events: &'a Events, } -impl ManualEventReader { +impl<'a, T: Component> ManualEventReader<'a, T> { /// See [`EventReader::iter`] - pub fn iter<'a>(&mut self, events: &'a Events) -> impl DoubleEndedIterator { - internal_event_reader(&mut self.last_event_count, events).map(|(e, _)| e) + pub fn iter(&self) -> impl DoubleEndedIterator { + let mut last_event_count = self.events.get_subscriber_read_count(self.subscriber_id); + let result = internal_event_reader(&mut last_event_count, self.events).map(|(e, _)| e); + self.events + .set_subscriber_read_count(self.subscriber_id, last_event_count); + result } /// See [`EventReader::iter_with_id`] - pub fn iter_with_id<'a>( - &mut self, - events: &'a Events, - ) -> impl DoubleEndedIterator)> { - internal_event_reader(&mut self.last_event_count, events) + pub fn iter_with_id(&self) -> impl DoubleEndedIterator)> { + let mut last_event_count = self.events.get_subscriber_read_count(self.subscriber_id); + let result = internal_event_reader(&mut last_event_count, self.events); + self.events + .set_subscriber_read_count(self.subscriber_id, last_event_count); + result } } @@ -206,47 +249,18 @@ fn internal_event_reader<'a, T>( ) -> impl DoubleEndedIterator)> { // if the reader has seen some of the events in a buffer, find the proper index offset. // otherwise read all events in the buffer - let a_index = if *last_event_count > events.a_start_event_count { - *last_event_count - events.a_start_event_count - } else { - 0 - }; - let b_index = if *last_event_count > events.b_start_event_count { - *last_event_count - events.b_start_event_count + let index = if *last_event_count > events.event_offset { + *last_event_count - events.event_offset } else { 0 }; *last_event_count = events.event_count; - match events.state { - State::A => events - .events_b - .get(b_index..) - .unwrap_or_else(|| &[]) - .iter() - .map(map_instance_event_with_id) - .chain( - events - .events_a - .get(a_index..) - .unwrap_or_else(|| &[]) - .iter() - .map(map_instance_event_with_id), - ), - State::B => events - .events_a - .get(a_index..) - .unwrap_or_else(|| &[]) - .iter() - .map(map_instance_event_with_id) - .chain( - events - .events_b - .get(b_index..) - .unwrap_or_else(|| &[]) - .iter() - .map(map_instance_event_with_id), - ), - } + events + .buffer + .get(index..) + .unwrap_or_else(|| &[]) + .iter() + .map(map_instance_event_with_id) } impl<'a, T: Component> EventReader<'a, T> { @@ -259,10 +273,12 @@ impl<'a, T: Component> EventReader<'a, T> { /// Like [`iter`](Self::iter), except also returning the [`EventId`] of the events. pub fn iter_with_id(&mut self) -> impl DoubleEndedIterator)> { - internal_event_reader(&mut self.last_event_count.0, &self.events).map(|(event, id)| { - trace!("EventReader::iter() -> {}", id); - (event, id) - }) + let subscriber_id = self.subscriber_id.0 .0; + let manual_reader = ManualEventReader { + subscriber_id, + events: &*self.events, + }; + manual_reader.iter_with_id() } } @@ -278,45 +294,58 @@ impl Events { let event_instance = EventInstance { event_id, event }; - match self.state { - State::A => self.events_a.push(event_instance), - State::B => self.events_b.push(event_instance), - } + self.buffer.push(event_instance); self.event_count += 1; } - /// Gets a new [ManualEventReader]. This will include all events already in the event buffers. - pub fn get_reader(&self) -> ManualEventReader { - ManualEventReader { - last_event_count: 0, - _marker: PhantomData, - } + pub fn add_subscriber(&self) -> usize { + let mut subscriber_last_counts_write = self.subscriber_last_counts.write(); + let id = subscriber_last_counts_write.len(); + subscriber_last_counts_write.push(0); + id + } + + pub fn get_subscriber_read_count(&self, subscription_id: usize) -> usize { + self.subscriber_last_counts.read()[subscription_id] } - /// Gets a new [ManualEventReader]. This will ignore all events already in the event buffers. It - /// will read all future events. - pub fn get_reader_current(&self) -> ManualEventReader { + pub fn set_subscriber_read_count(&self, subscription_id: usize, count: usize) { + self.subscriber_last_counts.write()[subscription_id] = count; + } + + pub fn get_reader(&self, name: &str) -> ManualEventReader { + let manual_subscriber_ids_read = self.manual_subscriber_ids.read(); + let id = if let Some(id) = manual_subscriber_ids_read.get(name) { + *id + } else { + let id = self.add_subscriber(); + drop(manual_subscriber_ids_read); + self.manual_subscriber_ids + .write() + .insert(name.to_string(), id); + id + }; ManualEventReader { - last_event_count: self.event_count, - _marker: PhantomData, + subscriber_id: id, + events: self, } } /// Swaps the event buffers and clears the oldest event buffer. In general, this should be /// called once per frame/update. pub fn update(&mut self) { - match self.state { - State::A => { - self.events_b = Vec::new(); - self.state = State::B; - self.b_start_event_count = self.event_count; - } - State::B => { - self.events_a = Vec::new(); - self.state = State::A; - self.a_start_event_count = self.event_count; - } + if self.subscriber_last_counts.read().is_empty() { + // todo: what should happen here? + } else { + let read_count = self + .subscriber_last_counts + .read() + .iter() + .fold(usize::max_value(), |count, next| min(count, *next)); + let remove_index = read_count - self.event_offset; + self.event_offset = read_count; + self.buffer.drain(0..remove_index); } } @@ -327,25 +356,15 @@ impl Events { /// Removes all events. pub fn clear(&mut self) { - self.events_a.clear(); - self.events_b.clear(); + self.buffer.clear(); + self.event_offset = self.event_count; } /// Creates a draining iterator that removes all events. pub fn drain(&mut self) -> impl Iterator + '_ { + self.event_offset = self.event_count; let map = |i: EventInstance| i.event; - match self.state { - State::A => self - .events_b - .drain(..) - .map(map) - .chain(self.events_a.drain(..).map(map)), - State::B => self - .events_a - .drain(..) - .map(map) - .chain(self.events_b.drain(..).map(map)), - } + self.buffer.drain(..).map(map) } pub fn extend(&mut self, events: I) @@ -364,16 +383,16 @@ impl Events { /// If events happen outside that window, they will not be handled. For example, any events that /// happen after this call and before the next `update()` call will be dropped. pub fn iter_current_update_events(&self) -> impl DoubleEndedIterator { - match self.state { - State::A => self.events_a.iter().map(map_instance_event), - State::B => self.events_b.iter().map(map_instance_event), - } + self.buffer.iter().map(map_instance_event) } } #[cfg(test)] mod tests { use super::*; + use bevy_ecs::schedule::{Schedule, SystemStage}; + use bevy_ecs::system::{IntoSystem, Local}; + use bevy_ecs::world::World; #[derive(Copy, Clone, PartialEq, Eq, Debug)] struct TestEvent { @@ -382,99 +401,215 @@ mod tests { #[test] fn test_events() { + fn event_writer_system1(mut event_writer: EventWriter) { + let event_0 = TestEvent { i: 0 }; + let event_1 = TestEvent { i: 1 }; + event_writer.send(event_0); + event_writer.send(event_1); + } + fn event_writer_system2(mut event_writer: EventWriter) { + let event_2 = TestEvent { i: 2 }; + event_writer.send(event_2); + } + fn event_reader_system1(mut event_reader: EventReader) { + for _event in event_reader.iter() { + // hi + } + } + + let mut schedule = Schedule::default(); + let update1 = SystemStage::single(event_writer_system1.system()); + let mut update2 = SystemStage::parallel(); + update2 + .add_system(event_reader_system1.system()) + .add_system(event_reader_system1.system()); + let update3 = SystemStage::single(event_writer_system2.system()); + let update4 = SystemStage::single(event_reader_system1.system()); + let update5 = SystemStage::single(Events::::update_system.system()); + schedule.add_stage("update1", update1); + schedule.add_stage("update2", update2); + schedule.add_stage("update3", update3); + schedule.add_stage("update4", update4); + schedule.add_stage("update5", update5); + + let mut world = World::default(); + world.insert_resource(Events::::default()); + schedule.run_once(&mut world); + let events = world.get_resource::>().unwrap(); + assert_eq!( + events.event_offset, 2, + "All subscribed systems read the first two events." + ); + + schedule.run_once(&mut world); + let events = world.get_resource::>().unwrap(); + assert_eq!( + events.event_offset, 5, + "All subscribed systems read all events from last frame plus 2 new events from this frame" + ); + } + + #[test] + fn test_manual_events() { let mut events = Events::::default(); let event_0 = TestEvent { i: 0 }; let event_1 = TestEvent { i: 1 }; let event_2 = TestEvent { i: 2 }; - // this reader will miss event_0 and event_1 because it wont read them over the course of - // two updates - let mut reader_missed = events.get_reader(); - - let mut reader_a = events.get_reader(); - events.send(event_0); + // _reader_slow sets up the subscription, even though it won't be used till later. + let _reader_slow = events.get_reader("slow"); + let reader_a = events.get_reader("a"); assert_eq!( - get_events(&events, &mut reader_a), + get_events(&reader_a), vec![event_0], "reader_a created before event receives event" ); assert_eq!( - get_events(&events, &mut reader_a), + get_events(&reader_a), vec![], "second iteration of reader_a created before event results in zero events" ); - let mut reader_b = events.get_reader(); + let reader_b = events.get_reader("b"); assert_eq!( - get_events(&events, &mut reader_b), + get_events(&reader_b), vec![event_0], "reader_b created after event receives event" ); assert_eq!( - get_events(&events, &mut reader_b), + get_events(&reader_b), vec![], "second iteration of reader_b created after event results in zero events" ); events.send(event_1); - let mut reader_c = events.get_reader(); + let reader_a = events.get_reader("a"); + let reader_c = events.get_reader("c"); assert_eq!( - get_events(&events, &mut reader_c), + get_events(&reader_c), vec![event_0, event_1], "reader_c created after two events receives both events" ); assert_eq!( - get_events(&events, &mut reader_c), + get_events(&reader_c), vec![], "second iteration of reader_c created after two event results in zero events" ); assert_eq!( - get_events(&events, &mut reader_a), + get_events(&reader_a), vec![event_1], "reader_a receives next unread event" ); events.update(); - let mut reader_d = events.get_reader(); - events.send(event_2); + let reader_a = events.get_reader("a"); + let reader_b = events.get_reader("b"); + let reader_c = events.get_reader("c"); + let reader_d = events.get_reader("d"); assert_eq!( - get_events(&events, &mut reader_a), + get_events(&reader_a), vec![event_2], "reader_a receives event created after update" ); assert_eq!( - get_events(&events, &mut reader_b), + get_events(&reader_b), vec![event_1, event_2], - "reader_b receives events created before and after update" + "reader_b receives events sent since its last read" ); assert_eq!( - get_events(&events, &mut reader_d), + get_events(&reader_c), + vec![event_2], + "reader_c receives event created since last fetch" + ); + assert_eq!( + get_events(&reader_d), vec![event_0, event_1, event_2], - "reader_d receives all events created before and after update" + "reader_d receives all events created so far because reader_slow is locking up the old events" ); events.update(); + let reader_slow = events.get_reader("slow"); assert_eq!( - get_events(&events, &mut reader_missed), - vec![event_2], - "reader_missed missed events unread after to update() calls" + get_events(&reader_slow), + vec![event_0, event_1, event_2], + "reader_slow receives all events" + ); + + events.update(); + let reader_slow = events.get_reader("slow"); + + assert_eq!( + get_events(&reader_slow), + vec![], + "reader slow has read all the events" + ); + + let slowest_reader = events.get_reader("slowest_reader"); + assert_eq!( + get_events(&slowest_reader), + vec![], + "the events have all been read, so this reader is too late" + ); + + // At this point, the event buffer should be emptied and the count and offset + // should be the same since all subscribed readers have read all the events. + assert_eq!( + events.event_count, events.event_offset, + "all subscribed readers have read all events" + ); + assert_eq!(events.buffer.is_empty(), true, "event buffer is empty"); + } + + #[test] + fn event_deferral() { + fn event_writer_system(mut event_writer: EventWriter) { + let event = TestEvent { i: 2 }; + event_writer.send(event); + } + fn event_reader_system( + mut event_reader: EventReader, + mut deferred_events: Local>, + mut event_reads: ResMut, + ) { + *event_reads = 0; + let mut defer = Vec::new(); + for event in event_reader.iter().chain(deferred_events.iter()) { + *event_reads += 1; + defer.push(*event); + } + *deferred_events = defer; + } + let mut schedule = Schedule::default(); + let update1 = SystemStage::single(event_writer_system.system()); + let update2 = SystemStage::single(event_reader_system.system()); + schedule.add_stage("update1", update1); + schedule.add_stage("update2", update2); + + let mut world = World::default(); + world.insert_resource(Events::::default()); + world.insert_resource(0usize); + schedule.run_once(&mut world); + let event_reads = world.get_resource::().unwrap(); + assert_eq!(*event_reads, 1usize, "Only one event was fired."); + schedule.run_once(&mut world); + let event_reads = world.get_resource::().unwrap(); + assert_eq!( + *event_reads, 2usize, + "One new event was fired, and one was deferred from last time." ); } - fn get_events( - events: &Events, - reader: &mut ManualEventReader, - ) -> Vec { - reader.iter(events).cloned().collect::>() + fn get_events(reader: &ManualEventReader) -> Vec { + reader.iter().cloned().collect::>() } } diff --git a/crates/bevy_app/src/schedule_runner.rs b/crates/bevy_app/src/schedule_runner.rs index 86b6dd1299be8..ba5244900da91 100644 --- a/crates/bevy_app/src/schedule_runner.rs +++ b/crates/bevy_app/src/schedule_runner.rs @@ -1,5 +1,5 @@ use super::{App, AppBuilder}; -use crate::{app::AppExit, event::Events, plugin::Plugin, ManualEventReader}; +use crate::{app::AppExit, event::Events, plugin::Plugin}; use bevy_utils::{Duration, Instant}; #[cfg(target_arch = "wasm32")] @@ -52,90 +52,83 @@ impl Plugin for ScheduleRunnerPlugin { .world_mut() .get_resource_or_insert_with(ScheduleRunnerSettings::default) .to_owned(); - app.set_runner(move |mut app: App| { - let mut app_exit_event_reader = ManualEventReader::::default(); - match settings.run_mode { - RunMode::Once => { - app.update(); - } - RunMode::Loop { wait } => { - let mut tick = move |app: &mut App, - wait: Option| - -> Result, AppExit> { - let start_time = Instant::now(); - - if let Some(app_exit_events) = - app.world.get_resource_mut::>() - { - if let Some(exit) = app_exit_event_reader.iter(&app_exit_events).last() - { - return Err(exit.clone()); - } + app.set_runner(move |mut app: App| match settings.run_mode { + RunMode::Once => { + app.update(); + } + RunMode::Loop { wait } => { + let tick = move |app: &mut App, + wait: Option| + -> Result, AppExit> { + let start_time = Instant::now(); + + if let Some(app_exit_events) = app.world.get_resource_mut::>() { + let app_exit_event_reader = app_exit_events.get_reader("app_runner"); + if let Some(exit) = app_exit_event_reader.iter().last() { + return Err(exit.clone()); } + } - app.update(); + app.update(); - if let Some(app_exit_events) = - app.world.get_resource_mut::>() - { - if let Some(exit) = app_exit_event_reader.iter(&app_exit_events).last() - { - return Err(exit.clone()); - } + if let Some(app_exit_events) = app.world.get_resource_mut::>() { + let app_exit_event_reader = app_exit_events.get_reader("app_runner"); + if let Some(exit) = app_exit_event_reader.iter().last() { + return Err(exit.clone()); } + } - let end_time = Instant::now(); + let end_time = Instant::now(); - if let Some(wait) = wait { - let exe_time = end_time - start_time; - if exe_time < wait { - return Ok(Some(wait - exe_time)); - } + if let Some(wait) = wait { + let exe_time = end_time - start_time; + if exe_time < wait { + return Ok(Some(wait - exe_time)); } + } - Ok(None) - }; + Ok(None) + }; - #[cfg(not(target_arch = "wasm32"))] - { - while let Ok(delay) = tick(&mut app, wait) { - if let Some(delay) = delay { - std::thread::sleep(delay); - } + #[cfg(not(target_arch = "wasm32"))] + { + while let Ok(delay) = tick(&mut app, wait) { + if let Some(delay) = delay { + std::thread::sleep(delay); } } + } - #[cfg(target_arch = "wasm32")] - { - fn set_timeout(f: &Closure, dur: Duration) { - web_sys::window() - .unwrap() - .set_timeout_with_callback_and_timeout_and_arguments_0( - f.as_ref().unchecked_ref(), - dur.as_millis() as i32, - ) - .expect("Should register `setTimeout`."); - } - let asap = Duration::from_millis(1); - - let mut rc = Rc::new(app); - let f = Rc::new(RefCell::new(None)); - let g = f.clone(); - - let c = move || { - let mut app = Rc::get_mut(&mut rc).unwrap(); - let delay = tick(&mut app, wait); - match delay { - Ok(delay) => { - set_timeout(f.borrow().as_ref().unwrap(), delay.unwrap_or(asap)) - } - Err(_) => {} + #[cfg(target_arch = "wasm32")] + { + fn set_timeout(f: &Closure, dur: Duration) { + web_sys::window() + .unwrap() + .set_timeout_with_callback_and_timeout_and_arguments_0( + f.as_ref().unchecked_ref(), + dur.as_millis() as i32, + ) + .expect("Should register `setTimeout`."); + } + let asap = Duration::from_millis(1); + + let mut rc = Rc::new(app); + let f = Rc::new(RefCell::new(None)); + let g = f.clone(); + + let c = move || { + let mut app = Rc::get_mut(&mut rc).unwrap(); + let delay = tick(&mut app, wait); + match delay { + Ok(delay) => { + set_timeout(f.borrow().as_ref().unwrap(), delay.unwrap_or(asap)) } - }; - *g.borrow_mut() = Some(Closure::wrap(Box::new(c) as Box)); - set_timeout(g.borrow().as_ref().unwrap(), asap); + Err(_) => {} + } }; - } + *g.borrow_mut() = Some(Closure::wrap(Box::new(c) as Box)); + set_timeout(g.borrow().as_ref().unwrap(), asap); + }; } }); } diff --git a/crates/bevy_render/src/render_graph/base.rs b/crates/bevy_render/src/render_graph/base.rs index bf7f349aaf5ed..012b77f69cd06 100644 --- a/crates/bevy_render/src/render_graph/base.rs +++ b/crates/bevy_render/src/render_graph/base.rs @@ -100,7 +100,7 @@ pub(crate) fn add_base_graph(config: &BaseRenderGraphConfig, world: &mut World) let mut graph = world.get_resource_mut::().unwrap(); let msaa = world.get_resource::().unwrap(); - graph.add_node(node::TEXTURE_COPY, TextureCopyNode::default()); + graph.add_node(node::TEXTURE_COPY, TextureCopyNode::new("texture_copy")); if config.add_3d_camera { graph.add_system_node(node::CAMERA_3D, CameraNode::new(camera::CAMERA_3D)); } diff --git a/crates/bevy_render/src/render_graph/nodes/texture_copy_node.rs b/crates/bevy_render/src/render_graph/nodes/texture_copy_node.rs index ac7c72fe843a9..726e9e4ef1aa2 100644 --- a/crates/bevy_render/src/render_graph/nodes/texture_copy_node.rs +++ b/crates/bevy_render/src/render_graph/nodes/texture_copy_node.rs @@ -3,14 +3,19 @@ use crate::{ renderer::{BufferInfo, BufferUsage, RenderContext}, texture::{Texture, TextureDescriptor, TEXTURE_ASSET_INDEX}, }; -use bevy_app::{Events, ManualEventReader}; +use bevy_app::Events; use bevy_asset::{AssetEvent, Assets}; use bevy_ecs::world::World; use bevy_utils::HashSet; -#[derive(Default)] pub struct TextureCopyNode { - pub texture_event_reader: ManualEventReader>, + pub name: &'static str, +} + +impl TextureCopyNode { + pub fn new(name: &'static str) -> Self { + TextureCopyNode { name } + } } impl Node for TextureCopyNode { @@ -24,7 +29,8 @@ impl Node for TextureCopyNode { let texture_events = world.get_resource::>>().unwrap(); let textures = world.get_resource::>().unwrap(); let mut copied_textures = HashSet::default(); - for event in self.texture_event_reader.iter(&texture_events) { + let texture_event_reader = texture_events.get_reader(self.name); + for event in texture_event_reader.iter() { match event { AssetEvent::Created { handle } | AssetEvent::Modified { handle } => { if let Some(texture) = textures.get(handle) { diff --git a/crates/bevy_render/src/render_graph/nodes/window_swapchain_node.rs b/crates/bevy_render/src/render_graph/nodes/window_swapchain_node.rs index 959f39b4a14a3..3f8fa422e6daf 100644 --- a/crates/bevy_render/src/render_graph/nodes/window_swapchain_node.rs +++ b/crates/bevy_render/src/render_graph/nodes/window_swapchain_node.rs @@ -2,26 +2,20 @@ use crate::{ render_graph::{Node, ResourceSlotInfo, ResourceSlots}, renderer::{RenderContext, RenderResourceId, RenderResourceType}, }; -use bevy_app::{Events, ManualEventReader}; +use bevy_app::Events; use bevy_ecs::world::World; use bevy_window::{WindowCreated, WindowId, WindowResized, Windows}; use std::borrow::Cow; pub struct WindowSwapChainNode { window_id: WindowId, - window_created_event_reader: ManualEventReader, - window_resized_event_reader: ManualEventReader, } impl WindowSwapChainNode { pub const OUT_TEXTURE: &'static str = "texture"; pub fn new(window_id: WindowId) -> Self { - WindowSwapChainNode { - window_id, - window_created_event_reader: Default::default(), - window_resized_event_reader: Default::default(), - } + WindowSwapChainNode { window_id } } } @@ -44,6 +38,11 @@ impl Node for WindowSwapChainNode { const WINDOW_TEXTURE: usize = 0; let window_created_events = world.get_resource::>().unwrap(); let window_resized_events = world.get_resource::>().unwrap(); + let window_created_event_reader = window_created_events + .get_reader(format!("swapchain_window_{}", self.window_id).as_str()); + let window_resized_event_reader = window_resized_events + .get_reader(format!("swapchain_window_{}", self.window_id).as_str()); + let windows = world.get_resource::().unwrap(); let window = windows @@ -53,13 +52,11 @@ impl Node for WindowSwapChainNode { let render_resource_context = render_context.resources_mut(); // create window swapchain when window is resized or created - if self - .window_created_event_reader - .iter(&window_created_events) + if window_created_event_reader + .iter() .any(|e| e.id == window.id()) - || self - .window_resized_event_reader - .iter(&window_resized_events) + || window_resized_event_reader + .iter() .any(|e| e.id == window.id()) { render_resource_context.create_swap_chain(window); diff --git a/crates/bevy_render/src/render_graph/nodes/window_texture_node.rs b/crates/bevy_render/src/render_graph/nodes/window_texture_node.rs index 8bec3b0888f29..611978aafbfaa 100644 --- a/crates/bevy_render/src/render_graph/nodes/window_texture_node.rs +++ b/crates/bevy_render/src/render_graph/nodes/window_texture_node.rs @@ -3,7 +3,7 @@ use crate::{ renderer::{RenderContext, RenderResourceId, RenderResourceType}, texture::TextureDescriptor, }; -use bevy_app::{Events, ManualEventReader}; +use bevy_app::Events; use bevy_ecs::world::World; use bevy_window::{WindowCreated, WindowId, WindowResized, Windows}; use std::borrow::Cow; @@ -11,8 +11,6 @@ use std::borrow::Cow; pub struct WindowTextureNode { window_id: WindowId, descriptor: TextureDescriptor, - window_created_event_reader: ManualEventReader, - window_resized_event_reader: ManualEventReader, } impl WindowTextureNode { @@ -22,8 +20,6 @@ impl WindowTextureNode { WindowTextureNode { window_id, descriptor, - window_created_event_reader: Default::default(), - window_resized_event_reader: Default::default(), } } } @@ -47,19 +43,21 @@ impl Node for WindowTextureNode { const WINDOW_TEXTURE: usize = 0; let window_created_events = world.get_resource::>().unwrap(); let window_resized_events = world.get_resource::>().unwrap(); + let window_created_event_reader = + window_created_events.get_reader(format!("texture_window_{}", self.window_id).as_str()); + let window_resized_event_reader = + window_resized_events.get_reader(format!("texture_window_{}", self.window_id).as_str()); let windows = world.get_resource::().unwrap(); let window = windows .get(self.window_id) .expect("Window texture node refers to a non-existent window."); - if self - .window_created_event_reader - .iter(&window_created_events) + if window_created_event_reader + .iter() .any(|e| e.id == window.id()) - || self - .window_resized_event_reader - .iter(&window_resized_events) + || window_resized_event_reader + .iter() .any(|e| e.id == window.id()) { let render_resource_context = render_context.resources_mut(); diff --git a/crates/bevy_scene/src/scene_spawner.rs b/crates/bevy_scene/src/scene_spawner.rs index 71fd41aabf638..47e5dc928f171 100644 --- a/crates/bevy_scene/src/scene_spawner.rs +++ b/crates/bevy_scene/src/scene_spawner.rs @@ -1,5 +1,5 @@ use crate::{DynamicScene, Scene}; -use bevy_app::{Events, ManualEventReader}; +use bevy_app::Events; use bevy_asset::{AssetEvent, Assets, Handle}; use bevy_ecs::{ entity::{Entity, EntityMap}, @@ -31,7 +31,6 @@ pub struct SceneSpawner { spawned_scenes: HashMap, Vec>, spawned_dynamic_scenes: HashMap, Vec>, spawned_instances: HashMap, - scene_asset_event_reader: ManualEventReader>, dynamic_scenes_to_spawn: Vec>, scenes_to_spawn: Vec<(Handle, InstanceId)>, scenes_to_despawn: Vec>, @@ -303,10 +302,8 @@ pub fn scene_spawner_system(world: &mut World) { .unwrap(); let mut updated_spawned_scenes = Vec::new(); - for event in scene_spawner - .scene_asset_event_reader - .iter(&scene_asset_events) - { + let scene_asset_event_reader = scene_asset_events.get_reader("scene_spawner_system"); + for event in scene_asset_event_reader.iter() { if let AssetEvent::Modified { handle } = event { if scene_spawner.spawned_dynamic_scenes.contains_key(handle) { updated_spawned_scenes.push(handle.clone_weak()); diff --git a/crates/bevy_sprite/src/color_material.rs b/crates/bevy_sprite/src/color_material.rs index 61c70954b832e..0c71d53803d77 100644 --- a/crates/bevy_sprite/src/color_material.rs +++ b/crates/bevy_sprite/src/color_material.rs @@ -1,4 +1,4 @@ -use bevy_app::{EventReader, Events, ManualEventReader}; +use bevy_app::{EventReader, Events}; use bevy_asset::{self, AssetEvent, Assets, Handle}; use bevy_ecs::system::{Local, Res, ResMut}; use bevy_reflect::TypeUuid; @@ -64,12 +64,10 @@ pub(crate) fn material_texture_detection_system( mut material_to_texture: Local, Handle>>, materials: Res>, mut texture_events: EventReader>, - (mut material_events_reader, mut material_events): ( - Local>>, - ResMut>>, - ), + mut material_events: ResMut>>, ) { - for event in material_events_reader.iter(&material_events) { + let material_events_reader = material_events.get_reader("material_texture_detection"); + for event in material_events_reader.iter() { match event { AssetEvent::Created { handle } => { if let Some(texture) = materials.get(handle).and_then(|mat| mat.texture.as_ref()) { diff --git a/crates/bevy_wgpu/src/wgpu_renderer.rs b/crates/bevy_wgpu/src/wgpu_renderer.rs index cdd5e3cf0f5e0..6e58b2e95ede7 100644 --- a/crates/bevy_wgpu/src/wgpu_renderer.rs +++ b/crates/bevy_wgpu/src/wgpu_renderer.rs @@ -3,21 +3,19 @@ use crate::{ wgpu_type_converter::WgpuInto, WgpuBackend, WgpuOptions, WgpuPowerOptions, }; -use bevy_app::{Events, ManualEventReader}; +use bevy_app::Events; use bevy_ecs::world::{Mut, World}; use bevy_render::{ render_graph::{DependentNodeStager, RenderGraph, RenderGraphStager}, renderer::RenderResourceContext, }; -use bevy_window::{WindowCreated, WindowResized, Windows}; +use bevy_window::{WindowCreated, Windows}; use std::{ops::Deref, sync::Arc}; pub struct WgpuRenderer { pub instance: wgpu::Instance, pub device: Arc, pub queue: wgpu::Queue, - pub window_resized_event_reader: ManualEventReader, - pub window_created_event_reader: ManualEventReader, pub initialized: bool, } @@ -67,8 +65,6 @@ impl WgpuRenderer { instance, device, queue, - window_resized_event_reader: Default::default(), - window_created_event_reader: Default::default(), initialized: false, } } @@ -83,10 +79,9 @@ impl WgpuRenderer { .unwrap(); let windows = world.get_resource::().unwrap(); let window_created_events = world.get_resource::>().unwrap(); - for window_created_event in self - .window_created_event_reader - .iter(&window_created_events) - { + let window_created_event_reader = + window_created_events.get_reader("renderer_window_created"); + for window_created_event in window_created_event_reader.iter() { let window = windows .get(window_created_event.id) .expect("Received window created event for non-existent window."); diff --git a/crates/bevy_winit/src/lib.rs b/crates/bevy_winit/src/lib.rs index 978009f4e4b77..a96844bc6be54 100644 --- a/crates/bevy_winit/src/lib.rs +++ b/crates/bevy_winit/src/lib.rs @@ -10,7 +10,7 @@ use bevy_input::{ pub use winit_config::*; pub use winit_windows::*; -use bevy_app::{App, AppBuilder, AppExit, CoreStage, Events, ManualEventReader, Plugin}; +use bevy_app::{App, AppBuilder, AppExit, CoreStage, Events, Plugin}; use bevy_ecs::{system::IntoExclusiveSystem, world::World}; use bevy_math::{ivec2, Vec2}; use bevy_utils::tracing::{error, trace, warn}; @@ -223,8 +223,6 @@ pub fn winit_runner_any_thread(app: App) { } pub fn winit_runner_with(mut app: App, mut event_loop: EventLoop<()>) { - let mut create_window_event_reader = ManualEventReader::::default(); - let mut app_exit_event_reader = ManualEventReader::::default(); app.world.insert_non_send(event_loop.create_proxy()); trace!("Entering winit event loop"); @@ -240,11 +238,8 @@ pub fn winit_runner_with(mut app: App, mut event_loop: EventLoop<()>) { *control_flow = ControlFlow::Poll; if let Some(app_exit_events) = app.world.get_resource_mut::>() { - if app_exit_event_reader - .iter(&app_exit_events) - .next_back() - .is_some() - { + let app_exit_event_reader = app_exit_events.get_reader("winit_runner"); + if app_exit_event_reader.iter().next_back().is_some() { *control_flow = ControlFlow::Exit; } } @@ -477,11 +472,7 @@ pub fn winit_runner_with(mut app: App, mut event_loop: EventLoop<()>) { }); } event::Event::MainEventsCleared => { - handle_create_window_events( - &mut app.world, - event_loop, - &mut create_window_event_reader, - ); + handle_create_window_events(&mut app.world, event_loop); app.update(); } _ => (), @@ -494,17 +485,14 @@ pub fn winit_runner_with(mut app: App, mut event_loop: EventLoop<()>) { } } -fn handle_create_window_events( - world: &mut World, - event_loop: &EventLoopWindowTarget<()>, - create_window_event_reader: &mut ManualEventReader, -) { +fn handle_create_window_events(world: &mut World, event_loop: &EventLoopWindowTarget<()>) { let world = world.cell(); let mut winit_windows = world.get_resource_mut::().unwrap(); let mut windows = world.get_resource_mut::().unwrap(); let create_window_events = world.get_resource::>().unwrap(); let mut window_created_events = world.get_resource_mut::>().unwrap(); - for create_window_event in create_window_event_reader.iter(&create_window_events) { + let create_window_event_reader = create_window_events.get_reader("create_window_events"); + for create_window_event in create_window_event_reader.iter() { let window = winit_windows.create_window( event_loop, create_window_event.id,