Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 48 additions & 3 deletions crates/bevy_render/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,10 @@ use batching::gpu_preprocessing::BatchingPlugin;
use bevy_app::{App, AppLabel, Plugin, SubApp};
use bevy_asset::{AssetApp, AssetServer};
use bevy_derive::Deref;
use bevy_ecs::{prelude::*, schedule::ScheduleLabel};
use bevy_ecs::{
prelude::*,
schedule::{InternedScheduleLabel, ScheduleLabel},
};
use bevy_platform::time::Instant;
use bevy_shader::{load_shader_library, Shader, ShaderLoader};
use bevy_time::TimeSender;
Expand Down Expand Up @@ -233,11 +236,48 @@ impl GpuResourceAppExt for SubApp {
}
}

/// The render recovery schedule. This schedule runs the [`Render`] schedule if
/// The render recovery schedule. This schedule runs the [`RenderScheduleOrder`] schedules if
/// we are in [`RenderState::Ready`], and is otherwise hidden from users.
#[derive(ScheduleLabel, Debug, Hash, PartialEq, Eq, Clone)]
struct RenderRecovery;

/// Defines the schedules to be run for the rendering, including their order.
#[derive(Resource, Debug)]
pub struct RenderScheduleOrder {
/// The labels to run for the rendering schedule (in the order they will be run).
pub labels: Vec<InternedScheduleLabel>,
}

impl Default for RenderScheduleOrder {
fn default() -> Self {
Self {
labels: vec![Render.intern()],
}
}
}

impl RenderScheduleOrder {
/// Adds the given `schedule` after the `after` schedule
pub fn insert_after(&mut self, after: impl ScheduleLabel, schedule: impl ScheduleLabel) {
let index = self
.labels
.iter()
.position(|current| (**current).eq(&after))
.unwrap_or_else(|| panic!("Expected {after:?} to exist"));
self.labels.insert(index + 1, schedule.intern());
}

/// Adds the given `schedule` before the `before` schedule
pub fn insert_before(&mut self, before: impl ScheduleLabel, schedule: impl ScheduleLabel) {
let index = self
.labels
.iter()
.position(|current| (**current).eq(&before))
.unwrap_or_else(|| panic!("Expected {before:?} to exist"));
self.labels.insert(index, schedule.intern());
}
}

/// The main render schedule.
#[derive(ScheduleLabel, Debug, Hash, PartialEq, Eq, Clone, Default)]
pub struct Render;
Expand Down Expand Up @@ -341,6 +381,7 @@ impl Plugin for RenderPlugin {
app.init_resource::<RenderAssetBytesPerFrame>()
.init_resource::<RenderErrorHandler>();
if let Some(render_app) = app.get_sub_app_mut(RenderApp) {
render_app.init_resource::<RenderScheduleOrder>();
render_app.init_resource::<RenderAssetBytesPerFrameLimiter>();
render_app.init_gpu_resource::<renderer::PendingCommandBuffers>();
render_app.insert_resource(sender);
Expand Down Expand Up @@ -415,7 +456,11 @@ fn renderer_is_ready(state: Res<RenderState>) -> bool {
}

fn run_render_schedule(world: &mut World) {
world.run_schedule(Render);
Copy link
Copy Markdown
Contributor

@BenjaminBrienen BenjaminBrienen Mar 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: The name of this function should probably be updated

world.resource_scope(|world, order: Mut<RenderScheduleOrder>| {
for &label in &order.labels {
let _ = world.try_run_schedule(label);
}
});
}

fn send_time(time_sender: Res<TimeSender>) {
Expand Down