Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_render/src/render_graph/camera_driver_node.rs
6596 views
1
use crate::{
2
camera::{ExtractedCamera, SortedCameras},
3
render_graph::{Node, NodeRunError, RenderGraphContext},
4
renderer::RenderContext,
5
view::ExtractedWindows,
6
};
7
use bevy_camera::{ClearColor, NormalizedRenderTarget};
8
use bevy_ecs::{entity::ContainsEntity, prelude::QueryState, world::World};
9
use bevy_platform::collections::HashSet;
10
use wgpu::{LoadOp, Operations, RenderPassColorAttachment, RenderPassDescriptor, StoreOp};
11
12
pub struct CameraDriverNode {
13
cameras: QueryState<&'static ExtractedCamera>,
14
}
15
16
impl CameraDriverNode {
17
pub fn new(world: &mut World) -> Self {
18
Self {
19
cameras: world.query(),
20
}
21
}
22
}
23
24
impl Node for CameraDriverNode {
25
fn update(&mut self, world: &mut World) {
26
self.cameras.update_archetypes(world);
27
}
28
fn run(
29
&self,
30
graph: &mut RenderGraphContext,
31
render_context: &mut RenderContext,
32
world: &World,
33
) -> Result<(), NodeRunError> {
34
let sorted_cameras = world.resource::<SortedCameras>();
35
let windows = world.resource::<ExtractedWindows>();
36
let mut camera_windows = <HashSet<_>>::default();
37
for sorted_camera in &sorted_cameras.0 {
38
let Ok(camera) = self.cameras.get_manual(world, sorted_camera.entity) else {
39
continue;
40
};
41
42
let mut run_graph = true;
43
if let Some(NormalizedRenderTarget::Window(window_ref)) = camera.target {
44
let window_entity = window_ref.entity();
45
if windows
46
.windows
47
.get(&window_entity)
48
.is_some_and(|w| w.physical_width > 0 && w.physical_height > 0)
49
{
50
camera_windows.insert(window_entity);
51
} else {
52
// The window doesn't exist anymore or zero-sized so we don't need to run the graph
53
run_graph = false;
54
}
55
}
56
if run_graph {
57
graph.run_sub_graph(camera.render_graph, vec![], Some(sorted_camera.entity))?;
58
}
59
}
60
61
let clear_color_global = world.resource::<ClearColor>();
62
63
// wgpu (and some backends) require doing work for swap chains if you call `get_current_texture()` and `present()`
64
// This ensures that Bevy doesn't crash, even when there are no cameras (and therefore no work submitted).
65
for (id, window) in world.resource::<ExtractedWindows>().iter() {
66
if camera_windows.contains(id) && render_context.has_commands() {
67
continue;
68
}
69
70
let Some(swap_chain_texture) = &window.swap_chain_texture_view else {
71
continue;
72
};
73
74
#[cfg(feature = "trace")]
75
let _span = tracing::info_span!("no_camera_clear_pass").entered();
76
let pass_descriptor = RenderPassDescriptor {
77
label: Some("no_camera_clear_pass"),
78
color_attachments: &[Some(RenderPassColorAttachment {
79
view: swap_chain_texture,
80
depth_slice: None,
81
resolve_target: None,
82
ops: Operations {
83
load: LoadOp::Clear(clear_color_global.to_linear().into()),
84
store: StoreOp::Store,
85
},
86
})],
87
depth_stencil_attachment: None,
88
timestamp_writes: None,
89
occlusion_query_set: None,
90
};
91
92
render_context
93
.command_encoder()
94
.begin_render_pass(&pass_descriptor);
95
}
96
97
Ok(())
98
}
99
}
100
101