Path: blob/main/crates/bevy_core_pipeline/src/schedule.rs
9367 views
//! The core rendering pipelines schedules. These schedules define the "default" render graph1//! for 2D and 3D rendering in Bevy.2//!3//! Rendering in Bevy is "camera driven", meaning that for each camera in the world, its4//! associated rendering schedule is executed. This allows different cameras to have different5//! rendering pipelines, for example a 3D camera with post-processing effects and a 2D camera6//! with a simple clear and sprite rendering.7//!8//! The [`camera_driver`] system is responsible for iterating over all cameras in the world9//! and executing their associated schedules. In this way, the schedule for each camera is a10//! sub-schedule or sub-graph of the root render graph schedule.11use bevy_camera::{ClearColor, NormalizedRenderTarget};12use bevy_ecs::{13prelude::*,14schedule::{IntoScheduleConfigs, Schedule, ScheduleLabel, SystemSet},15};16use bevy_platform::collections::HashSet;17use bevy_render::{18camera::{ExtractedCamera, SortedCameras},19render_resource::{20CommandEncoderDescriptor, LoadOp, Operations, RenderPassColorAttachment,21RenderPassDescriptor, StoreOp,22},23renderer::{CurrentView, PendingCommandBuffers, RenderDevice, RenderQueue},24view::ExtractedWindows,25};26use tracing::info_span;2728/// Schedule label for the Core 3D rendering pipeline.29#[derive(ScheduleLabel, Debug, Clone, PartialEq, Eq, Hash, Default)]30pub struct Core3d;3132/// System sets for the Core 3D rendering pipeline, defining the main stages of rendering.33/// These stages include and run in the following order:34/// - `Prepass`: Initial rendering operations, such as depth pre-pass.35/// - `MainPass`: The primary rendering operations, including drawing opaque and transparent objects.36/// - `PostProcess`: Final rendering operations, such as post-processing effects.37///38/// Additional systems can be added to these sets to customize the rendering pipeline, or additional39/// sets can be created relative to these core sets.40#[derive(SystemSet, Debug, Clone, PartialEq, Eq, Hash)]41pub enum Core3dSystems {42Prepass,43MainPass,44PostProcess,45}4647impl Core3d {48pub fn base_schedule() -> Schedule {49use bevy_ecs::schedule::ScheduleBuildSettings;50use Core3dSystems::*;5152let mut schedule = Schedule::new(Self);5354schedule.set_build_settings(ScheduleBuildSettings {55auto_insert_apply_deferred: false,56..Default::default()57});5859schedule.configure_sets((Prepass, MainPass, PostProcess).chain());6061schedule62}63}6465/// Schedule label for the Core 2D rendering pipeline.66#[derive(ScheduleLabel, Debug, Clone, PartialEq, Eq, Hash, Default)]67pub struct Core2d;6869/// System sets for the Core 2D rendering pipeline, defining the main stages of rendering.70/// These stages include and run in the following order:71/// - `MainPass`: The primary rendering operations, including drawing 2D sprites and meshes.72/// - `PostProcess`: Final rendering operations, such as post-processing effects.73///74/// Additional systems can be added to these sets to customize the rendering pipeline, or additional75/// sets can be created relative to these core sets.76#[derive(SystemSet, Debug, Clone, PartialEq, Eq, Hash)]77pub enum Core2dSystems {78MainPass,79PostProcess,80}8182impl Core2d {83pub fn base_schedule() -> Schedule {84use bevy_ecs::schedule::ScheduleBuildSettings;85use Core2dSystems::*;8687let mut schedule = Schedule::new(Self);8889schedule.set_build_settings(ScheduleBuildSettings {90auto_insert_apply_deferred: false,91..Default::default()92});9394schedule.configure_sets((MainPass, PostProcess).chain());9596schedule97}98}99100/// The default entry point for camera driven rendering added to the root [`bevy_render::renderer::RenderGraph`]101/// schedule. This system iterates over all cameras in the world, executing their associated102/// rendering schedules defined by the [`bevy_render::camera::CameraRenderGraph`] component.103///104/// After executing all camera schedules, it submits any pending command buffers to the GPU105/// and clears any swap chains that were not covered by a camera. Users can order any additional106/// operations (e.g. one-off compute passes) before or after this system in the root render107/// graph schedule.108pub fn camera_driver(world: &mut World) {109let sorted_cameras: Vec<_> = {110let sorted = world.resource::<SortedCameras>();111sorted.0.iter().map(|c| (c.entity, c.order)).collect()112};113114let mut camera_windows = HashSet::default();115116for camera in sorted_cameras {117#[cfg(feature = "trace")]118let (camera_entity, order) = camera;119#[cfg(not(feature = "trace"))]120let (camera_entity, _) = camera;121let Some(camera) = world.get::<ExtractedCamera>(camera_entity) else {122continue;123};124125let schedule = camera.schedule;126let target = camera.target.clone();127128let mut run_schedule = true;129if let Some(NormalizedRenderTarget::Window(window_ref)) = &target {130let window_entity = window_ref.entity();131let windows = world.resource::<ExtractedWindows>();132if windows133.windows134.get(&window_entity)135.is_some_and(|w| w.physical_width > 0 && w.physical_height > 0)136{137camera_windows.insert(window_entity);138} else {139run_schedule = false;140}141}142143if run_schedule {144world.insert_resource(CurrentView(camera_entity));145146#[cfg(feature = "trace")]147let _span = tracing::info_span!(148"camera_schedule",149camera = format!("Camera {} ({:?})", order, camera_entity)150)151.entered();152153world.run_schedule(schedule);154}155}156157submit_pending_command_buffers(world);158world.remove_resource::<CurrentView>();159handle_uncovered_swap_chains(world, &camera_windows);160}161162fn submit_pending_command_buffers(world: &mut World) {163let mut pending = world.resource_mut::<PendingCommandBuffers>();164let buffer_count = pending.len();165let buffers = pending.take();166167if !buffers.is_empty() {168let _span = info_span!("queue_submit", count = buffer_count).entered();169let queue = world.resource::<RenderQueue>();170queue.submit(buffers);171}172}173174fn handle_uncovered_swap_chains(world: &mut World, camera_windows: &HashSet<Entity>) {175let windows_to_clear: Vec<_> = {176let clear_color = world.resource::<ClearColor>().0.to_linear();177let windows = world.resource::<ExtractedWindows>();178179windows180.iter()181.filter_map(|(window_entity, window)| {182if camera_windows.contains(window_entity) {183return None;184}185let swap_chain_texture = window.swap_chain_texture_view.as_ref()?;186Some((swap_chain_texture.clone(), clear_color))187})188.collect()189};190191if windows_to_clear.is_empty() {192return;193}194195let render_device = world.resource::<RenderDevice>();196let render_queue = world.resource::<RenderQueue>();197198let mut encoder = render_device.create_command_encoder(&CommandEncoderDescriptor::default());199200for (swap_chain_texture, clear_color) in &windows_to_clear {201#[cfg(feature = "trace")]202let _span = tracing::info_span!("no_camera_clear_pass").entered();203204let pass_descriptor = RenderPassDescriptor {205label: Some("no_camera_clear_pass"),206color_attachments: &[Some(RenderPassColorAttachment {207view: swap_chain_texture,208depth_slice: None,209resolve_target: None,210ops: Operations {211load: LoadOp::Clear((*clear_color).into()),212store: StoreOp::Store,213},214})],215depth_stencil_attachment: None,216timestamp_writes: None,217occlusion_query_set: None,218multiview_mask: None,219};220221encoder.begin_render_pass(&pass_descriptor);222}223224render_queue.submit([encoder.finish()]);225}226227228