diff --git a/crates/bevy_app/src/app.rs b/crates/bevy_app/src/app.rs index ad9a8a984fda20..7ea8c04706d9ef 100644 --- a/crates/bevy_app/src/app.rs +++ b/crates/bevy_app/src/app.rs @@ -161,10 +161,11 @@ impl App { /// See [`add_sub_app`](Self::add_sub_app) and [`run_once`](Schedule::run_once) for more details. pub fn update(&mut self) { #[cfg(feature = "trace")] - let _bevy_frame_update_span = info_span!("frame").entered(); + let _bevy_frame_update_span = info_span!("main_app").entered(); self.schedule.run(&mut self.world); for sub_app in self.sub_apps.values_mut() { - (sub_app.extract)(&mut self.world, &mut sub_app.app); + sub_app.extract(&mut self.world); + sub_app.run(); } } diff --git a/crates/bevy_render/src/lib.rs b/crates/bevy_render/src/lib.rs index 35a09a4f4fe5ae..0d41e357776c50 100644 --- a/crates/bevy_render/src/lib.rs +++ b/crates/bevy_render/src/lib.rs @@ -39,6 +39,7 @@ pub mod prelude { use globals::GlobalsPlugin; pub use once_cell; +use pipelined_rendering::update_rendering; use prelude::ComputedVisibility; use crate::{ @@ -61,8 +62,20 @@ use std::{ }; /// Contains the default Bevy rendering backend based on wgpu. -#[derive(Default)] -pub struct RenderPlugin; +pub struct RenderPlugin { + pub use_pipelined_rendering: bool, +} + +impl Default for RenderPlugin { + fn default() -> Self { + RenderPlugin { + #[cfg(not(target_arch = "wasm32"))] + use_pipelined_rendering: true, + #[cfg(target_arch = "wasm32")] + use_pipelined_rendering: false, + } + } +} /// The labels of the default App rendering stages. #[derive(Debug, Hash, PartialEq, Eq, Clone, StageLabel)] @@ -127,6 +140,10 @@ pub mod main_graph { #[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, AppLabel)] pub struct RenderApp; +/// A Label for the sub app that runs the parts of pipelined rendering that need to run on the main thread. +#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, AppLabel)] +pub struct PipelinedRenderingApp; + impl Plugin for RenderPlugin { /// Initializes the renderer, sets up the [`RenderStage`](RenderStage) and creates the rendering sub-app. fn build(&self, app: &mut App) { @@ -220,7 +237,7 @@ impl Plugin for RenderPlugin { app.add_sub_app(RenderApp, render_app, move |app_world, render_app| { #[cfg(feature = "trace")] - let _render_span = bevy_utils::tracing::info_span!("renderer subapp").entered(); + let _render_span = bevy_utils::tracing::info_span!("extract").entered(); { #[cfg(feature = "trace")] let _stage_span = @@ -329,6 +346,17 @@ impl Plugin for RenderPlugin { }); } + if self.use_pipelined_rendering { + app.add_sub_app( + PipelinedRenderingApp, + App::new(), + |app_world, _render_app| { + update_rendering(app_world); + }, + |_render_world| {}, + ); + } + app.add_plugin(ValidParentCheckPlugin::::default()) .add_plugin(WindowRenderPlugin) .add_plugin(CameraPlugin) diff --git a/crates/bevy_render/src/pipelined_rendering.rs b/crates/bevy_render/src/pipelined_rendering.rs index 31bb22aea2ee47..3227cb014adb5a 100644 --- a/crates/bevy_render/src/pipelined_rendering.rs +++ b/crates/bevy_render/src/pipelined_rendering.rs @@ -1,12 +1,16 @@ use async_channel::{Receiver, Sender}; use bevy_app::{App, SubApp}; -use bevy_ecs::{schedule::MainThreadExecutor, system::Resource, world::Mut}; +use bevy_ecs::{ + schedule::MainThreadExecutor, + system::Resource, + world::{Mut, World}, +}; use bevy_tasks::ComputeTaskPool; #[cfg(feature = "trace")] use bevy_utils::tracing::Instrument; -use crate::RenderApp; +use crate::{PipelinedRenderingApp, RenderApp}; /// Resource to be used for pipelined rendering for sending the render app from the main thread to the rendering thread #[derive(Resource)] @@ -17,7 +21,12 @@ pub struct MainToRenderAppSender(pub Sender); pub struct RenderToMainAppReceiver(pub Receiver); /// sets up the render thread and insert resource into the main app for controlling the render thread -pub fn setup_pipelined_rendering(app: &mut App) { +pub fn setup_rendering(app: &mut App) { + // skip this if pipelined rendering is not enabled + if app.get_sub_app(PipelinedRenderingApp).is_err() { + return; + } + let (app_to_render_sender, app_to_render_receiver) = async_channel::bounded::(1); let (render_to_app_sender, render_to_app_receiver) = async_channel::bounded::(1); @@ -31,38 +40,27 @@ pub fn setup_pipelined_rendering(app: &mut App) { loop { // TODO: exit loop when app is exited let recv_task = app_to_render_receiver.recv(); - #[cfg(feature = "trace")] - let span = bevy_utils::tracing::info_span!("receive render world from main"); - #[cfg(feature = "trace")] - let recv_task = recv_task.instrument(span); let mut sub_app = recv_task.await.unwrap(); sub_app.run(); render_to_app_sender.send(sub_app).await.unwrap(); } }; #[cfg(feature = "trace")] - let span = bevy_utils::tracing::info_span!("render task"); + let span = bevy_utils::tracing::info_span!("render app"); #[cfg(feature = "trace")] let render_task = render_task.instrument(span); ComputeTaskPool::get().spawn(render_task).detach(); } -pub fn update_rendering(app: &mut App) { - app.update(); - +pub fn update_rendering(app_world: &mut World) { // wait to get the render app back to signal that rendering is finished - let mut render_app = app - .world + let mut render_app = app_world .resource_scope(|world, main_thread_executor: Mut| { ComputeTaskPool::get() .scope(Some(main_thread_executor.0.clone()), |s| { s.spawn(async { let receiver = world.get_resource::().unwrap(); let recv = receiver.0.recv(); - #[cfg(feature = "trace")] - let span = bevy_utils::tracing::info_span!("wait for render"); - #[cfg(feature = "trace")] - let recv = recv.instrument(span); recv.await.unwrap() }); }) @@ -70,16 +68,10 @@ pub fn update_rendering(app: &mut App) { }) .unwrap(); - render_app.extract(&mut app.world); - - { - #[cfg(feature = "trace")] - let _span = bevy_utils::tracing::info_span!("send world to render").entered(); - app.world - .resource_scope(|_world, sender: Mut| { - sender.0.send_blocking(render_app).unwrap(); - }); - } + render_app.extract(app_world); + app_world.resource_scope(|_world, sender: Mut| { + sender.0.send_blocking(render_app).unwrap(); + }); // frame pacing plugin should run here somehow. i.e. after rendering, but before input handling } diff --git a/crates/bevy_winit/src/lib.rs b/crates/bevy_winit/src/lib.rs index c459a0bf3d3a55..3cc364a2d5113b 100644 --- a/crates/bevy_winit/src/lib.rs +++ b/crates/bevy_winit/src/lib.rs @@ -4,7 +4,7 @@ mod web_resize; mod winit_config; mod winit_windows; -use bevy_render::pipelined_rendering::{setup_pipelined_rendering, update_rendering}; +use bevy_render::pipelined_rendering::setup_rendering; use converters::convert_cursor_grab_mode; pub use winit_config::*; pub use winit_windows::*; @@ -349,7 +349,7 @@ pub fn winit_runner_with(mut app: App) { let return_from_run = app.world.resource::().return_from_run; - setup_pipelined_rendering(&mut app); + setup_rendering(&mut app); trace!("Entering winit event loop"); @@ -592,8 +592,7 @@ pub fn winit_runner_with(mut app: App) { }; if update { winit_state.last_update = Instant::now(); - update_rendering(&mut app); - // app.update(); + app.update(); } } Event::RedrawEventsCleared => {