Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Merged by Bors] - Update time by sending frame instant through a channel #4744

Closed
wants to merge 14 commits into from
1 change: 1 addition & 0 deletions crates/bevy_render/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ bevy_math = { path = "../bevy_math", version = "0.8.0-dev" }
bevy_mikktspace = { path = "../bevy_mikktspace", version = "0.8.0-dev" }
bevy_reflect = { path = "../bevy_reflect", version = "0.8.0-dev", features = ["bevy"] }
bevy_render_macros = { path = "macros", version = "0.8.0-dev" }
bevy_time = { path = "../bevy_time", version = "0.8.0-dev" }
bevy_transform = { path = "../bevy_transform", version = "0.8.0-dev" }
bevy_window = { path = "../bevy_window", version = "0.8.0-dev" }
bevy_utils = { path = "../bevy_utils", version = "0.8.0-dev" }
Expand Down
4 changes: 4 additions & 0 deletions crates/bevy_render/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,10 @@ impl Plugin for RenderPlugin {
.insert_resource(asset_server)
.init_resource::<RenderGraph>();

let (sender, receiver) = bevy_time::create_time_channels();
app.insert_resource(receiver);
render_app.insert_resource(sender);

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();
Expand Down
8 changes: 8 additions & 0 deletions crates/bevy_render/src/renderer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ use crate::{
view::{ExtractedWindows, ViewTarget},
};
use bevy_ecs::prelude::*;
use bevy_time::TimeSender;
use bevy_utils::Instant;
use std::sync::Arc;
use wgpu::{AdapterInfo, CommandEncoder, Instance, Queue, RequestAdapterOptions};

Expand Down Expand Up @@ -73,6 +75,12 @@ pub fn render_system(world: &mut World) {
tracy.frame_mark = true
);
}

// update the time and send it to the app world
let time_sender = world.resource::<TimeSender>();
time_sender.0.try_send(Instant::now()).expect(
"The TimeSender channel should always be empty during render. You might need to add the bevy::core::time_system to your app.",
);
}

/// This queue is used to enqueue tasks for the GPU to execute asynchronously.
Expand Down
3 changes: 3 additions & 0 deletions crates/bevy_time/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,6 @@ bevy_app = { path = "../bevy_app", version = "0.8.0-dev" }
bevy_ecs = { path = "../bevy_ecs", version = "0.8.0-dev", features = ["bevy_reflect"] }
bevy_reflect = { path = "../bevy_reflect", version = "0.8.0-dev", features = ["bevy"] }
bevy_utils = { path = "../bevy_utils", version = "0.8.0-dev" }

# other
crossbeam-channel = "0.5.0"
37 changes: 35 additions & 2 deletions crates/bevy_time/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ pub use stopwatch::*;
pub use time::*;
pub use timer::*;

use bevy_ecs::system::{Local, Res, ResMut};
use bevy_utils::{tracing::warn, Instant};
use crossbeam_channel::{Receiver, Sender};

pub mod prelude {
//! The Bevy Time Prelude.
#[doc(hidden)]
Expand Down Expand Up @@ -41,6 +45,35 @@ impl Plugin for TimePlugin {
}
}

fn time_system(mut time: ResMut<Time>) {
time.update();
/// Channel resource used to receive time from render world
pub struct TimeReceiver(pub Receiver<Instant>);
/// Channel resource used to send time from render world
pub struct TimeSender(pub Sender<Instant>);

/// Creates channels used for sending time between render world and app world
pub fn create_time_channels() -> (TimeSender, TimeReceiver) {
// bound the channel to 2 since when pipelined the render phase can finish before
// the time system runs.
let (s, r) = crossbeam_channel::bounded::<Instant>(2);
(TimeSender(s), TimeReceiver(r))
}

/// The system used to update the [`Time`] used by app logic. If there is a render world the time is sent from
/// there to this system through channels. Otherwise the time is updated in this system.
fn time_system(
mut time: ResMut<Time>,
time_recv: Option<Res<TimeReceiver>>,
mut has_received_time: Local<bool>,
) {
if let Some(time_recv) = time_recv {
// TODO: Figure out how to handle this when using pipelined rendering.
if let Ok(new_time) = time_recv.0.try_recv() {
time.update_with_instant(new_time);
*has_received_time = true;
} else if *has_received_time {
warn!("time_system did not receive the time from the render world! Calculations depending on the time may be incorrect.");
}
} else {
time.update();
}
}