bevy_render/camera/
camera_driver_node.rs1use crate::{
2 camera::{ClearColor, ExtractedCamera, NormalizedRenderTarget, SortedCameras},
3 render_graph::{Node, NodeRunError, RenderGraphContext},
4 renderer::RenderContext,
5 view::ExtractedWindows,
6};
7use bevy_ecs::{prelude::QueryState, world::World};
8use bevy_utils::HashSet;
9use wgpu::{LoadOp, Operations, RenderPassColorAttachment, RenderPassDescriptor, StoreOp};
10
11pub struct CameraDriverNode {
12 cameras: QueryState<&'static ExtractedCamera>,
13}
14
15impl CameraDriverNode {
16 pub fn new(world: &mut World) -> Self {
17 Self {
18 cameras: world.query(),
19 }
20 }
21}
22
23impl Node for CameraDriverNode {
24 fn update(&mut self, world: &mut World) {
25 self.cameras.update_archetypes(world);
26 }
27 fn run(
28 &self,
29 graph: &mut RenderGraphContext,
30 render_context: &mut RenderContext,
31 world: &World,
32 ) -> Result<(), NodeRunError> {
33 let sorted_cameras = world.resource::<SortedCameras>();
34 let windows = world.resource::<ExtractedWindows>();
35 let mut camera_windows = HashSet::new();
36 for sorted_camera in &sorted_cameras.0 {
37 let Ok(camera) = self.cameras.get_manual(world, sorted_camera.entity) else {
38 continue;
39 };
40
41 let mut run_graph = true;
42 if let Some(NormalizedRenderTarget::Window(window_ref)) = camera.target {
43 let window_entity = window_ref.entity();
44 if windows
45 .windows
46 .get(&window_entity)
47 .is_some_and(|w| w.physical_width > 0 && w.physical_height > 0)
48 {
49 camera_windows.insert(window_entity);
50 } else {
51 run_graph = false;
53 }
54 }
55 if run_graph {
56 graph.run_sub_graph(camera.render_graph, vec![], Some(sorted_camera.entity))?;
57 }
58 }
59
60 let clear_color_global = world.resource::<ClearColor>();
61
62 for (id, window) in world.resource::<ExtractedWindows>().iter() {
65 if camera_windows.contains(id) {
66 continue;
67 }
68
69 let Some(swap_chain_texture) = &window.swap_chain_texture_view else {
70 continue;
71 };
72
73 #[cfg(feature = "trace")]
74 let _span = bevy_utils::tracing::info_span!("no_camera_clear_pass").entered();
75 let pass_descriptor = RenderPassDescriptor {
76 label: Some("no_camera_clear_pass"),
77 color_attachments: &[Some(RenderPassColorAttachment {
78 view: swap_chain_texture,
79 resolve_target: None,
80 ops: Operations {
81 load: LoadOp::Clear(clear_color_global.to_linear().into()),
82 store: StoreOp::Store,
83 },
84 })],
85 depth_stencil_attachment: None,
86 timestamp_writes: None,
87 occlusion_query_set: None,
88 };
89
90 render_context
91 .command_encoder()
92 .begin_render_pass(&pass_descriptor);
93 }
94
95 Ok(())
96 }
97}