Skip to content

Commit

Permalink
add ability to disable pipelined rendering
Browse files Browse the repository at this point in the history
  • Loading branch information
hymm committed Nov 9, 2022
1 parent feb4746 commit e8c5e9c
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 36 deletions.
5 changes: 3 additions & 2 deletions crates/bevy_app/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
}

Expand Down
34 changes: 31 additions & 3 deletions crates/bevy_render/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ pub mod prelude {

use globals::GlobalsPlugin;
pub use once_cell;
use pipelined_rendering::update_rendering;
use prelude::ComputedVisibility;

use crate::{
Expand All @@ -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)]
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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 =
Expand Down Expand Up @@ -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::<ComputedVisibility>::default())
.add_plugin(WindowRenderPlugin)
.add_plugin(CameraPlugin)
Expand Down
46 changes: 19 additions & 27 deletions crates/bevy_render/src/pipelined_rendering.rs
Original file line number Diff line number Diff line change
@@ -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)]
Expand All @@ -17,7 +21,12 @@ pub struct MainToRenderAppSender(pub Sender<SubApp>);
pub struct RenderToMainAppReceiver(pub Receiver<SubApp>);

/// 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::<SubApp>(1);
let (render_to_app_sender, render_to_app_receiver) = async_channel::bounded::<SubApp>(1);

Expand All @@ -31,55 +40,38 @@ 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<MainThreadExecutor>| {
ComputeTaskPool::get()
.scope(Some(main_thread_executor.0.clone()), |s| {
s.spawn(async {
let receiver = world.get_resource::<RenderToMainAppReceiver>().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()
});
})
.pop()
})
.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<MainToRenderAppSender>| {
sender.0.send_blocking(render_app).unwrap();
});
}
render_app.extract(app_world);

app_world.resource_scope(|_world, sender: Mut<MainToRenderAppSender>| {
sender.0.send_blocking(render_app).unwrap();
});
// frame pacing plugin should run here somehow. i.e. after rendering, but before input handling
}
7 changes: 3 additions & 4 deletions crates/bevy_winit/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::*;
Expand Down Expand Up @@ -349,7 +349,7 @@ pub fn winit_runner_with(mut app: App) {

let return_from_run = app.world.resource::<WinitSettings>().return_from_run;

setup_pipelined_rendering(&mut app);
setup_rendering(&mut app);

trace!("Entering winit event loop");

Expand Down Expand Up @@ -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 => {
Expand Down

0 comments on commit e8c5e9c

Please sign in to comment.