bevy_core_pipeline/deferred/
node.rs1use bevy_camera::{MainPassResolutionOverride, Viewport};
2use bevy_ecs::{prelude::*, query::QueryItem};
3use bevy_render::experimental::occlusion_culling::OcclusionCulling;
4use bevy_render::render_graph::ViewNode;
5
6use bevy_render::view::{ExtractedView, NoIndirectDrawing};
7use bevy_render::{
8 camera::ExtractedCamera,
9 diagnostic::RecordDiagnostics,
10 render_graph::{NodeRunError, RenderGraphContext},
11 render_phase::{TrackedRenderPass, ViewBinnedRenderPhases},
12 render_resource::{CommandEncoderDescriptor, RenderPassDescriptor, StoreOp},
13 renderer::RenderContext,
14 view::ViewDepthTexture,
15};
16use tracing::error;
17#[cfg(feature = "trace")]
18use tracing::info_span;
19
20use crate::prepass::ViewPrepassTextures;
21
22use super::{AlphaMask3dDeferred, Opaque3dDeferred};
23
24#[derive(Default)]
32pub struct EarlyDeferredGBufferPrepassNode;
33
34impl ViewNode for EarlyDeferredGBufferPrepassNode {
35 type ViewQuery = <LateDeferredGBufferPrepassNode as ViewNode>::ViewQuery;
36
37 fn run<'w>(
38 &self,
39 graph: &mut RenderGraphContext,
40 render_context: &mut RenderContext<'w>,
41 view_query: QueryItem<'w, '_, Self::ViewQuery>,
42 world: &'w World,
43 ) -> Result<(), NodeRunError> {
44 run_deferred_prepass(
45 graph,
46 render_context,
47 view_query,
48 false,
49 world,
50 "early deferred prepass",
51 )
52 }
53}
54
55#[derive(Default)]
63pub struct LateDeferredGBufferPrepassNode;
64
65impl ViewNode for LateDeferredGBufferPrepassNode {
66 type ViewQuery = (
67 &'static ExtractedCamera,
68 &'static ExtractedView,
69 &'static ViewDepthTexture,
70 &'static ViewPrepassTextures,
71 Option<&'static MainPassResolutionOverride>,
72 Has<OcclusionCulling>,
73 Has<NoIndirectDrawing>,
74 );
75
76 fn run<'w>(
77 &self,
78 graph: &mut RenderGraphContext,
79 render_context: &mut RenderContext<'w>,
80 view_query: QueryItem<'w, '_, Self::ViewQuery>,
81 world: &'w World,
82 ) -> Result<(), NodeRunError> {
83 let (.., occlusion_culling, no_indirect_drawing) = view_query;
84 if !occlusion_culling || no_indirect_drawing {
85 return Ok(());
86 }
87
88 run_deferred_prepass(
89 graph,
90 render_context,
91 view_query,
92 true,
93 world,
94 "late deferred prepass",
95 )
96 }
97}
98
99fn run_deferred_prepass<'w>(
109 graph: &mut RenderGraphContext,
110 render_context: &mut RenderContext<'w>,
111 (camera, extracted_view, view_depth_texture, view_prepass_textures, resolution_override, _, _): QueryItem<
112 'w,
113 '_,
114 <LateDeferredGBufferPrepassNode as ViewNode>::ViewQuery,
115 >,
116 is_late: bool,
117 world: &'w World,
118 label: &'static str,
119) -> Result<(), NodeRunError> {
120 let (Some(opaque_deferred_phases), Some(alpha_mask_deferred_phases)) = (
121 world.get_resource::<ViewBinnedRenderPhases<Opaque3dDeferred>>(),
122 world.get_resource::<ViewBinnedRenderPhases<AlphaMask3dDeferred>>(),
123 ) else {
124 return Ok(());
125 };
126
127 let (Some(opaque_deferred_phase), Some(alpha_mask_deferred_phase)) = (
128 opaque_deferred_phases.get(&extracted_view.retained_view_entity),
129 alpha_mask_deferred_phases.get(&extracted_view.retained_view_entity),
130 ) else {
131 return Ok(());
132 };
133
134 let diagnostic = render_context.diagnostic_recorder();
135
136 let mut color_attachments = vec![];
137 color_attachments.push(
138 view_prepass_textures
139 .normal
140 .as_ref()
141 .map(|normals_texture| normals_texture.get_attachment()),
142 );
143 color_attachments.push(
144 view_prepass_textures
145 .motion_vectors
146 .as_ref()
147 .map(|motion_vectors_texture| motion_vectors_texture.get_attachment()),
148 );
149
150 #[cfg(all(feature = "webgl", target_arch = "wasm32", not(feature = "webgpu")))]
156 if !is_late {
157 if let Some(deferred_texture) = &view_prepass_textures.deferred {
158 render_context.command_encoder().clear_texture(
159 &deferred_texture.texture.texture,
160 &bevy_render::render_resource::ImageSubresourceRange::default(),
161 );
162 }
163 }
164
165 color_attachments.push(
166 view_prepass_textures
167 .deferred
168 .as_ref()
169 .map(|deferred_texture| {
170 if is_late {
171 deferred_texture.get_attachment()
172 } else {
173 #[cfg(all(feature = "webgl", target_arch = "wasm32", not(feature = "webgpu")))]
174 {
175 bevy_render::render_resource::RenderPassColorAttachment {
176 view: &deferred_texture.texture.default_view,
177 resolve_target: None,
178 ops: bevy_render::render_resource::Operations {
179 load: bevy_render::render_resource::LoadOp::Load,
180 store: StoreOp::Store,
181 },
182 depth_slice: None,
183 }
184 }
185 #[cfg(any(
186 not(feature = "webgl"),
187 not(target_arch = "wasm32"),
188 feature = "webgpu"
189 ))]
190 deferred_texture.get_attachment()
191 }
192 }),
193 );
194
195 color_attachments.push(
196 view_prepass_textures
197 .deferred_lighting_pass_id
198 .as_ref()
199 .map(|deferred_lighting_pass_id| deferred_lighting_pass_id.get_attachment()),
200 );
201
202 if color_attachments.iter().all(Option::is_none) {
204 color_attachments.clear();
205 }
206
207 let depth_stencil_attachment = Some(view_depth_texture.get_attachment(StoreOp::Store));
208
209 let view_entity = graph.view_entity();
210 render_context.add_command_buffer_generation_task(move |render_device| {
211 #[cfg(feature = "trace")]
212 let _deferred_span = info_span!("deferred_prepass").entered();
213
214 let mut command_encoder = render_device.create_command_encoder(&CommandEncoderDescriptor {
216 label: Some("deferred_prepass_command_encoder"),
217 });
218
219 let render_pass = command_encoder.begin_render_pass(&RenderPassDescriptor {
221 label: Some(label),
222 color_attachments: &color_attachments,
223 depth_stencil_attachment,
224 timestamp_writes: None,
225 occlusion_query_set: None,
226 });
227 let mut render_pass = TrackedRenderPass::new(&render_device, render_pass);
228 let pass_span = diagnostic.pass_span(&mut render_pass, label);
229 if let Some(viewport) =
230 Viewport::from_viewport_and_override(camera.viewport.as_ref(), resolution_override)
231 {
232 render_pass.set_camera_viewport(&viewport);
233 }
234
235 if !opaque_deferred_phase.multidrawable_meshes.is_empty()
237 || !opaque_deferred_phase.batchable_meshes.is_empty()
238 || !opaque_deferred_phase.unbatchable_meshes.is_empty()
239 {
240 #[cfg(feature = "trace")]
241 let _opaque_prepass_span = info_span!("opaque_deferred_prepass").entered();
242 if let Err(err) = opaque_deferred_phase.render(&mut render_pass, world, view_entity) {
243 error!("Error encountered while rendering the opaque deferred phase {err:?}");
244 }
245 }
246
247 if !alpha_mask_deferred_phase.is_empty() {
249 #[cfg(feature = "trace")]
250 let _alpha_mask_deferred_span = info_span!("alpha_mask_deferred_prepass").entered();
251 if let Err(err) = alpha_mask_deferred_phase.render(&mut render_pass, world, view_entity)
252 {
253 error!("Error encountered while rendering the alpha mask deferred phase {err:?}");
254 }
255 }
256
257 pass_span.end(&mut render_pass);
258 drop(render_pass);
259
260 if let Some(prepass_depth_texture) = &view_prepass_textures.depth {
262 command_encoder.copy_texture_to_texture(
263 view_depth_texture.texture.as_image_copy(),
264 prepass_depth_texture.texture.texture.as_image_copy(),
265 view_prepass_textures.size,
266 );
267 }
268
269 command_encoder.finish()
270 });
271
272 Ok(())
273}