1mod prepass_bindings;
2
3use crate::{
4 alpha_mode_pipeline_key, binding_arrays_are_usable, buffer_layout,
5 collect_meshes_for_gpu_building, init_material_pipeline, set_mesh_motion_vector_flags,
6 setup_morph_and_skinning_defs, skin, DeferredAlphaMaskDrawFunction, DeferredFragmentShader,
7 DeferredOpaqueDrawFunction, DeferredVertexShader, DrawMesh, MaterialPipeline, MeshLayouts,
8 MeshPipeline, MeshPipelineKey, PreparedMaterial, PrepassAlphaMaskDrawFunction,
9 PrepassFragmentShader, PrepassOpaqueDepthOnlyDrawFunction, PrepassOpaqueDrawFunction,
10 PrepassVertexShader, RenderLightmaps, RenderMaterialInstances, RenderMeshInstanceFlags,
11 RenderMeshInstances, SetMaterialBindGroup, SetMeshBindGroup, ShadowView,
12};
13use bevy_app::{App, Plugin, PreUpdate};
14use bevy_asset::{embedded_asset, load_embedded_asset, AssetServer, Handle};
15use bevy_camera::{Camera, Camera3d};
16use bevy_core_pipeline::{core_3d::CORE_3D_DEPTH_FORMAT, deferred::*, prepass::*};
17use bevy_ecs::{
18 prelude::*,
19 system::{
20 lifetimeless::{Read, SRes},
21 SystemParam, SystemParamItem, SystemState,
22 },
23};
24use bevy_material::{
25 key::{ErasedMaterialPipelineKey, ErasedMeshPipelineKey},
26 AlphaMode, MaterialProperties, OpaqueRendererMethod, RenderPhaseType,
27};
28use bevy_math::{Affine3A, Mat4, Vec4};
29use bevy_mesh::{Mesh, Mesh3d, MeshVertexBufferLayoutRef};
30use bevy_render::{
31 batching::gpu_preprocessing::GpuPreprocessingSupport,
32 camera::{DirtySpecializations, PendingQueues},
33 globals::{GlobalsBuffer, GlobalsUniform},
34 mesh::{allocator::MeshAllocator, RenderMesh},
35 render_asset::{prepare_assets, RenderAssets},
36 render_phase::*,
37 render_resource::{binding_types::uniform_buffer, *},
38 renderer::{RenderAdapter, RenderDevice, RenderQueue},
39 sync_world::RenderEntity,
40 view::{
41 ExtractedView, Msaa, RenderVisibilityRanges, RenderVisibleEntities, RetainedViewEntity,
42 ViewUniform, ViewUniformOffset, ViewUniforms, VISIBILITY_RANGES_STORAGE_BUFFER_COUNT,
43 },
44 Extract, ExtractSchedule, GpuResourceAppExt, Render, RenderApp, RenderDebugFlags,
45 RenderStartup, RenderSystems,
46};
47use bevy_shader::{load_shader_library, Shader, ShaderDefVal};
48use bevy_transform::prelude::GlobalTransform;
49use core::any::TypeId;
50pub use prepass_bindings::*;
51use tracing::{error, warn};
52
53#[cfg(feature = "meshlet")]
54use crate::meshlet::{
55 prepare_material_meshlet_meshes_prepass, queue_material_meshlet_meshes, InstanceManager,
56 MeshletMesh3d,
57};
58
59use alloc::sync::Arc;
60use bevy_derive::{Deref, DerefMut};
61use bevy_ecs::{change_detection::Tick, system::SystemChangeTick};
62use bevy_platform::collections::{HashMap, HashSet};
63use bevy_platform::hash::FixedHasher;
64use bevy_render::{
65 erased_render_asset::ErasedRenderAssets,
66 sync_world::{MainEntity, MainEntityHashMap},
67 RenderSystems::{PrepareAssets, PrepareResources},
68};
69use bevy_utils::default;
70
71pub struct PrepassPipelinePlugin;
75
76impl Plugin for PrepassPipelinePlugin {
77 fn build(&self, app: &mut App) {
78 embedded_asset!(app, "prepass.wgsl");
79
80 load_shader_library!(app, "prepass_bindings.wgsl");
81 load_shader_library!(app, "prepass_utils.wgsl");
82 load_shader_library!(app, "prepass_io.wgsl");
83
84 let Some(render_app) = app.get_sub_app_mut(RenderApp) else {
85 return;
86 };
87
88 render_app
89 .add_systems(
90 RenderStartup,
91 (
92 init_prepass_pipeline.after(init_material_pipeline),
93 init_prepass_view_bind_group,
94 )
95 .chain(),
96 )
97 .add_systems(
98 Render,
99 prepare_prepass_view_bind_group.in_set(RenderSystems::PrepareBindGroups),
100 )
101 .init_gpu_resource::<SpecializedMeshPipelines<PrepassPipelineSpecializer>>();
102 }
103}
104
105pub struct PrepassPlugin {
109 pub debug_flags: RenderDebugFlags,
111}
112
113impl PrepassPlugin {
114 pub fn new(debug_flags: RenderDebugFlags) -> Self {
116 PrepassPlugin { debug_flags }
117 }
118}
119
120impl Plugin for PrepassPlugin {
121 fn build(&self, app: &mut App) {
122 let no_prepass_plugin_loaded = app
123 .world()
124 .get_resource::<AnyPrepassPluginLoaded>()
125 .is_none();
126
127 if no_prepass_plugin_loaded {
128 app.insert_resource(AnyPrepassPluginLoaded)
129 .add_systems(
132 PreUpdate,
133 (
134 update_mesh_previous_global_transforms,
135 update_previous_view_data,
136 ),
137 )
138 .add_plugins((
139 BinnedRenderPhasePlugin::<Opaque3dPrepass, MeshPipeline>::new(self.debug_flags),
140 BinnedRenderPhasePlugin::<AlphaMask3dPrepass, MeshPipeline>::new(
141 self.debug_flags,
142 ),
143 ));
144 }
145
146 let Some(render_app) = app.get_sub_app_mut(RenderApp) else {
147 return;
148 };
149
150 if no_prepass_plugin_loaded {
151 render_app
152 .add_systems(ExtractSchedule, extract_camera_previous_view_data)
153 .add_systems(
154 Render,
155 prepare_previous_view_uniforms.in_set(PrepareResources),
156 );
157 }
158
159 render_app
160 .init_gpu_resource::<ViewKeyPrepassCache>()
161 .init_gpu_resource::<SpecializedPrepassMaterialPipelineCache>()
162 .init_gpu_resource::<PendingPrepassMeshMaterialQueues>()
163 .add_render_command::<Opaque3dPrepass, DrawPrepass>()
164 .add_render_command::<Opaque3dPrepass, DrawDepthOnlyPrepass>()
165 .add_render_command::<AlphaMask3dPrepass, DrawPrepass>()
166 .add_render_command::<Opaque3dDeferred, DrawPrepass>()
167 .add_render_command::<AlphaMask3dDeferred, DrawPrepass>()
168 .add_systems(
169 Render,
170 (
171 check_prepass_views_need_specialization.in_set(PrepareAssets),
172 specialize_prepass_material_meshes
173 .in_set(RenderSystems::PrepareMeshes)
174 .after(prepare_assets::<RenderMesh>)
175 .after(collect_meshes_for_gpu_building)
176 .after(set_mesh_motion_vector_flags),
177 queue_prepass_material_meshes.in_set(RenderSystems::QueueMeshes),
178 ),
179 );
180
181 #[cfg(feature = "meshlet")]
182 render_app.add_systems(
183 Render,
184 prepare_material_meshlet_meshes_prepass
185 .in_set(RenderSystems::QueueMeshes)
186 .before(queue_material_meshlet_meshes)
187 .run_if(resource_exists::<InstanceManager>),
188 );
189 }
190}
191
192#[derive(Resource)]
193struct AnyPrepassPluginLoaded;
194
195pub fn update_previous_view_data(
196 mut commands: Commands,
197 query: Query<(Entity, &Camera, &GlobalTransform), Or<(With<Camera3d>, With<ShadowView>)>>,
198) {
199 for (entity, camera, camera_transform) in &query {
200 let world_from_view = camera_transform.affine();
201 let view_from_world = Mat4::from(world_from_view.inverse());
202 let view_from_clip = camera.clip_from_view().inverse();
203
204 commands.entity(entity).try_insert(PreviousViewData {
205 view_from_world,
206 clip_from_world: camera.clip_from_view() * view_from_world,
207 clip_from_view: camera.clip_from_view(),
208 world_from_clip: Mat4::from(world_from_view) * view_from_clip,
209 view_from_clip,
210 });
211 }
212}
213
214#[derive(Component, PartialEq, Clone, Default)]
215pub struct PreviousGlobalTransform(pub Affine3A);
216
217#[cfg(not(feature = "meshlet"))]
218type PreviousMeshFilter = With<Mesh3d>;
219#[cfg(feature = "meshlet")]
220type PreviousMeshFilter = Or<(With<Mesh3d>, With<MeshletMesh3d>)>;
221
222pub fn update_mesh_previous_global_transforms(
223 mut commands: Commands,
224 views: Query<&Camera, Or<(With<Camera3d>, With<ShadowView>)>>,
225 new_meshes: Query<
226 (Entity, &GlobalTransform),
227 (PreviousMeshFilter, Without<PreviousGlobalTransform>),
228 >,
229 mut meshes: Query<(Ref<GlobalTransform>, &mut PreviousGlobalTransform), PreviousMeshFilter>,
230) {
231 if !views.iter().any(|camera| camera.is_active) {
232 return;
233 }
234
235 for (entity, transform) in &new_meshes {
236 let new_previous_transform = PreviousGlobalTransform(transform.affine());
237 commands.entity(entity).try_insert(new_previous_transform);
238 }
239 meshes.par_iter_mut().for_each(|(transform, mut previous)| {
240 if transform.is_changed_after(previous.last_changed()) {
241 *previous = PreviousGlobalTransform(transform.affine());
242 }
243 });
244}
245
246#[derive(Resource, Clone)]
247pub struct PrepassPipeline {
248 pub view_layout_motion_vectors: BindGroupLayoutDescriptor,
249 pub view_layout_no_motion_vectors: BindGroupLayoutDescriptor,
250 pub mesh_layouts: MeshLayouts,
251 pub empty_layout: BindGroupLayoutDescriptor,
252 pub default_prepass_shader: Handle<Shader>,
253
254 pub skins_use_uniform_buffers: bool,
257
258 pub depth_clip_control_supported: bool,
259
260 pub binding_arrays_are_usable: bool,
263 pub material_pipeline: MaterialPipeline,
264}
265
266pub fn init_prepass_pipeline(
267 mut commands: Commands,
268 render_device: Res<RenderDevice>,
269 render_adapter: Res<RenderAdapter>,
270 mesh_pipeline: Res<MeshPipeline>,
271 material_pipeline: Res<MaterialPipeline>,
272 asset_server: Res<AssetServer>,
273) {
274 let visibility_ranges_buffer_binding_type =
275 render_device.get_supported_read_only_binding_type(VISIBILITY_RANGES_STORAGE_BUFFER_COUNT);
276
277 let view_layout_motion_vectors = BindGroupLayoutDescriptor::new(
278 "prepass_view_layout_motion_vectors",
279 &BindGroupLayoutEntries::with_indices(
280 ShaderStages::VERTEX_FRAGMENT,
281 (
282 (0, uniform_buffer::<ViewUniform>(true)),
284 (1, uniform_buffer::<GlobalsUniform>(false)),
286 (2, uniform_buffer::<PreviousViewData>(true)),
288 (
290 14,
291 buffer_layout(
292 visibility_ranges_buffer_binding_type,
293 false,
294 Some(Vec4::min_size()),
295 )
296 .visibility(ShaderStages::VERTEX),
297 ),
298 ),
299 ),
300 );
301
302 let view_layout_no_motion_vectors = BindGroupLayoutDescriptor::new(
303 "prepass_view_layout_no_motion_vectors",
304 &BindGroupLayoutEntries::with_indices(
305 ShaderStages::VERTEX_FRAGMENT,
306 (
307 (0, uniform_buffer::<ViewUniform>(true)),
309 (1, uniform_buffer::<GlobalsUniform>(false)),
311 (
313 14,
314 buffer_layout(
315 visibility_ranges_buffer_binding_type,
316 false,
317 Some(Vec4::min_size()),
318 )
319 .visibility(ShaderStages::VERTEX),
320 ),
321 ),
322 ),
323 );
324
325 let depth_clip_control_supported = render_device
326 .features()
327 .contains(WgpuFeatures::DEPTH_CLIP_CONTROL);
328 commands.insert_resource(PrepassPipeline {
329 view_layout_motion_vectors,
330 view_layout_no_motion_vectors,
331 mesh_layouts: mesh_pipeline.mesh_layouts.clone(),
332 default_prepass_shader: load_embedded_asset!(asset_server.as_ref(), "prepass.wgsl"),
333 skins_use_uniform_buffers: skin::skins_use_uniform_buffers(&render_device.limits()),
334 depth_clip_control_supported,
335 binding_arrays_are_usable: binding_arrays_are_usable(&render_device, &render_adapter),
336 empty_layout: BindGroupLayoutDescriptor::new("prepass_empty_layout", &[]),
337 material_pipeline: material_pipeline.clone(),
338 });
339}
340
341pub struct PrepassPipelineSpecializer {
342 pub pipeline: PrepassPipeline,
343 pub properties: Arc<MaterialProperties>,
344}
345
346impl SpecializedMeshPipeline for PrepassPipelineSpecializer {
347 type Key = ErasedMaterialPipelineKey;
348
349 fn specialize(
350 &self,
351 key: Self::Key,
352 layout: &MeshVertexBufferLayoutRef,
353 ) -> Result<RenderPipelineDescriptor, SpecializedMeshPipelineError> {
354 let mut shader_defs = Vec::new();
355 if self.properties.bindless {
356 shader_defs.push("BINDLESS".into());
357 }
358 let mut descriptor = self.pipeline.specialize(
359 key.mesh_key.downcast(),
360 shader_defs,
361 layout,
362 &self.properties,
363 )?;
364
365 if let Some(specialize) = self.properties.user_specialize {
369 specialize(
370 &self.pipeline.material_pipeline,
371 &mut descriptor,
372 layout,
373 key,
374 )?;
375 }
376
377 Ok(descriptor)
378 }
379}
380
381fn is_depth_only_opaque_prepass(mesh_key: MeshPipelineKey) -> bool {
382 mesh_key.intersection(MeshPipelineKey::ALL_PREPASS_BITS) == MeshPipelineKey::DEPTH_PREPASS
383}
384
385impl PrepassPipeline {
386 fn specialize(
387 &self,
388 mesh_key: MeshPipelineKey,
389 shader_defs: Vec<ShaderDefVal>,
390 layout: &MeshVertexBufferLayoutRef,
391 material_properties: &MaterialProperties,
392 ) -> Result<RenderPipelineDescriptor, SpecializedMeshPipelineError> {
393 let mut shader_defs = shader_defs;
394 let mut bind_group_layouts = vec![
395 if mesh_key.contains(MeshPipelineKey::MOTION_VECTOR_PREPASS) {
396 self.view_layout_motion_vectors.clone()
397 } else {
398 self.view_layout_no_motion_vectors.clone()
399 },
400 self.empty_layout.clone(),
401 ];
402 let mut vertex_attributes = Vec::new();
403
404 shader_defs.push("PREPASS_PIPELINE".into());
408
409 shader_defs.push(ShaderDefVal::UInt(
410 "MATERIAL_BIND_GROUP".into(),
411 crate::MATERIAL_BIND_GROUP_INDEX as u32,
412 ));
413 let emulate_unclipped_depth = mesh_key.contains(MeshPipelineKey::UNCLIPPED_DEPTH_ORTHO)
416 && !self.depth_clip_control_supported;
417 if is_depth_only_opaque_prepass(mesh_key) && !emulate_unclipped_depth {
418 bind_group_layouts.push(self.empty_layout.clone());
419 } else {
420 bind_group_layouts.push(
421 material_properties
422 .material_layout
423 .as_ref()
424 .unwrap()
425 .clone(),
426 );
427 }
428 #[cfg(all(feature = "webgl", target_arch = "wasm32", not(feature = "webgpu")))]
429 shader_defs.push("WEBGL2".into());
430 shader_defs.push("VERTEX_OUTPUT_INSTANCE_INDEX".into());
431 let view_projection = mesh_key.intersection(MeshPipelineKey::VIEW_PROJECTION_RESERVED_BITS);
432 if view_projection == MeshPipelineKey::VIEW_PROJECTION_NONSTANDARD {
433 shader_defs.push("VIEW_PROJECTION_NONSTANDARD".into());
434 } else if view_projection == MeshPipelineKey::VIEW_PROJECTION_PERSPECTIVE {
435 shader_defs.push("VIEW_PROJECTION_PERSPECTIVE".into());
436 } else if view_projection == MeshPipelineKey::VIEW_PROJECTION_ORTHOGRAPHIC {
437 shader_defs.push("VIEW_PROJECTION_ORTHOGRAPHIC".into());
438 }
439 if mesh_key.contains(MeshPipelineKey::DEPTH_PREPASS) {
440 shader_defs.push("DEPTH_PREPASS".into());
441 }
442 if mesh_key.contains(MeshPipelineKey::MAY_DISCARD) {
443 shader_defs.push("MAY_DISCARD".into());
444 }
445 let blend_key = mesh_key.intersection(MeshPipelineKey::BLEND_RESERVED_BITS);
446 if blend_key == MeshPipelineKey::BLEND_PREMULTIPLIED_ALPHA {
447 shader_defs.push("BLEND_PREMULTIPLIED_ALPHA".into());
448 }
449 if blend_key == MeshPipelineKey::BLEND_ALPHA {
450 shader_defs.push("BLEND_ALPHA".into());
451 }
452 if layout.0.contains(Mesh::ATTRIBUTE_POSITION) {
453 shader_defs.push("VERTEX_POSITIONS".into());
454 vertex_attributes.push(Mesh::ATTRIBUTE_POSITION.at_shader_location(0));
455 }
456 if emulate_unclipped_depth {
457 shader_defs.push("UNCLIPPED_DEPTH_ORTHO_EMULATION".into());
458 shader_defs.push("PREPASS_FRAGMENT".into());
465 }
466 let unclipped_depth = mesh_key.contains(MeshPipelineKey::UNCLIPPED_DEPTH_ORTHO)
467 && self.depth_clip_control_supported;
468 if layout.0.contains(Mesh::ATTRIBUTE_UV_0) {
469 shader_defs.push("VERTEX_UVS".into());
470 shader_defs.push("VERTEX_UVS_A".into());
471 vertex_attributes.push(Mesh::ATTRIBUTE_UV_0.at_shader_location(1));
472 }
473 if layout.0.contains(Mesh::ATTRIBUTE_UV_1) {
474 shader_defs.push("VERTEX_UVS".into());
475 shader_defs.push("VERTEX_UVS_B".into());
476 vertex_attributes.push(Mesh::ATTRIBUTE_UV_1.at_shader_location(2));
477 }
478 if mesh_key.contains(MeshPipelineKey::NORMAL_PREPASS) {
479 shader_defs.push("NORMAL_PREPASS".into());
480 }
481 if mesh_key.intersects(MeshPipelineKey::NORMAL_PREPASS | MeshPipelineKey::DEFERRED_PREPASS)
482 {
483 shader_defs.push("NORMAL_PREPASS_OR_DEFERRED_PREPASS".into());
484 if layout.0.contains(Mesh::ATTRIBUTE_NORMAL) {
485 shader_defs.push("VERTEX_NORMALS".into());
486 vertex_attributes.push(Mesh::ATTRIBUTE_NORMAL.at_shader_location(3));
487 } else if mesh_key.contains(MeshPipelineKey::NORMAL_PREPASS) {
488 warn!(
489 "The default normal prepass expects the mesh to have vertex normal attributes."
490 );
491 }
492 if layout.0.contains(Mesh::ATTRIBUTE_TANGENT) {
493 shader_defs.push("VERTEX_TANGENTS".into());
494 vertex_attributes.push(Mesh::ATTRIBUTE_TANGENT.at_shader_location(4));
495 }
496 }
497 if mesh_key
498 .intersects(MeshPipelineKey::MOTION_VECTOR_PREPASS | MeshPipelineKey::DEFERRED_PREPASS)
499 {
500 shader_defs.push("MOTION_VECTOR_PREPASS_OR_DEFERRED_PREPASS".into());
501 }
502 if mesh_key.contains(MeshPipelineKey::DEFERRED_PREPASS) {
503 shader_defs.push("DEFERRED_PREPASS".into());
504 }
505 if mesh_key.contains(MeshPipelineKey::LIGHTMAPPED) {
506 shader_defs.push("LIGHTMAP".into());
507 }
508 if mesh_key.contains(MeshPipelineKey::LIGHTMAP_BICUBIC_SAMPLING) {
509 shader_defs.push("LIGHTMAP_BICUBIC_SAMPLING".into());
510 }
511 if layout.0.contains(Mesh::ATTRIBUTE_COLOR) {
512 shader_defs.push("VERTEX_COLORS".into());
513 vertex_attributes.push(Mesh::ATTRIBUTE_COLOR.at_shader_location(7));
514 }
515 if mesh_key.contains(MeshPipelineKey::MOTION_VECTOR_PREPASS) {
516 shader_defs.push("MOTION_VECTOR_PREPASS".into());
517 }
518 if mesh_key.contains(MeshPipelineKey::HAS_PREVIOUS_SKIN) {
519 shader_defs.push("HAS_PREVIOUS_SKIN".into());
520 }
521 if mesh_key.contains(MeshPipelineKey::HAS_PREVIOUS_MORPH) {
522 shader_defs.push("HAS_PREVIOUS_MORPH".into());
523 }
524 if self.binding_arrays_are_usable {
525 shader_defs.push("MULTIPLE_LIGHTMAPS_IN_ARRAY".into());
526 }
527 if mesh_key.contains(MeshPipelineKey::VISIBILITY_RANGE_DITHER) {
528 shader_defs.push("VISIBILITY_RANGE_DITHER".into());
529 }
530 if mesh_key.intersects(
531 MeshPipelineKey::NORMAL_PREPASS
532 | MeshPipelineKey::MOTION_VECTOR_PREPASS
533 | MeshPipelineKey::DEFERRED_PREPASS,
534 ) {
535 shader_defs.push("PREPASS_FRAGMENT".into());
536 }
537 let bind_group = setup_morph_and_skinning_defs(
538 &self.mesh_layouts,
539 layout,
540 5,
541 &mesh_key,
542 &mut shader_defs,
543 &mut vertex_attributes,
544 self.skins_use_uniform_buffers,
545 );
546 bind_group_layouts.insert(2, bind_group);
547 let vertex_buffer_layout = layout.0.get_layout(&vertex_attributes)?;
548 let mut targets = prepass_target_descriptors(
550 mesh_key.contains(MeshPipelineKey::NORMAL_PREPASS),
551 mesh_key.contains(MeshPipelineKey::MOTION_VECTOR_PREPASS),
552 mesh_key.contains(MeshPipelineKey::DEFERRED_PREPASS),
553 );
554
555 if targets.iter().all(Option::is_none) {
556 targets.clear();
559 }
560
561 let fragment_required = !targets.is_empty()
565 || emulate_unclipped_depth
566 || (mesh_key.contains(MeshPipelineKey::MAY_DISCARD)
567 && material_properties
568 .get_shader(PrepassFragmentShader)
569 .is_some());
570
571 let fragment = fragment_required.then(|| {
572 let frag_shader_handle = if mesh_key.contains(MeshPipelineKey::DEFERRED_PREPASS) {
574 match material_properties.get_shader(DeferredFragmentShader) {
575 Some(frag_shader_handle) => frag_shader_handle,
576 None => self.default_prepass_shader.clone(),
577 }
578 } else {
579 match material_properties.get_shader(PrepassFragmentShader) {
580 Some(frag_shader_handle) => frag_shader_handle,
581 None => self.default_prepass_shader.clone(),
582 }
583 };
584
585 FragmentState {
586 shader: frag_shader_handle,
587 shader_defs: shader_defs.clone(),
588 targets,
589 ..default()
590 }
591 });
592
593 let vert_shader_handle = if mesh_key.contains(MeshPipelineKey::DEFERRED_PREPASS) {
595 if let Some(handle) = material_properties.get_shader(DeferredVertexShader) {
596 handle
597 } else {
598 self.default_prepass_shader.clone()
599 }
600 } else if let Some(handle) = material_properties.get_shader(PrepassVertexShader) {
601 handle
602 } else {
603 self.default_prepass_shader.clone()
604 };
605 let descriptor = RenderPipelineDescriptor {
606 vertex: VertexState {
607 shader: vert_shader_handle,
608 shader_defs,
609 buffers: vec![vertex_buffer_layout],
610 ..default()
611 },
612 fragment,
613 layout: bind_group_layouts,
614 primitive: PrimitiveState {
615 topology: mesh_key.primitive_topology(),
616 strip_index_format: mesh_key.strip_index_format(),
617 unclipped_depth,
618 ..default()
619 },
620 depth_stencil: Some(DepthStencilState {
621 format: CORE_3D_DEPTH_FORMAT,
622 depth_write_enabled: Some(true),
623 depth_compare: Some(CompareFunction::GreaterEqual),
624 stencil: StencilState {
625 front: StencilFaceState::IGNORE,
626 back: StencilFaceState::IGNORE,
627 read_mask: 0,
628 write_mask: 0,
629 },
630 bias: DepthBiasState {
631 constant: 0,
632 slope_scale: 0.0,
633 clamp: 0.0,
634 },
635 }),
636 multisample: MultisampleState {
637 count: mesh_key.msaa_samples(),
638 mask: !0,
639 alpha_to_coverage_enabled: false,
640 },
641 label: Some("prepass_pipeline".into()),
642 ..default()
643 };
644 Ok(descriptor)
645 }
646}
647
648pub fn extract_camera_previous_view_data(
650 mut commands: Commands,
651 cameras_3d: Extract<Query<(RenderEntity, &Camera, Option<&PreviousViewData>), With<Camera3d>>>,
652) {
653 for (entity, camera, maybe_previous_view_data) in cameras_3d.iter() {
654 let mut entity = commands
655 .get_entity(entity)
656 .expect("Camera entity wasn't synced.");
657 if camera.is_active {
658 if let Some(previous_view_data) = maybe_previous_view_data {
659 entity.insert(previous_view_data.clone());
660 }
661 } else {
662 entity.remove::<PreviousViewData>();
663 }
664 }
665}
666
667pub fn prepare_previous_view_uniforms(
668 mut commands: Commands,
669 render_device: Res<RenderDevice>,
670 render_queue: Res<RenderQueue>,
671 mut previous_view_uniforms: ResMut<PreviousViewUniforms>,
672 views: Query<
673 (Entity, &ExtractedView, Option<&PreviousViewData>),
674 Or<(With<Camera3d>, With<ShadowView>)>,
675 >,
676) {
677 let views_iter = views.iter();
678 let view_count = views_iter.len();
679 let Some(mut writer) =
680 previous_view_uniforms
681 .uniforms
682 .get_writer(view_count, &render_device, &render_queue)
683 else {
684 return;
685 };
686
687 for (entity, camera, maybe_previous_view_uniforms) in views_iter {
688 let prev_view_data = match maybe_previous_view_uniforms {
689 Some(previous_view) => previous_view.clone(),
690 None => {
691 let world_from_view = camera.world_from_view.affine();
692 let view_from_world = Mat4::from(world_from_view.inverse());
693 let view_from_clip = camera.clip_from_view.inverse();
694
695 PreviousViewData {
696 view_from_world,
697 clip_from_world: camera.clip_from_view * view_from_world,
698 clip_from_view: camera.clip_from_view,
699 world_from_clip: Mat4::from(world_from_view) * view_from_clip,
700 view_from_clip,
701 }
702 }
703 };
704
705 commands.entity(entity).insert(PreviousViewUniformOffset {
706 offset: writer.write(&prev_view_data),
707 });
708 }
709}
710
711#[derive(Resource)]
712pub struct PrepassViewBindGroup {
713 pub motion_vectors: Option<BindGroup>,
714 pub no_motion_vectors: Option<BindGroup>,
715 pub empty_bind_group: BindGroup,
716}
717
718pub fn init_prepass_view_bind_group(
719 mut commands: Commands,
720 render_device: Res<RenderDevice>,
721 pipeline_cache: Res<PipelineCache>,
722 pipeline: Res<PrepassPipeline>,
723) {
724 let empty_bind_group = render_device.create_bind_group(
725 "prepass_view_empty_bind_group",
726 &pipeline_cache.get_bind_group_layout(&pipeline.empty_layout),
727 &[],
728 );
729 commands.insert_resource(PrepassViewBindGroup {
730 motion_vectors: None,
731 no_motion_vectors: None,
732 empty_bind_group,
733 });
734}
735
736pub fn prepare_prepass_view_bind_group(
737 render_device: Res<RenderDevice>,
738 pipeline_cache: Res<PipelineCache>,
739 prepass_pipeline: Res<PrepassPipeline>,
740 view_uniforms: Res<ViewUniforms>,
741 globals_buffer: Res<GlobalsBuffer>,
742 previous_view_uniforms: Res<PreviousViewUniforms>,
743 visibility_ranges: Res<RenderVisibilityRanges>,
744 mut prepass_view_bind_group: ResMut<PrepassViewBindGroup>,
745) {
746 if let (Some(view_binding), Some(globals_binding), Some(visibility_ranges_buffer)) = (
747 view_uniforms.uniforms.binding(),
748 globals_buffer.buffer.binding(),
749 visibility_ranges.buffer().buffer(),
750 ) {
751 prepass_view_bind_group.no_motion_vectors = Some(render_device.create_bind_group(
752 "prepass_view_no_motion_vectors_bind_group",
753 &pipeline_cache.get_bind_group_layout(&prepass_pipeline.view_layout_no_motion_vectors),
754 &BindGroupEntries::with_indices((
755 (0, view_binding.clone()),
756 (1, globals_binding.clone()),
757 (14, visibility_ranges_buffer.as_entire_binding()),
758 )),
759 ));
760
761 if let Some(previous_view_uniforms_binding) = previous_view_uniforms.uniforms.binding() {
762 prepass_view_bind_group.motion_vectors = Some(render_device.create_bind_group(
763 "prepass_view_motion_vectors_bind_group",
764 &pipeline_cache.get_bind_group_layout(&prepass_pipeline.view_layout_motion_vectors),
765 &BindGroupEntries::with_indices((
766 (0, view_binding),
767 (1, globals_binding),
768 (2, previous_view_uniforms_binding),
769 (14, visibility_ranges_buffer.as_entire_binding()),
770 )),
771 ));
772 }
773 }
774}
775
776#[derive(Resource, Deref, DerefMut, Default)]
778pub struct SpecializedPrepassMaterialPipelineCache {
779 #[deref]
781 map: HashMap<RetainedViewEntity, SpecializedPrepassMaterialViewPipelineCache>,
782}
783
784#[derive(Deref, DerefMut, Default)]
787pub struct SpecializedPrepassMaterialViewPipelineCache {
788 #[deref]
790 map: MainEntityHashMap<(Tick, CachedRenderPipelineId, DrawFunctionId)>,
791}
792
793#[derive(Resource, Deref, DerefMut, Default, Clone)]
794pub struct ViewKeyPrepassCache(HashMap<RetainedViewEntity, MeshPipelineKey>);
795
796pub fn check_prepass_views_need_specialization(
797 mut view_key_cache: ResMut<ViewKeyPrepassCache>,
798 mut dirty_specializations: ResMut<DirtySpecializations>,
799 mut views: Query<(
800 &ExtractedView,
801 &Msaa,
802 Option<&DepthPrepass>,
803 Option<&NormalPrepass>,
804 Option<&MotionVectorPrepass>,
805 )>,
806) {
807 for (view, msaa, depth_prepass, normal_prepass, motion_vector_prepass) in views.iter_mut() {
808 let mut view_key = MeshPipelineKey::from_msaa_samples(msaa.samples());
809 if depth_prepass.is_some() {
810 view_key |= MeshPipelineKey::DEPTH_PREPASS;
811 }
812 if normal_prepass.is_some() {
813 view_key |= MeshPipelineKey::NORMAL_PREPASS;
814 }
815 if motion_vector_prepass.is_some() {
816 view_key |= MeshPipelineKey::MOTION_VECTOR_PREPASS;
817 }
818
819 if let Some(current_key) = view_key_cache.get_mut(&view.retained_view_entity) {
820 if *current_key != view_key {
821 view_key_cache.insert(view.retained_view_entity, view_key);
822 dirty_specializations
823 .views
824 .insert(view.retained_view_entity);
825 }
826 } else {
827 view_key_cache.insert(view.retained_view_entity, view_key);
828 dirty_specializations
829 .views
830 .insert(view.retained_view_entity);
831 }
832 }
833}
834
835pub(crate) struct PrepassSpecializationWorkItem {
836 visible_entity: MainEntity,
837 retained_view_entity: RetainedViewEntity,
838 mesh_key: MeshPipelineKey,
839 layout: MeshVertexBufferLayoutRef,
840 properties: Arc<MaterialProperties>,
841 material_type_id: TypeId,
842}
843
844#[derive(Default, Deref, DerefMut, Resource)]
849pub struct PendingPrepassMeshMaterialQueues(pub PendingQueues);
850
851#[derive(SystemParam)]
852pub(crate) struct SpecializePrepassSystemParam<'w, 's> {
853 render_meshes: Res<'w, RenderAssets<RenderMesh>>,
854 render_materials: Res<'w, ErasedRenderAssets<PreparedMaterial>>,
855 render_mesh_instances: Res<'w, RenderMeshInstances>,
856 render_material_instances: Res<'w, RenderMaterialInstances>,
857 render_lightmaps: Res<'w, RenderLightmaps>,
858 render_visibility_ranges: Res<'w, RenderVisibilityRanges>,
859 view_key_cache: Res<'w, ViewKeyPrepassCache>,
860 views: Query<
861 'w,
862 's,
863 (
864 &'static ExtractedView,
865 &'static RenderVisibleEntities,
866 &'static Msaa,
867 Option<&'static MotionVectorPrepass>,
868 Option<&'static DeferredPrepass>,
869 ),
870 >,
871 opaque_prepass_render_phases: Res<'w, ViewBinnedRenderPhases<Opaque3dPrepass>>,
872 alpha_mask_prepass_render_phases: Res<'w, ViewBinnedRenderPhases<AlphaMask3dPrepass>>,
873 opaque_deferred_render_phases: Res<'w, ViewBinnedRenderPhases<Opaque3dDeferred>>,
874 alpha_mask_deferred_render_phases: Res<'w, ViewBinnedRenderPhases<AlphaMask3dDeferred>>,
875 specialized_prepass_material_pipeline_cache:
876 ResMut<'w, SpecializedPrepassMaterialPipelineCache>,
877 pending_prepass_mesh_material_queues: ResMut<'w, PendingPrepassMeshMaterialQueues>,
878 dirty_specializations: Res<'w, DirtySpecializations>,
879 this_run: SystemChangeTick,
880}
881
882pub(crate) fn specialize_prepass_material_meshes(
883 world: &mut World,
884 state: &mut SystemState<SpecializePrepassSystemParam>,
885 mut work_items: Local<Vec<PrepassSpecializationWorkItem>>,
886 mut removals: Local<Vec<(RetainedViewEntity, MainEntity)>>,
887 mut all_views: Local<HashSet<RetainedViewEntity, FixedHasher>>,
888) {
889 work_items.clear();
890 removals.clear();
891 all_views.clear();
892
893 let this_run;
894
895 {
896 let SpecializePrepassSystemParam {
897 render_meshes,
898 render_materials,
899 render_mesh_instances,
900 render_material_instances,
901 render_lightmaps,
902 render_visibility_ranges,
903 view_key_cache,
904 views,
905 opaque_prepass_render_phases,
906 alpha_mask_prepass_render_phases,
907 opaque_deferred_render_phases,
908 alpha_mask_deferred_render_phases,
909 mut specialized_prepass_material_pipeline_cache,
910 mut pending_prepass_mesh_material_queues,
911 dirty_specializations,
912 this_run: system_change_tick,
913 } = state.get_mut(world).unwrap();
914
915 this_run = system_change_tick.this_run();
916
917 for (extracted_view, visible_entities, msaa, motion_vector_prepass, deferred_prepass) in
918 &views
919 {
920 if !opaque_deferred_render_phases.contains_key(&extracted_view.retained_view_entity)
921 && !alpha_mask_deferred_render_phases
922 .contains_key(&extracted_view.retained_view_entity)
923 && !opaque_prepass_render_phases.contains_key(&extracted_view.retained_view_entity)
924 && !alpha_mask_prepass_render_phases
925 .contains_key(&extracted_view.retained_view_entity)
926 {
927 continue;
928 }
929
930 let Some(view_key) = view_key_cache.get(&extracted_view.retained_view_entity) else {
931 continue;
932 };
933
934 all_views.insert(extracted_view.retained_view_entity);
935
936 let Some(render_visible_mesh_entities) = visible_entities.get::<Mesh3d>() else {
937 continue;
938 };
939
940 let view_pending_prepass_mesh_material_queues = pending_prepass_mesh_material_queues
942 .prepare_for_new_frame(extracted_view.retained_view_entity);
943
944 let mut maybe_specialized_prepass_material_pipeline_cache =
946 specialized_prepass_material_pipeline_cache
947 .get_mut(&extracted_view.retained_view_entity);
948
949 if let Some(ref mut specialized_prepass_material_pipeline_cache) =
952 maybe_specialized_prepass_material_pipeline_cache
953 {
954 if dirty_specializations
955 .must_wipe_specializations_for_view(extracted_view.retained_view_entity)
956 {
957 specialized_prepass_material_pipeline_cache.clear();
958 } else {
959 for &renderable_entity in dirty_specializations.iter_to_despecialize() {
960 specialized_prepass_material_pipeline_cache.remove(&renderable_entity);
961 }
962 }
963 }
964
965 for (render_entity, visible_entity) in dirty_specializations.iter_to_specialize(
967 extracted_view.retained_view_entity,
968 render_visible_mesh_entities,
969 &view_pending_prepass_mesh_material_queues.prev_frame,
970 ) {
971 if maybe_specialized_prepass_material_pipeline_cache
972 .as_ref()
973 .is_some_and(|specialized_prepass_material_pipeline_cache| {
974 specialized_prepass_material_pipeline_cache.contains_key(visible_entity)
975 })
976 {
977 continue;
978 }
979
980 let Some(material_instance) =
985 render_material_instances.instances.get(visible_entity)
986 else {
987 view_pending_prepass_mesh_material_queues
988 .current_frame
989 .insert((*render_entity, *visible_entity));
990 continue;
991 };
992 let Some(mesh_instance) =
993 render_mesh_instances.render_mesh_queue_data(*visible_entity)
994 else {
995 view_pending_prepass_mesh_material_queues
996 .current_frame
997 .insert((*render_entity, *visible_entity));
998 continue;
999 };
1000 let Some(material) = render_materials.get(material_instance.asset_id) else {
1001 view_pending_prepass_mesh_material_queues
1002 .current_frame
1003 .insert((*render_entity, *visible_entity));
1004 continue;
1005 };
1006 if !material.properties.prepass_enabled {
1007 removals.push((extracted_view.retained_view_entity, *visible_entity));
1009 continue;
1010 }
1011 let Some(mesh) = render_meshes.get(mesh_instance.mesh_asset_id()) else {
1012 continue;
1013 };
1014
1015 let mut mesh_key =
1016 *view_key | MeshPipelineKey::from_bits_retain(mesh.key_bits.bits());
1017
1018 let alpha_mode = material.properties.alpha_mode;
1019 match alpha_mode {
1020 AlphaMode::Opaque | AlphaMode::AlphaToCoverage | AlphaMode::Mask(_) => {
1021 mesh_key |= alpha_mode_pipeline_key(alpha_mode, msaa);
1022 }
1023 AlphaMode::Blend
1024 | AlphaMode::Premultiplied
1025 | AlphaMode::Add
1026 | AlphaMode::Multiply => {
1027 removals.push((extracted_view.retained_view_entity, *visible_entity));
1030 continue;
1031 }
1032 }
1033
1034 if material.properties.reads_view_transmission_texture {
1035 removals.push((extracted_view.retained_view_entity, *visible_entity));
1038 continue;
1039 }
1040
1041 let forward = match material.properties.render_method {
1042 OpaqueRendererMethod::Forward => true,
1043 OpaqueRendererMethod::Deferred => false,
1044 OpaqueRendererMethod::Auto => unreachable!(),
1045 };
1046
1047 let deferred = deferred_prepass.is_some() && !forward;
1048
1049 if deferred {
1050 mesh_key |= MeshPipelineKey::DEFERRED_PREPASS;
1051 }
1052
1053 if let Some(lightmap) = render_lightmaps.render_lightmaps.get(visible_entity) {
1054 mesh_key |= MeshPipelineKey::LIGHTMAPPED;
1060
1061 if lightmap.bicubic_sampling && deferred {
1062 mesh_key |= MeshPipelineKey::LIGHTMAP_BICUBIC_SAMPLING;
1063 }
1064 }
1065
1066 if render_visibility_ranges
1067 .entity_has_crossfading_visibility_ranges(*visible_entity)
1068 {
1069 mesh_key |= MeshPipelineKey::VISIBILITY_RANGE_DITHER;
1070 }
1071
1072 if motion_vector_prepass.is_some() {
1074 if mesh_instance
1075 .flags()
1076 .contains(RenderMeshInstanceFlags::HAS_PREVIOUS_SKIN)
1077 {
1078 mesh_key |= MeshPipelineKey::HAS_PREVIOUS_SKIN;
1079 }
1080 if mesh_instance
1081 .flags()
1082 .contains(RenderMeshInstanceFlags::HAS_PREVIOUS_MORPH)
1083 {
1084 mesh_key |= MeshPipelineKey::HAS_PREVIOUS_MORPH;
1085 }
1086 }
1087
1088 work_items.push(PrepassSpecializationWorkItem {
1089 visible_entity: *visible_entity,
1090 retained_view_entity: extracted_view.retained_view_entity,
1091 mesh_key,
1092 layout: mesh.layout.clone(),
1093 properties: material.properties.clone(),
1094 material_type_id: material_instance.asset_id.type_id(),
1095 });
1096 }
1097 }
1098
1099 pending_prepass_mesh_material_queues.expire_stale_views(&all_views);
1100 }
1101
1102 let depth_clip_control_supported = world
1103 .resource::<PrepassPipeline>()
1104 .depth_clip_control_supported;
1105
1106 for item in work_items.drain(..) {
1107 let Some(prepass_specialize) = item.properties.prepass_specialize else {
1108 continue;
1109 };
1110
1111 let key = ErasedMaterialPipelineKey {
1112 type_id: item.material_type_id,
1113 mesh_key: ErasedMeshPipelineKey::new(item.mesh_key),
1114 material_key: item.properties.material_key.clone(),
1115 };
1116
1117 let emulate_unclipped_depth = item
1118 .mesh_key
1119 .contains(MeshPipelineKey::UNCLIPPED_DEPTH_ORTHO)
1120 && !depth_clip_control_supported;
1121 let deferred = item.mesh_key.contains(MeshPipelineKey::DEFERRED_PREPASS);
1122 let draw_function = match item.properties.render_phase_type {
1123 RenderPhaseType::Opaque => {
1124 if deferred {
1125 item.properties
1126 .get_draw_function(DeferredOpaqueDrawFunction)
1127 } else if is_depth_only_opaque_prepass(item.mesh_key) && !emulate_unclipped_depth {
1128 item.properties
1129 .get_draw_function(PrepassOpaqueDepthOnlyDrawFunction)
1130 } else {
1131 item.properties.get_draw_function(PrepassOpaqueDrawFunction)
1132 }
1133 }
1134 RenderPhaseType::AlphaMask => {
1135 if deferred {
1136 item.properties
1137 .get_draw_function(DeferredAlphaMaskDrawFunction)
1138 } else {
1139 item.properties
1140 .get_draw_function(PrepassAlphaMaskDrawFunction)
1141 }
1142 }
1143 RenderPhaseType::Transmissive | RenderPhaseType::Transparent => continue,
1144 };
1145
1146 let Some(draw_function) = draw_function else {
1147 continue;
1148 };
1149
1150 match prepass_specialize(world, key, &item.layout, &item.properties) {
1151 Ok(pipeline_id) => {
1152 world
1153 .resource_mut::<SpecializedPrepassMaterialPipelineCache>()
1154 .entry(item.retained_view_entity)
1155 .or_default()
1156 .insert(item.visible_entity, (this_run, pipeline_id, draw_function));
1157 }
1158 Err(err) => error!("{}", err),
1159 }
1160 }
1161
1162 if !removals.is_empty() {
1163 let mut cache = world.resource_mut::<SpecializedPrepassMaterialPipelineCache>();
1164 for (view, entity) in removals.drain(..) {
1165 if let Some(view_cache) = cache.get_mut(&view) {
1166 view_cache.remove(&entity);
1167 }
1168 }
1169 }
1170
1171 world
1172 .resource_mut::<SpecializedPrepassMaterialPipelineCache>()
1173 .retain(|view, _| all_views.contains(view));
1174}
1175
1176pub fn queue_prepass_material_meshes(
1177 render_mesh_instances: Res<RenderMeshInstances>,
1178 render_materials: Res<ErasedRenderAssets<PreparedMaterial>>,
1179 render_material_instances: Res<RenderMaterialInstances>,
1180 mesh_allocator: Res<MeshAllocator>,
1181 gpu_preprocessing_support: Res<GpuPreprocessingSupport>,
1182 mut opaque_prepass_render_phases: ResMut<ViewBinnedRenderPhases<Opaque3dPrepass>>,
1183 mut alpha_mask_prepass_render_phases: ResMut<ViewBinnedRenderPhases<AlphaMask3dPrepass>>,
1184 mut opaque_deferred_render_phases: ResMut<ViewBinnedRenderPhases<Opaque3dDeferred>>,
1185 mut alpha_mask_deferred_render_phases: ResMut<ViewBinnedRenderPhases<AlphaMask3dDeferred>>,
1186 views: Query<(&ExtractedView, &RenderVisibleEntities)>,
1187 specialized_material_pipeline_cache: Res<SpecializedPrepassMaterialPipelineCache>,
1188 mut pending_prepass_mesh_material_queues: ResMut<PendingPrepassMeshMaterialQueues>,
1189 dirty_specializations: Res<DirtySpecializations>,
1190) {
1191 for (extracted_view, visible_entities) in &views {
1192 let (
1193 mut opaque_phase,
1194 mut alpha_mask_phase,
1195 mut opaque_deferred_phase,
1196 mut alpha_mask_deferred_phase,
1197 ) = (
1198 opaque_prepass_render_phases.get_mut(&extracted_view.retained_view_entity),
1199 alpha_mask_prepass_render_phases.get_mut(&extracted_view.retained_view_entity),
1200 opaque_deferred_render_phases.get_mut(&extracted_view.retained_view_entity),
1201 alpha_mask_deferred_render_phases.get_mut(&extracted_view.retained_view_entity),
1202 );
1203
1204 let Some(view_specialized_material_pipeline_cache) =
1205 specialized_material_pipeline_cache.get(&extracted_view.retained_view_entity)
1206 else {
1207 continue;
1208 };
1209
1210 if opaque_phase.is_none()
1212 && alpha_mask_phase.is_none()
1213 && opaque_deferred_phase.is_none()
1214 && alpha_mask_deferred_phase.is_none()
1215 {
1216 continue;
1217 }
1218
1219 let Some(render_visible_mesh_entities) = visible_entities.get::<Mesh3d>() else {
1220 continue;
1221 };
1222
1223 let view_pending_prepass_mesh_material_queues = pending_prepass_mesh_material_queues
1225 .get_mut(&extracted_view.retained_view_entity)
1226 .expect(
1227 "View pending prepass mesh material queues should have been created in \
1228 `specialize_prepass_material_meshes`",
1229 );
1230
1231 for &main_entity in dirty_specializations.iter_to_dequeue(
1233 extracted_view.retained_view_entity,
1234 render_visible_mesh_entities,
1235 ) {
1236 if let Some(ref mut opaque_phase) = opaque_phase {
1237 opaque_phase.remove(main_entity);
1238 }
1239 if let Some(ref mut alpha_mask_phase) = alpha_mask_phase {
1240 alpha_mask_phase.remove(main_entity);
1241 }
1242 if let Some(ref mut opaque_deferred_phase) = opaque_deferred_phase {
1243 opaque_deferred_phase.remove(main_entity);
1244 }
1245 if let Some(ref mut alpha_mask_deferred_phase) = alpha_mask_deferred_phase {
1246 alpha_mask_deferred_phase.remove(main_entity);
1247 }
1248 }
1249
1250 for (render_entity, visible_entity) in dirty_specializations.iter_to_queue(
1252 extracted_view.retained_view_entity,
1253 render_visible_mesh_entities,
1254 &view_pending_prepass_mesh_material_queues.prev_frame,
1255 ) {
1256 let Some(&(_, pipeline_id, draw_function)) =
1257 view_specialized_material_pipeline_cache.get(visible_entity)
1258 else {
1259 continue;
1260 };
1261
1262 let Some(material_instance) = render_material_instances.instances.get(visible_entity)
1267 else {
1268 view_pending_prepass_mesh_material_queues
1269 .current_frame
1270 .insert((*render_entity, *visible_entity));
1271 continue;
1272 };
1273 let Some(mesh_instance) = render_mesh_instances.render_mesh_queue_data(*visible_entity)
1274 else {
1275 view_pending_prepass_mesh_material_queues
1276 .current_frame
1277 .insert((*render_entity, *visible_entity));
1278 continue;
1279 };
1280 let Some(material) = render_materials.get(material_instance.asset_id) else {
1281 view_pending_prepass_mesh_material_queues
1282 .current_frame
1283 .insert((*render_entity, *visible_entity));
1284 continue;
1285 };
1286 let Some(mesh_slabs) = mesh_allocator.mesh_slabs(&mesh_instance.mesh_asset_id()) else {
1287 continue;
1288 };
1289
1290 let deferred = match material.properties.render_method {
1291 OpaqueRendererMethod::Forward => false,
1292 OpaqueRendererMethod::Deferred => true,
1293 OpaqueRendererMethod::Auto => unreachable!(),
1294 };
1295
1296 match material.properties.render_phase_type {
1297 RenderPhaseType::Opaque => {
1298 if deferred {
1299 opaque_deferred_phase.as_mut().unwrap().add(
1300 OpaqueNoLightmap3dBatchSetKey {
1301 draw_function,
1302 pipeline: pipeline_id,
1303 material_bind_group_index: Some(material.binding.group.0),
1304 slabs: mesh_slabs,
1305 },
1306 OpaqueNoLightmap3dBinKey {
1307 asset_id: mesh_instance.mesh_asset_id().into(),
1308 },
1309 (*render_entity, *visible_entity),
1310 mesh_instance.current_uniform_index,
1311 BinnedRenderPhaseType::mesh(
1312 mesh_instance.should_batch(),
1313 &gpu_preprocessing_support,
1314 ),
1315 );
1316 } else if let Some(opaque_phase) = opaque_phase.as_mut() {
1317 let depth_only_draw_function = material
1318 .properties
1319 .get_draw_function(PrepassOpaqueDepthOnlyDrawFunction);
1320 let material_bind_group_index =
1321 if Some(draw_function) == depth_only_draw_function {
1322 None
1323 } else {
1324 Some(material.binding.group.0)
1325 };
1326 opaque_phase.add(
1327 OpaqueNoLightmap3dBatchSetKey {
1328 draw_function,
1329 pipeline: pipeline_id,
1330 material_bind_group_index,
1331 slabs: mesh_slabs,
1332 },
1333 OpaqueNoLightmap3dBinKey {
1334 asset_id: mesh_instance.mesh_asset_id().into(),
1335 },
1336 (*render_entity, *visible_entity),
1337 mesh_instance.current_uniform_index,
1338 BinnedRenderPhaseType::mesh(
1339 mesh_instance.should_batch(),
1340 &gpu_preprocessing_support,
1341 ),
1342 );
1343 }
1344 }
1345 RenderPhaseType::AlphaMask => {
1346 if deferred {
1347 alpha_mask_deferred_phase.as_mut().unwrap().add(
1348 OpaqueNoLightmap3dBatchSetKey {
1349 draw_function,
1350 pipeline: pipeline_id,
1351 material_bind_group_index: Some(material.binding.group.0),
1352 slabs: mesh_slabs,
1353 },
1354 OpaqueNoLightmap3dBinKey {
1355 asset_id: mesh_instance.mesh_asset_id().into(),
1356 },
1357 (*render_entity, *visible_entity),
1358 mesh_instance.current_uniform_index,
1359 BinnedRenderPhaseType::mesh(
1360 mesh_instance.should_batch(),
1361 &gpu_preprocessing_support,
1362 ),
1363 );
1364 } else if let Some(alpha_mask_phase) = alpha_mask_phase.as_mut() {
1365 alpha_mask_phase.add(
1366 OpaqueNoLightmap3dBatchSetKey {
1367 draw_function,
1368 pipeline: pipeline_id,
1369 material_bind_group_index: Some(material.binding.group.0),
1370 slabs: mesh_slabs,
1371 },
1372 OpaqueNoLightmap3dBinKey {
1373 asset_id: mesh_instance.mesh_asset_id().into(),
1374 },
1375 (*render_entity, *visible_entity),
1376 mesh_instance.current_uniform_index,
1377 BinnedRenderPhaseType::mesh(
1378 mesh_instance.should_batch(),
1379 &gpu_preprocessing_support,
1380 ),
1381 );
1382 }
1383 }
1384 _ => {}
1385 }
1386 }
1387 }
1388}
1389
1390pub struct SetPrepassViewBindGroup<const I: usize>;
1391impl<P: PhaseItem, const I: usize> RenderCommand<P> for SetPrepassViewBindGroup<I> {
1392 type Param = SRes<PrepassViewBindGroup>;
1393 type ViewQuery = (
1394 Read<ViewUniformOffset>,
1395 Has<MotionVectorPrepass>,
1396 Option<Read<PreviousViewUniformOffset>>,
1397 );
1398 type ItemQuery = ();
1399
1400 #[inline]
1401 fn render<'w>(
1402 _item: &P,
1403 (view_uniform_offset, has_motion_vector_prepass, previous_view_uniform_offset): (
1404 &'_ ViewUniformOffset,
1405 bool,
1406 Option<&'_ PreviousViewUniformOffset>,
1407 ),
1408 _entity: Option<()>,
1409 prepass_view_bind_group: SystemParamItem<'w, '_, Self::Param>,
1410 pass: &mut TrackedRenderPass<'w>,
1411 ) -> RenderCommandResult {
1412 let prepass_view_bind_group = prepass_view_bind_group.into_inner();
1413
1414 match previous_view_uniform_offset {
1415 Some(previous_view_uniform_offset) if has_motion_vector_prepass => {
1416 pass.set_bind_group(
1417 I,
1418 prepass_view_bind_group.motion_vectors.as_ref().unwrap(),
1419 &[
1420 view_uniform_offset.offset,
1421 previous_view_uniform_offset.offset,
1422 ],
1423 );
1424 }
1425 _ => {
1426 pass.set_bind_group(
1427 I,
1428 prepass_view_bind_group.no_motion_vectors.as_ref().unwrap(),
1429 &[view_uniform_offset.offset],
1430 );
1431 }
1432 }
1433 RenderCommandResult::Success
1434 }
1435}
1436
1437pub struct SetPrepassViewEmptyBindGroup<const I: usize>;
1438impl<P: PhaseItem, const I: usize> RenderCommand<P> for SetPrepassViewEmptyBindGroup<I> {
1439 type Param = SRes<PrepassViewBindGroup>;
1440 type ViewQuery = ();
1441 type ItemQuery = ();
1442
1443 #[inline]
1444 fn render<'w>(
1445 _item: &P,
1446 _view: (),
1447 _entity: Option<()>,
1448 prepass_view_bind_group: SystemParamItem<'w, '_, Self::Param>,
1449 pass: &mut TrackedRenderPass<'w>,
1450 ) -> RenderCommandResult {
1451 let prepass_view_bind_group = prepass_view_bind_group.into_inner();
1452 pass.set_bind_group(I, &prepass_view_bind_group.empty_bind_group, &[]);
1453 RenderCommandResult::Success
1454 }
1455}
1456
1457pub struct SetPrepassEmptyMaterialBindGroup<const I: usize>;
1458impl<P: PhaseItem, const I: usize> RenderCommand<P> for SetPrepassEmptyMaterialBindGroup<I> {
1459 type Param = SRes<PrepassViewBindGroup>;
1460 type ViewQuery = ();
1461 type ItemQuery = ();
1462
1463 #[inline]
1464 fn render<'w>(
1465 _item: &P,
1466 _view: (),
1467 _entity: Option<()>,
1468 prepass_view_bind_group: SystemParamItem<'w, '_, Self::Param>,
1469 pass: &mut TrackedRenderPass<'w>,
1470 ) -> RenderCommandResult {
1471 let prepass_view_bind_group = prepass_view_bind_group.into_inner();
1472 pass.set_bind_group(I, &prepass_view_bind_group.empty_bind_group, &[]);
1473 RenderCommandResult::Success
1474 }
1475}
1476
1477pub type DrawPrepass = (
1478 SetItemPipeline,
1479 SetPrepassViewBindGroup<0>,
1480 SetPrepassViewEmptyBindGroup<1>,
1481 SetMeshBindGroup<2>,
1482 SetMaterialBindGroup<3>,
1483 DrawMesh,
1484);
1485
1486pub type DrawDepthOnlyPrepass = (
1487 SetItemPipeline,
1488 SetPrepassViewBindGroup<0>,
1489 SetPrepassViewEmptyBindGroup<1>,
1490 SetMeshBindGroup<2>,
1491 SetPrepassEmptyMaterialBindGroup<3>,
1492 DrawMesh,
1493);