Skip to content
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();
}
}