From 25e2cefa88a430f58b5ce581cb7fbbb0dbff90a9 Mon Sep 17 00:00:00 2001 From: B_head Date: Mon, 26 Jun 2023 07:41:11 +0900 Subject: [PATCH] Move render runs from `update()` to `Schedule` --- crates/bevy_render/src/lib.rs | 30 ++++++++++++++++++- crates/bevy_render/src/pipelined_rendering.rs | 23 ++++---------- 2 files changed, 35 insertions(+), 18 deletions(-) diff --git a/crates/bevy_render/src/lib.rs b/crates/bevy_render/src/lib.rs index de977b24cadd1..8df96b7292259 100644 --- a/crates/bevy_render/src/lib.rs +++ b/crates/bevy_render/src/lib.rs @@ -57,7 +57,11 @@ use crate::{ }; use bevy_app::{App, AppLabel, Plugin, Render, SubApp}; use bevy_asset::{AddAsset, AssetServer}; -use bevy_ecs::{prelude::*, schedule::ScheduleLabel, system::SystemState}; +use bevy_ecs::{ + prelude::*, + schedule::{MainThreadExecutor, ScheduleLabel}, + system::SystemState, +}; use bevy_utils::tracing::debug; use std::{ ops::{Deref, DerefMut}, @@ -372,6 +376,30 @@ impl Plugin for RenderPlugin { .insert_resource(adapter_info); } } + + fn cleanup(&self, app: &mut App) { + // skip setting up when No backend is used + if self.wgpu_settings.backends.is_none() { + return; + } + + // skip setting up when using PipelinedRenderingPlugin + if app.world.get_resource::().is_some() { + return; + }; + + let mut render_app = app + .remove_sub_app(RenderApp) + .expect("Unable to get RenderApp. Another plugin may have removed the RenderApp before RenderPlugin"); + + app.add_systems(Render, move |world: &mut World| { + #[cfg(feature = "trace")] + let _sub_app_span = + bevy_utils::tracing::info_span!("sub app", name = ?RenderApp).entered(); + render_app.extract(world); + render_app.run(); + }); + } } /// A "scratch" world used to avoid allocating new worlds every frame when diff --git a/crates/bevy_render/src/pipelined_rendering.rs b/crates/bevy_render/src/pipelined_rendering.rs index b4f9acd73ca19..b604a03f0ac28 100644 --- a/crates/bevy_render/src/pipelined_rendering.rs +++ b/crates/bevy_render/src/pipelined_rendering.rs @@ -10,13 +10,6 @@ use bevy_tasks::ComputeTaskPool; use crate::RenderApp; -/// A Label for the sub app that runs the parts of pipelined rendering that need to run on the main thread. -/// -/// The Main schedule of this app can be used to run logic after the render schedule starts, but -/// before I/O processing. This can be useful for something like frame pacing. -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, AppLabel)] -pub struct RenderExtractApp; - /// Channel to send the render app from the main thread to the rendering thread #[derive(Resource)] pub struct MainToRenderAppSender(pub Sender); @@ -70,18 +63,15 @@ impl Plugin for PipelinedRenderingPlugin { return; } app.insert_resource(MainThreadExecutor::new()); - - let mut sub_app = App::empty(); - sub_app.init_schedule(Main); - app.insert_sub_app(RenderExtractApp, SubApp::new(sub_app, update_rendering)); } // Sets up the render thread and inserts resources into the main app used for controlling the render thread. fn cleanup(&self, app: &mut App) { // skip setting up when headless - if app.get_sub_app(RenderExtractApp).is_err() { + // clone main thread executor to render world + let Some(executor) = app.world.get_resource::().cloned() else { 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); @@ -90,14 +80,13 @@ impl Plugin for PipelinedRenderingPlugin { .remove_sub_app(RenderApp) .expect("Unable to get RenderApp. Another plugin may have removed the RenderApp before PipelinedRenderingPlugin"); - // clone main thread executor to render world - let executor = app.world.get_resource::().unwrap(); - render_app.app.world.insert_resource(executor.clone()); + render_app.app.world.insert_resource(executor); render_to_app_sender.send_blocking(render_app).unwrap(); app.insert_resource(MainToRenderAppSender(app_to_render_sender)); app.insert_resource(RenderToMainAppReceiver(render_to_app_receiver)); + app.add_systems(Render, update_rendering); std::thread::spawn(move || { #[cfg(feature = "trace")] @@ -124,7 +113,7 @@ impl Plugin for PipelinedRenderingPlugin { // This function waits for the rendering world to be received, // runs extract, and then sends the rendering world back to the render thread. -fn update_rendering(app_world: &mut World, _sub_app: &mut App) { +fn update_rendering(app_world: &mut World) { app_world.resource_scope(|world, main_thread_executor: Mut| { // we use a scope here to run any main thread tasks that the render world still needs to run // while we wait for the render world to be received.