Skip to content

Commit

Permalink
Move render runs from update() to Schedule
Browse files Browse the repository at this point in the history
  • Loading branch information
B-head committed Jun 27, 2023
1 parent 0f656a3 commit 25e2cef
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 18 deletions.
30 changes: 29 additions & 1 deletion crates/bevy_render/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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},
Expand Down Expand Up @@ -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::<MainThreadExecutor>().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
Expand Down
23 changes: 6 additions & 17 deletions crates/bevy_render/src/pipelined_rendering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<SubApp>);
Expand Down Expand Up @@ -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::<MainThreadExecutor>().cloned() else {
return;
}
};

let (app_to_render_sender, app_to_render_receiver) = async_channel::bounded::<SubApp>(1);
let (render_to_app_sender, render_to_app_receiver) = async_channel::bounded::<SubApp>(1);
Expand All @@ -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::<MainThreadExecutor>().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")]
Expand All @@ -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<MainThreadExecutor>| {
// 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.
Expand Down

0 comments on commit 25e2cef

Please sign in to comment.