Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_core_pipeline/src/schedule.rs
9367 views
1
//! The core rendering pipelines schedules. These schedules define the "default" render graph
2
//! for 2D and 3D rendering in Bevy.
3
//!
4
//! Rendering in Bevy is "camera driven", meaning that for each camera in the world, its
5
//! associated rendering schedule is executed. This allows different cameras to have different
6
//! rendering pipelines, for example a 3D camera with post-processing effects and a 2D camera
7
//! with a simple clear and sprite rendering.
8
//!
9
//! The [`camera_driver`] system is responsible for iterating over all cameras in the world
10
//! and executing their associated schedules. In this way, the schedule for each camera is a
11
//! sub-schedule or sub-graph of the root render graph schedule.
12
use bevy_camera::{ClearColor, NormalizedRenderTarget};
13
use bevy_ecs::{
14
prelude::*,
15
schedule::{IntoScheduleConfigs, Schedule, ScheduleLabel, SystemSet},
16
};
17
use bevy_platform::collections::HashSet;
18
use bevy_render::{
19
camera::{ExtractedCamera, SortedCameras},
20
render_resource::{
21
CommandEncoderDescriptor, LoadOp, Operations, RenderPassColorAttachment,
22
RenderPassDescriptor, StoreOp,
23
},
24
renderer::{CurrentView, PendingCommandBuffers, RenderDevice, RenderQueue},
25
view::ExtractedWindows,
26
};
27
use tracing::info_span;
28
29
/// Schedule label for the Core 3D rendering pipeline.
30
#[derive(ScheduleLabel, Debug, Clone, PartialEq, Eq, Hash, Default)]
31
pub struct Core3d;
32
33
/// System sets for the Core 3D rendering pipeline, defining the main stages of rendering.
34
/// These stages include and run in the following order:
35
/// - `Prepass`: Initial rendering operations, such as depth pre-pass.
36
/// - `MainPass`: The primary rendering operations, including drawing opaque and transparent objects.
37
/// - `PostProcess`: Final rendering operations, such as post-processing effects.
38
///
39
/// Additional systems can be added to these sets to customize the rendering pipeline, or additional
40
/// sets can be created relative to these core sets.
41
#[derive(SystemSet, Debug, Clone, PartialEq, Eq, Hash)]
42
pub enum Core3dSystems {
43
Prepass,
44
MainPass,
45
PostProcess,
46
}
47
48
impl Core3d {
49
pub fn base_schedule() -> Schedule {
50
use bevy_ecs::schedule::ScheduleBuildSettings;
51
use Core3dSystems::*;
52
53
let mut schedule = Schedule::new(Self);
54
55
schedule.set_build_settings(ScheduleBuildSettings {
56
auto_insert_apply_deferred: false,
57
..Default::default()
58
});
59
60
schedule.configure_sets((Prepass, MainPass, PostProcess).chain());
61
62
schedule
63
}
64
}
65
66
/// Schedule label for the Core 2D rendering pipeline.
67
#[derive(ScheduleLabel, Debug, Clone, PartialEq, Eq, Hash, Default)]
68
pub struct Core2d;
69
70
/// System sets for the Core 2D rendering pipeline, defining the main stages of rendering.
71
/// These stages include and run in the following order:
72
/// - `MainPass`: The primary rendering operations, including drawing 2D sprites and meshes.
73
/// - `PostProcess`: Final rendering operations, such as post-processing effects.
74
///
75
/// Additional systems can be added to these sets to customize the rendering pipeline, or additional
76
/// sets can be created relative to these core sets.
77
#[derive(SystemSet, Debug, Clone, PartialEq, Eq, Hash)]
78
pub enum Core2dSystems {
79
MainPass,
80
PostProcess,
81
}
82
83
impl Core2d {
84
pub fn base_schedule() -> Schedule {
85
use bevy_ecs::schedule::ScheduleBuildSettings;
86
use Core2dSystems::*;
87
88
let mut schedule = Schedule::new(Self);
89
90
schedule.set_build_settings(ScheduleBuildSettings {
91
auto_insert_apply_deferred: false,
92
..Default::default()
93
});
94
95
schedule.configure_sets((MainPass, PostProcess).chain());
96
97
schedule
98
}
99
}
100
101
/// The default entry point for camera driven rendering added to the root [`bevy_render::renderer::RenderGraph`]
102
/// schedule. This system iterates over all cameras in the world, executing their associated
103
/// rendering schedules defined by the [`bevy_render::camera::CameraRenderGraph`] component.
104
///
105
/// After executing all camera schedules, it submits any pending command buffers to the GPU
106
/// and clears any swap chains that were not covered by a camera. Users can order any additional
107
/// operations (e.g. one-off compute passes) before or after this system in the root render
108
/// graph schedule.
109
pub fn camera_driver(world: &mut World) {
110
let sorted_cameras: Vec<_> = {
111
let sorted = world.resource::<SortedCameras>();
112
sorted.0.iter().map(|c| (c.entity, c.order)).collect()
113
};
114
115
let mut camera_windows = HashSet::default();
116
117
for camera in sorted_cameras {
118
#[cfg(feature = "trace")]
119
let (camera_entity, order) = camera;
120
#[cfg(not(feature = "trace"))]
121
let (camera_entity, _) = camera;
122
let Some(camera) = world.get::<ExtractedCamera>(camera_entity) else {
123
continue;
124
};
125
126
let schedule = camera.schedule;
127
let target = camera.target.clone();
128
129
let mut run_schedule = true;
130
if let Some(NormalizedRenderTarget::Window(window_ref)) = &target {
131
let window_entity = window_ref.entity();
132
let windows = world.resource::<ExtractedWindows>();
133
if windows
134
.windows
135
.get(&window_entity)
136
.is_some_and(|w| w.physical_width > 0 && w.physical_height > 0)
137
{
138
camera_windows.insert(window_entity);
139
} else {
140
run_schedule = false;
141
}
142
}
143
144
if run_schedule {
145
world.insert_resource(CurrentView(camera_entity));
146
147
#[cfg(feature = "trace")]
148
let _span = tracing::info_span!(
149
"camera_schedule",
150
camera = format!("Camera {} ({:?})", order, camera_entity)
151
)
152
.entered();
153
154
world.run_schedule(schedule);
155
}
156
}
157
158
submit_pending_command_buffers(world);
159
world.remove_resource::<CurrentView>();
160
handle_uncovered_swap_chains(world, &camera_windows);
161
}
162
163
fn submit_pending_command_buffers(world: &mut World) {
164
let mut pending = world.resource_mut::<PendingCommandBuffers>();
165
let buffer_count = pending.len();
166
let buffers = pending.take();
167
168
if !buffers.is_empty() {
169
let _span = info_span!("queue_submit", count = buffer_count).entered();
170
let queue = world.resource::<RenderQueue>();
171
queue.submit(buffers);
172
}
173
}
174
175
fn handle_uncovered_swap_chains(world: &mut World, camera_windows: &HashSet<Entity>) {
176
let windows_to_clear: Vec<_> = {
177
let clear_color = world.resource::<ClearColor>().0.to_linear();
178
let windows = world.resource::<ExtractedWindows>();
179
180
windows
181
.iter()
182
.filter_map(|(window_entity, window)| {
183
if camera_windows.contains(window_entity) {
184
return None;
185
}
186
let swap_chain_texture = window.swap_chain_texture_view.as_ref()?;
187
Some((swap_chain_texture.clone(), clear_color))
188
})
189
.collect()
190
};
191
192
if windows_to_clear.is_empty() {
193
return;
194
}
195
196
let render_device = world.resource::<RenderDevice>();
197
let render_queue = world.resource::<RenderQueue>();
198
199
let mut encoder = render_device.create_command_encoder(&CommandEncoderDescriptor::default());
200
201
for (swap_chain_texture, clear_color) in &windows_to_clear {
202
#[cfg(feature = "trace")]
203
let _span = tracing::info_span!("no_camera_clear_pass").entered();
204
205
let pass_descriptor = RenderPassDescriptor {
206
label: Some("no_camera_clear_pass"),
207
color_attachments: &[Some(RenderPassColorAttachment {
208
view: swap_chain_texture,
209
depth_slice: None,
210
resolve_target: None,
211
ops: Operations {
212
load: LoadOp::Clear((*clear_color).into()),
213
store: StoreOp::Store,
214
},
215
})],
216
depth_stencil_attachment: None,
217
timestamp_writes: None,
218
occlusion_query_set: None,
219
multiview_mask: None,
220
};
221
222
encoder.begin_render_pass(&pass_descriptor);
223
}
224
225
render_queue.submit([encoder.finish()]);
226
}
227
228