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