bevy_core_pipeline/deferred/
node.rs1use bevy_ecs::{prelude::*, query::QueryItem};
2use bevy_render::render_graph::ViewNode;
3
4use bevy_render::{
5 camera::ExtractedCamera,
6 render_graph::{NodeRunError, RenderGraphContext},
7 render_phase::{TrackedRenderPass, ViewBinnedRenderPhases},
8 render_resource::{CommandEncoderDescriptor, RenderPassDescriptor, StoreOp},
9 renderer::RenderContext,
10 view::ViewDepthTexture,
11};
12use bevy_utils::tracing::error;
13#[cfg(feature = "trace")]
14use bevy_utils::tracing::info_span;
15
16use crate::prepass::ViewPrepassTextures;
17
18use super::{AlphaMask3dDeferred, Opaque3dDeferred};
19
20#[derive(Default)]
24pub struct DeferredGBufferPrepassNode;
25
26impl ViewNode for DeferredGBufferPrepassNode {
27 type ViewQuery = (
28 Entity,
29 &'static ExtractedCamera,
30 &'static ViewDepthTexture,
31 &'static ViewPrepassTextures,
32 );
33
34 fn run<'w>(
35 &self,
36 graph: &mut RenderGraphContext,
37 render_context: &mut RenderContext<'w>,
38 (view, camera, view_depth_texture, view_prepass_textures): QueryItem<'w, Self::ViewQuery>,
39 world: &'w World,
40 ) -> Result<(), NodeRunError> {
41 let (Some(opaque_deferred_phases), Some(alpha_mask_deferred_phases)) = (
42 world.get_resource::<ViewBinnedRenderPhases<Opaque3dDeferred>>(),
43 world.get_resource::<ViewBinnedRenderPhases<AlphaMask3dDeferred>>(),
44 ) else {
45 return Ok(());
46 };
47
48 let (Some(opaque_deferred_phase), Some(alpha_mask_deferred_phase)) = (
49 opaque_deferred_phases.get(&view),
50 alpha_mask_deferred_phases.get(&view),
51 ) else {
52 return Ok(());
53 };
54
55 let mut color_attachments = vec![];
56 color_attachments.push(
57 view_prepass_textures
58 .normal
59 .as_ref()
60 .map(|normals_texture| normals_texture.get_attachment()),
61 );
62 color_attachments.push(
63 view_prepass_textures
64 .motion_vectors
65 .as_ref()
66 .map(|motion_vectors_texture| motion_vectors_texture.get_attachment()),
67 );
68
69 #[cfg(all(feature = "webgl", target_arch = "wasm32", not(feature = "webgpu")))]
75 if let Some(deferred_texture) = &view_prepass_textures.deferred {
76 render_context.command_encoder().clear_texture(
77 &deferred_texture.texture.texture,
78 &bevy_render::render_resource::ImageSubresourceRange::default(),
79 );
80 }
81
82 color_attachments.push(
83 view_prepass_textures
84 .deferred
85 .as_ref()
86 .map(|deferred_texture| {
87 #[cfg(all(feature = "webgl", target_arch = "wasm32", not(feature = "webgpu")))]
88 {
89 bevy_render::render_resource::RenderPassColorAttachment {
90 view: &deferred_texture.texture.default_view,
91 resolve_target: None,
92 ops: bevy_render::render_resource::Operations {
93 load: bevy_render::render_resource::LoadOp::Load,
94 store: StoreOp::Store,
95 },
96 }
97 }
98 #[cfg(any(
99 not(feature = "webgl"),
100 not(target_arch = "wasm32"),
101 feature = "webgpu"
102 ))]
103 deferred_texture.get_attachment()
104 }),
105 );
106
107 color_attachments.push(
108 view_prepass_textures
109 .deferred_lighting_pass_id
110 .as_ref()
111 .map(|deferred_lighting_pass_id| deferred_lighting_pass_id.get_attachment()),
112 );
113
114 if color_attachments.iter().all(Option::is_none) {
116 color_attachments.clear();
117 }
118
119 let depth_stencil_attachment = Some(view_depth_texture.get_attachment(StoreOp::Store));
120
121 let view_entity = graph.view_entity();
122 render_context.add_command_buffer_generation_task(move |render_device| {
123 #[cfg(feature = "trace")]
124 let _deferred_span = info_span!("deferred_prepass").entered();
125
126 let mut command_encoder =
128 render_device.create_command_encoder(&CommandEncoderDescriptor {
129 label: Some("deferred_prepass_command_encoder"),
130 });
131
132 let render_pass = command_encoder.begin_render_pass(&RenderPassDescriptor {
134 label: Some("deferred_prepass"),
135 color_attachments: &color_attachments,
136 depth_stencil_attachment,
137 timestamp_writes: None,
138 occlusion_query_set: None,
139 });
140 let mut render_pass = TrackedRenderPass::new(&render_device, render_pass);
141 if let Some(viewport) = camera.viewport.as_ref() {
142 render_pass.set_camera_viewport(viewport);
143 }
144
145 if !opaque_deferred_phase.batchable_mesh_keys.is_empty()
147 || !opaque_deferred_phase.unbatchable_mesh_keys.is_empty()
148 {
149 #[cfg(feature = "trace")]
150 let _opaque_prepass_span = info_span!("opaque_deferred_prepass").entered();
151 if let Err(err) = opaque_deferred_phase.render(&mut render_pass, world, view_entity)
152 {
153 error!("Error encountered while rendering the opaque deferred phase {err:?}");
154 }
155 }
156
157 if !alpha_mask_deferred_phase.is_empty() {
159 #[cfg(feature = "trace")]
160 let _alpha_mask_deferred_span = info_span!("alpha_mask_deferred_prepass").entered();
161 if let Err(err) =
162 alpha_mask_deferred_phase.render(&mut render_pass, world, view_entity)
163 {
164 error!(
165 "Error encountered while rendering the alpha mask deferred phase {err:?}"
166 );
167 }
168 }
169
170 drop(render_pass);
171
172 if let Some(prepass_depth_texture) = &view_prepass_textures.depth {
174 command_encoder.copy_texture_to_texture(
175 view_depth_texture.texture.as_image_copy(),
176 prepass_depth_texture.texture.texture.as_image_copy(),
177 view_prepass_textures.size,
178 );
179 }
180
181 command_encoder.finish()
182 });
183
184 Ok(())
185 }
186}