1use crate::material_bind_groups::{MaterialBindGroupIndex, MaterialBindGroupSlot};
2use bevy_asset::{embedded_asset, load_embedded_asset, AssetId};
3use bevy_camera::{
4 primitives::Aabb,
5 visibility::{NoFrustumCulling, RenderLayers, ViewVisibility, VisibilityRange},
6 Camera, Camera3d, Projection,
7};
8use bevy_core_pipeline::{
9 core_3d::{AlphaMask3d, Opaque3d, Transmissive3d, Transparent3d, CORE_3D_DEPTH_FORMAT},
10 deferred::{AlphaMask3dDeferred, Opaque3dDeferred},
11 oit::{prepare_oit_buffers, OrderIndependentTransparencySettingsOffset},
12 prepass::MotionVectorPrepass,
13};
14use bevy_derive::{Deref, DerefMut};
15use bevy_diagnostic::FrameCount;
16use bevy_ecs::{
17 prelude::*,
18 query::{QueryData, ROQueryItem},
19 system::{lifetimeless::*, SystemParamItem, SystemState},
20};
21use bevy_image::{BevyDefault, ImageSampler, TextureFormatPixelInfo};
22use bevy_light::{
23 EnvironmentMapLight, IrradianceVolume, NotShadowCaster, NotShadowReceiver,
24 ShadowFilteringMethod, TransmittedShadowReceiver,
25};
26use bevy_math::{Affine3, Rect, UVec2, Vec3, Vec4};
27use bevy_mesh::{
28 skinning::SkinnedMesh, BaseMeshPipelineKey, Mesh, Mesh3d, MeshTag, MeshVertexBufferLayoutRef,
29 VertexAttributeDescriptor,
30};
31use bevy_platform::collections::{hash_map::Entry, HashMap};
32use bevy_render::{
33 batching::{
34 gpu_preprocessing::{
35 self, GpuPreprocessingSupport, IndirectBatchSet, IndirectParametersBuffers,
36 IndirectParametersCpuMetadata, IndirectParametersIndexed, IndirectParametersNonIndexed,
37 InstanceInputUniformBuffer, UntypedPhaseIndirectParametersBuffers,
38 },
39 no_gpu_preprocessing, GetBatchData, GetFullBatchData, NoAutomaticBatching,
40 },
41 mesh::{allocator::MeshAllocator, RenderMesh, RenderMeshBufferInfo},
42 render_asset::RenderAssets,
43 render_phase::{
44 BinnedRenderPhasePlugin, InputUniformIndex, PhaseItem, PhaseItemExtraIndex, RenderCommand,
45 RenderCommandResult, SortedRenderPhasePlugin, TrackedRenderPass,
46 },
47 render_resource::*,
48 renderer::{RenderAdapter, RenderDevice, RenderQueue},
49 sync_world::MainEntityHashSet,
50 texture::{DefaultImageSampler, GpuImage},
51 view::{
52 self, NoIndirectDrawing, RenderVisibilityRanges, RetainedViewEntity, ViewTarget,
53 ViewUniformOffset,
54 },
55 Extract,
56};
57use bevy_shader::{load_shader_library, Shader, ShaderDefVal, ShaderSettings};
58use bevy_transform::components::GlobalTransform;
59use bevy_utils::{default, Parallel, TypeIdMap};
60use core::any::TypeId;
61use core::mem::size_of;
62use material_bind_groups::MaterialBindingId;
63use tracing::{error, warn};
64
65use self::irradiance_volume::IRRADIANCE_VOLUMES_ARE_USABLE;
66use crate::{
67 render::{
68 morph::{
69 extract_morphs, no_automatic_morph_batching, prepare_morphs, MorphIndices,
70 MorphUniforms,
71 },
72 skin::no_automatic_skin_batching,
73 },
74 *,
75};
76use bevy_core_pipeline::oit::OrderIndependentTransparencySettings;
77use bevy_core_pipeline::prepass::{DeferredPrepass, DepthPrepass, NormalPrepass};
78use bevy_core_pipeline::tonemapping::{DebandDither, Tonemapping};
79use bevy_ecs::component::Tick;
80use bevy_ecs::system::SystemChangeTick;
81use bevy_render::camera::TemporalJitter;
82use bevy_render::prelude::Msaa;
83use bevy_render::sync_world::{MainEntity, MainEntityHashMap};
84use bevy_render::view::ExtractedView;
85use bevy_render::RenderSystems::PrepareAssets;
86
87use bytemuck::{Pod, Zeroable};
88use nonmax::{NonMaxU16, NonMaxU32};
89use smallvec::{smallvec, SmallVec};
90use static_assertions::const_assert_eq;
91
92pub struct MeshRenderPlugin {
94 pub use_gpu_instance_buffer_builder: bool,
99 pub debug_flags: RenderDebugFlags,
101}
102
103impl MeshRenderPlugin {
104 pub fn new(debug_flags: RenderDebugFlags) -> MeshRenderPlugin {
106 MeshRenderPlugin {
107 use_gpu_instance_buffer_builder: false,
108 debug_flags,
109 }
110 }
111}
112
113#[cfg(debug_assertions)]
122pub const MESH_PIPELINE_VIEW_LAYOUT_SAFE_MAX_TEXTURES: usize = 10;
123
124impl Plugin for MeshRenderPlugin {
125 fn build(&self, app: &mut App) {
126 load_shader_library!(app, "forward_io.wgsl");
127 load_shader_library!(app, "mesh_view_types.wgsl", |settings| *settings =
128 ShaderSettings {
129 shader_defs: vec![
130 ShaderDefVal::UInt(
131 "MAX_DIRECTIONAL_LIGHTS".into(),
132 MAX_DIRECTIONAL_LIGHTS as u32
133 ),
134 ShaderDefVal::UInt(
135 "MAX_CASCADES_PER_LIGHT".into(),
136 MAX_CASCADES_PER_LIGHT as u32,
137 )
138 ]
139 });
140 load_shader_library!(app, "mesh_view_bindings.wgsl");
141 load_shader_library!(app, "mesh_types.wgsl");
142 load_shader_library!(app, "mesh_functions.wgsl");
143 load_shader_library!(app, "skinning.wgsl");
144 load_shader_library!(app, "morph.wgsl");
145 load_shader_library!(app, "occlusion_culling.wgsl");
146
147 embedded_asset!(app, "mesh.wgsl");
148
149 if app.get_sub_app(RenderApp).is_none() {
150 return;
151 }
152
153 app.add_systems(
154 PostUpdate,
155 (no_automatic_skin_batching, no_automatic_morph_batching),
156 )
157 .add_plugins((
158 BinnedRenderPhasePlugin::<Opaque3d, MeshPipeline>::new(self.debug_flags),
159 BinnedRenderPhasePlugin::<AlphaMask3d, MeshPipeline>::new(self.debug_flags),
160 BinnedRenderPhasePlugin::<Shadow, MeshPipeline>::new(self.debug_flags),
161 BinnedRenderPhasePlugin::<Opaque3dDeferred, MeshPipeline>::new(self.debug_flags),
162 BinnedRenderPhasePlugin::<AlphaMask3dDeferred, MeshPipeline>::new(self.debug_flags),
163 SortedRenderPhasePlugin::<Transmissive3d, MeshPipeline>::new(self.debug_flags),
164 SortedRenderPhasePlugin::<Transparent3d, MeshPipeline>::new(self.debug_flags),
165 ));
166
167 if let Some(render_app) = app.get_sub_app_mut(RenderApp) {
168 render_app
169 .init_resource::<MorphUniforms>()
170 .init_resource::<MorphIndices>()
171 .init_resource::<MeshCullingDataBuffer>()
172 .init_resource::<RenderMaterialInstances>()
173 .configure_sets(
174 ExtractSchedule,
175 MeshExtractionSystems
176 .after(view::extract_visibility_ranges)
177 .after(late_sweep_material_instances),
178 )
179 .add_systems(
180 ExtractSchedule,
181 (
182 extract_skins,
183 extract_morphs,
184 gpu_preprocessing::clear_batched_gpu_instance_buffers::<MeshPipeline>
185 .before(MeshExtractionSystems),
186 ),
187 )
188 .add_systems(
189 Render,
190 (
191 set_mesh_motion_vector_flags.in_set(RenderSystems::PrepareMeshes),
192 prepare_skins.in_set(RenderSystems::PrepareResources),
193 prepare_morphs.in_set(RenderSystems::PrepareResources),
194 prepare_mesh_bind_groups.in_set(RenderSystems::PrepareBindGroups),
195 prepare_mesh_view_bind_groups
196 .in_set(RenderSystems::PrepareBindGroups)
197 .after(prepare_oit_buffers),
198 no_gpu_preprocessing::clear_batched_cpu_instance_buffers::<MeshPipeline>
199 .in_set(RenderSystems::Cleanup)
200 .after(RenderSystems::Render),
201 ),
202 );
203 }
204 }
205
206 fn finish(&self, app: &mut App) {
207 let mut mesh_bindings_shader_defs = Vec::with_capacity(1);
208
209 if let Some(render_app) = app.get_sub_app_mut(RenderApp) {
210 render_app
211 .init_resource::<ViewKeyCache>()
212 .init_resource::<ViewSpecializationTicks>()
213 .init_resource::<GpuPreprocessingSupport>()
214 .init_resource::<SkinUniforms>()
215 .add_systems(
216 Render,
217 check_views_need_specialization.in_set(PrepareAssets),
218 );
219
220 let gpu_preprocessing_support =
221 render_app.world().resource::<GpuPreprocessingSupport>();
222 let use_gpu_instance_buffer_builder =
223 self.use_gpu_instance_buffer_builder && gpu_preprocessing_support.is_available();
224
225 let render_mesh_instances = RenderMeshInstances::new(use_gpu_instance_buffer_builder);
226 render_app.insert_resource(render_mesh_instances);
227
228 if use_gpu_instance_buffer_builder {
229 render_app
230 .init_resource::<gpu_preprocessing::BatchedInstanceBuffers<
231 MeshUniform,
232 MeshInputUniform
233 >>()
234 .init_resource::<RenderMeshInstanceGpuQueues>()
235 .init_resource::<MeshesToReextractNextFrame>()
236 .add_systems(
237 ExtractSchedule,
238 extract_meshes_for_gpu_building.in_set(MeshExtractionSystems),
239 )
240 .add_systems(
241 Render,
242 (
243 gpu_preprocessing::write_batched_instance_buffers::<MeshPipeline>
244 .in_set(RenderSystems::PrepareResourcesFlush),
245 gpu_preprocessing::delete_old_work_item_buffers::<MeshPipeline>
246 .in_set(RenderSystems::PrepareResources),
247 collect_meshes_for_gpu_building
248 .in_set(RenderSystems::PrepareMeshes)
249 .before(set_mesh_motion_vector_flags),
253 ),
254 );
255 } else {
256 let render_device = render_app.world().resource::<RenderDevice>();
257 let cpu_batched_instance_buffer =
258 no_gpu_preprocessing::BatchedInstanceBuffer::<MeshUniform>::new(render_device);
259 render_app
260 .insert_resource(cpu_batched_instance_buffer)
261 .add_systems(
262 ExtractSchedule,
263 extract_meshes_for_cpu_building.in_set(MeshExtractionSystems),
264 )
265 .add_systems(
266 Render,
267 no_gpu_preprocessing::write_batched_instance_buffer::<MeshPipeline>
268 .in_set(RenderSystems::PrepareResourcesFlush),
269 );
270 };
271
272 let render_device = render_app.world().resource::<RenderDevice>();
273 if let Some(per_object_buffer_batch_size) =
274 GpuArrayBuffer::<MeshUniform>::batch_size(render_device)
275 {
276 mesh_bindings_shader_defs.push(ShaderDefVal::UInt(
277 "PER_OBJECT_BUFFER_BATCH_SIZE".into(),
278 per_object_buffer_batch_size,
279 ));
280 }
281
282 render_app
283 .init_resource::<MeshPipelineViewLayouts>()
284 .init_resource::<MeshPipeline>();
285 }
286
287 load_shader_library!(app, "mesh_bindings.wgsl", move |settings| *settings =
290 ShaderSettings {
291 shader_defs: mesh_bindings_shader_defs.clone(),
292 });
293 }
294}
295
296#[derive(Resource, Deref, DerefMut, Default, Debug, Clone)]
297pub struct ViewKeyCache(HashMap<RetainedViewEntity, MeshPipelineKey>);
298
299#[derive(Resource, Deref, DerefMut, Default, Debug, Clone)]
300pub struct ViewSpecializationTicks(HashMap<RetainedViewEntity, Tick>);
301
302pub fn check_views_need_specialization(
303 mut view_key_cache: ResMut<ViewKeyCache>,
304 mut view_specialization_ticks: ResMut<ViewSpecializationTicks>,
305 mut views: Query<(
306 &ExtractedView,
307 &Msaa,
308 Option<&Tonemapping>,
309 Option<&DebandDither>,
310 Option<&ShadowFilteringMethod>,
311 Has<ScreenSpaceAmbientOcclusion>,
312 (
313 Has<NormalPrepass>,
314 Has<DepthPrepass>,
315 Has<MotionVectorPrepass>,
316 Has<DeferredPrepass>,
317 ),
318 Option<&Camera3d>,
319 Has<TemporalJitter>,
320 Option<&Projection>,
321 Has<DistanceFog>,
322 (
323 Has<RenderViewLightProbes<EnvironmentMapLight>>,
324 Has<RenderViewLightProbes<IrradianceVolume>>,
325 ),
326 Has<OrderIndependentTransparencySettings>,
327 )>,
328 ticks: SystemChangeTick,
329) {
330 for (
331 view,
332 msaa,
333 tonemapping,
334 dither,
335 shadow_filter_method,
336 ssao,
337 (normal_prepass, depth_prepass, motion_vector_prepass, deferred_prepass),
338 camera_3d,
339 temporal_jitter,
340 projection,
341 distance_fog,
342 (has_environment_maps, has_irradiance_volumes),
343 has_oit,
344 ) in views.iter_mut()
345 {
346 let mut view_key = MeshPipelineKey::from_msaa_samples(msaa.samples())
347 | MeshPipelineKey::from_hdr(view.hdr);
348
349 if normal_prepass {
350 view_key |= MeshPipelineKey::NORMAL_PREPASS;
351 }
352
353 if depth_prepass {
354 view_key |= MeshPipelineKey::DEPTH_PREPASS;
355 }
356
357 if motion_vector_prepass {
358 view_key |= MeshPipelineKey::MOTION_VECTOR_PREPASS;
359 }
360
361 if deferred_prepass {
362 view_key |= MeshPipelineKey::DEFERRED_PREPASS;
363 }
364
365 if temporal_jitter {
366 view_key |= MeshPipelineKey::TEMPORAL_JITTER;
367 }
368
369 if has_environment_maps {
370 view_key |= MeshPipelineKey::ENVIRONMENT_MAP;
371 }
372
373 if has_irradiance_volumes {
374 view_key |= MeshPipelineKey::IRRADIANCE_VOLUME;
375 }
376
377 if has_oit {
378 view_key |= MeshPipelineKey::OIT_ENABLED;
379 }
380
381 if let Some(projection) = projection {
382 view_key |= match projection {
383 Projection::Perspective(_) => MeshPipelineKey::VIEW_PROJECTION_PERSPECTIVE,
384 Projection::Orthographic(_) => MeshPipelineKey::VIEW_PROJECTION_ORTHOGRAPHIC,
385 Projection::Custom(_) => MeshPipelineKey::VIEW_PROJECTION_NONSTANDARD,
386 };
387 }
388
389 match shadow_filter_method.unwrap_or(&ShadowFilteringMethod::default()) {
390 ShadowFilteringMethod::Hardware2x2 => {
391 view_key |= MeshPipelineKey::SHADOW_FILTER_METHOD_HARDWARE_2X2;
392 }
393 ShadowFilteringMethod::Gaussian => {
394 view_key |= MeshPipelineKey::SHADOW_FILTER_METHOD_GAUSSIAN;
395 }
396 ShadowFilteringMethod::Temporal => {
397 view_key |= MeshPipelineKey::SHADOW_FILTER_METHOD_TEMPORAL;
398 }
399 }
400
401 if !view.hdr {
402 if let Some(tonemapping) = tonemapping {
403 view_key |= MeshPipelineKey::TONEMAP_IN_SHADER;
404 view_key |= tonemapping_pipeline_key(*tonemapping);
405 }
406 if let Some(DebandDither::Enabled) = dither {
407 view_key |= MeshPipelineKey::DEBAND_DITHER;
408 }
409 }
410 if ssao {
411 view_key |= MeshPipelineKey::SCREEN_SPACE_AMBIENT_OCCLUSION;
412 }
413 if distance_fog {
414 view_key |= MeshPipelineKey::DISTANCE_FOG;
415 }
416 if let Some(camera_3d) = camera_3d {
417 view_key |= screen_space_specular_transmission_pipeline_key(
418 camera_3d.screen_space_specular_transmission_quality,
419 );
420 }
421 if !view_key_cache
422 .get_mut(&view.retained_view_entity)
423 .is_some_and(|current_key| *current_key == view_key)
424 {
425 view_key_cache.insert(view.retained_view_entity, view_key);
426 view_specialization_ticks.insert(view.retained_view_entity, ticks.this_run());
427 }
428 }
429}
430
431#[derive(Component)]
432pub struct MeshTransforms {
433 pub world_from_local: Affine3,
434 pub previous_world_from_local: Affine3,
435 pub flags: u32,
436}
437
438#[derive(ShaderType, Clone)]
439pub struct MeshUniform {
440 pub world_from_local: [Vec4; 3],
442 pub previous_world_from_local: [Vec4; 3],
443 pub local_from_world_transpose_a: [Vec4; 2],
448 pub local_from_world_transpose_b: f32,
449 pub flags: u32,
450 pub lightmap_uv_rect: UVec2,
460 pub first_vertex_index: u32,
466 pub current_skin_index: u32,
468 pub material_and_lightmap_bind_group_slot: u32,
473 pub tag: u32,
475 pub pad: u32,
477}
478
479#[derive(ShaderType, Pod, Zeroable, Clone, Copy, Default, Debug)]
484#[repr(C)]
485pub struct MeshInputUniform {
486 pub world_from_local: [Vec4; 3],
488 pub lightmap_uv_rect: UVec2,
500 pub flags: u32,
502 pub previous_input_index: u32,
507 pub first_vertex_index: u32,
513 pub first_index_index: u32,
521 pub index_count: u32,
524 pub current_skin_index: u32,
526 pub material_and_lightmap_bind_group_slot: u32,
531 pub timestamp: u32,
539 pub tag: u32,
541 pub pad: u32,
543}
544
545#[derive(ShaderType, Pod, Zeroable, Clone, Copy, Default)]
549#[repr(C)]
550pub struct MeshCullingData {
551 pub aabb_center: Vec4,
554 pub aabb_half_extents: Vec4,
557}
558
559#[derive(Resource, Deref, DerefMut)]
566pub struct MeshCullingDataBuffer(RawBufferVec<MeshCullingData>);
567
568impl MeshUniform {
569 pub fn new(
570 mesh_transforms: &MeshTransforms,
571 first_vertex_index: u32,
572 material_bind_group_slot: MaterialBindGroupSlot,
573 maybe_lightmap: Option<(LightmapSlotIndex, Rect)>,
574 current_skin_index: Option<u32>,
575 tag: Option<u32>,
576 ) -> Self {
577 let (local_from_world_transpose_a, local_from_world_transpose_b) =
578 mesh_transforms.world_from_local.inverse_transpose_3x3();
579 let lightmap_bind_group_slot = match maybe_lightmap {
580 None => u16::MAX,
581 Some((slot_index, _)) => slot_index.into(),
582 };
583
584 Self {
585 world_from_local: mesh_transforms.world_from_local.to_transpose(),
586 previous_world_from_local: mesh_transforms.previous_world_from_local.to_transpose(),
587 lightmap_uv_rect: pack_lightmap_uv_rect(maybe_lightmap.map(|(_, uv_rect)| uv_rect)),
588 local_from_world_transpose_a,
589 local_from_world_transpose_b,
590 flags: mesh_transforms.flags,
591 first_vertex_index,
592 current_skin_index: current_skin_index.unwrap_or(u32::MAX),
593 material_and_lightmap_bind_group_slot: u32::from(material_bind_group_slot)
594 | ((lightmap_bind_group_slot as u32) << 16),
595 tag: tag.unwrap_or(0),
596 pad: 0,
597 }
598 }
599}
600
601bitflags::bitflags! {
603 #[repr(transparent)]
608 pub struct MeshFlags: u32 {
609 const LOD_INDEX_MASK = (1 << 16) - 1;
613 const NO_FRUSTUM_CULLING = 1 << 28;
618 const SHADOW_RECEIVER = 1 << 29;
619 const TRANSMITTED_SHADOW_RECEIVER = 1 << 30;
620 const SIGN_DETERMINANT_MODEL_3X3 = 1 << 31;
623 const NONE = 0;
624 const UNINITIALIZED = 0xFFFFFFFF;
625 }
626}
627
628impl MeshFlags {
629 fn from_components(
630 transform: &GlobalTransform,
631 lod_index: Option<NonMaxU16>,
632 no_frustum_culling: bool,
633 not_shadow_receiver: bool,
634 transmitted_receiver: bool,
635 ) -> MeshFlags {
636 let mut mesh_flags = if not_shadow_receiver {
637 MeshFlags::empty()
638 } else {
639 MeshFlags::SHADOW_RECEIVER
640 };
641 if no_frustum_culling {
642 mesh_flags |= MeshFlags::NO_FRUSTUM_CULLING;
643 }
644 if transmitted_receiver {
645 mesh_flags |= MeshFlags::TRANSMITTED_SHADOW_RECEIVER;
646 }
647 if transform.affine().matrix3.determinant().is_sign_positive() {
648 mesh_flags |= MeshFlags::SIGN_DETERMINANT_MODEL_3X3;
649 }
650
651 let lod_index_bits = match lod_index {
652 None => u16::MAX,
653 Some(lod_index) => u16::from(lod_index),
654 };
655 mesh_flags |=
656 MeshFlags::from_bits_retain((lod_index_bits as u32) << MeshFlags::LOD_INDEX_SHIFT);
657
658 mesh_flags
659 }
660
661 pub const LOD_INDEX_SHIFT: u32 = 0;
663}
664
665bitflags::bitflags! {
666 #[derive(Clone, Copy)]
668 pub struct RenderMeshInstanceFlags: u8 {
669 const SHADOW_CASTER = 1 << 0;
671 const AUTOMATIC_BATCHING = 1 << 1;
673 const HAS_PREVIOUS_TRANSFORM = 1 << 2;
676 const HAS_PREVIOUS_SKIN = 1 << 3;
679 const HAS_PREVIOUS_MORPH = 1 << 4;
682 }
683}
684
685#[derive(Deref, DerefMut)]
688pub struct RenderMeshInstanceCpu {
689 #[deref]
692 pub shared: RenderMeshInstanceShared,
693 pub transforms: MeshTransforms,
697}
698
699#[derive(Deref, DerefMut)]
702pub struct RenderMeshInstanceGpu {
703 #[deref]
706 pub shared: RenderMeshInstanceShared,
707 pub translation: Vec3,
712 pub current_uniform_index: NonMaxU32,
714}
715
716pub struct RenderMeshInstanceShared {
719 pub mesh_asset_id: AssetId<Mesh>,
721 pub material_bindings_index: MaterialBindingId,
723 pub flags: RenderMeshInstanceFlags,
725 pub lightmap_slab_index: Option<LightmapSlabIndex>,
728 pub tag: u32,
730 pub render_layers: Option<RenderLayers>,
732}
733
734pub struct RenderMeshInstanceGpuBuilder {
740 pub shared: RenderMeshInstanceShared,
742 pub world_from_local: Affine3,
744 pub lightmap_uv_rect: UVec2,
756 pub previous_input_index: Option<NonMaxU32>,
758 pub mesh_flags: MeshFlags,
760}
761
762#[derive(Default)]
768pub enum RenderMeshInstanceGpuQueue {
769 #[default]
774 None,
775 CpuCulling {
779 changed: Vec<(MainEntity, RenderMeshInstanceGpuBuilder)>,
783 removed: Vec<MainEntity>,
785 },
786 GpuCulling {
790 changed: Vec<(MainEntity, RenderMeshInstanceGpuBuilder, MeshCullingData)>,
794 removed: Vec<MainEntity>,
796 },
797}
798
799#[derive(Resource, Default, Deref, DerefMut)]
805pub struct RenderMeshInstanceGpuQueues(Parallel<RenderMeshInstanceGpuQueue>);
806
807#[derive(Resource, Default, Deref, DerefMut)]
812pub struct MeshesToReextractNextFrame(MainEntityHashSet);
813
814impl RenderMeshInstanceShared {
815 fn for_gpu_building(
818 previous_transform: Option<&PreviousGlobalTransform>,
819 mesh: &Mesh3d,
820 tag: Option<&MeshTag>,
821 not_shadow_caster: bool,
822 no_automatic_batching: bool,
823 render_layers: Option<&RenderLayers>,
824 ) -> Self {
825 Self::for_cpu_building(
826 previous_transform,
827 mesh,
828 tag,
829 default(),
830 not_shadow_caster,
831 no_automatic_batching,
832 render_layers,
833 )
834 }
835
836 fn for_cpu_building(
838 previous_transform: Option<&PreviousGlobalTransform>,
839 mesh: &Mesh3d,
840 tag: Option<&MeshTag>,
841 material_bindings_index: MaterialBindingId,
842 not_shadow_caster: bool,
843 no_automatic_batching: bool,
844 render_layers: Option<&RenderLayers>,
845 ) -> Self {
846 let mut mesh_instance_flags = RenderMeshInstanceFlags::empty();
847 mesh_instance_flags.set(RenderMeshInstanceFlags::SHADOW_CASTER, !not_shadow_caster);
848 mesh_instance_flags.set(
849 RenderMeshInstanceFlags::AUTOMATIC_BATCHING,
850 !no_automatic_batching,
851 );
852 mesh_instance_flags.set(
853 RenderMeshInstanceFlags::HAS_PREVIOUS_TRANSFORM,
854 previous_transform.is_some(),
855 );
856
857 RenderMeshInstanceShared {
858 mesh_asset_id: mesh.id(),
859 flags: mesh_instance_flags,
860 material_bindings_index,
861 lightmap_slab_index: None,
862 tag: tag.map_or(0, |i| **i),
863 render_layers: render_layers.cloned(),
864 }
865 }
866
867 #[inline]
870 pub fn should_batch(&self) -> bool {
871 self.flags
872 .contains(RenderMeshInstanceFlags::AUTOMATIC_BATCHING)
873 }
874}
875
876#[derive(Resource)]
882pub enum RenderMeshInstances {
883 CpuBuilding(RenderMeshInstancesCpu),
885 GpuBuilding(RenderMeshInstancesGpu),
887}
888
889#[derive(Default, Deref, DerefMut)]
892pub struct RenderMeshInstancesCpu(MainEntityHashMap<RenderMeshInstanceCpu>);
893
894#[derive(Default, Deref, DerefMut)]
897pub struct RenderMeshInstancesGpu(MainEntityHashMap<RenderMeshInstanceGpu>);
898
899impl RenderMeshInstances {
900 fn new(use_gpu_instance_buffer_builder: bool) -> RenderMeshInstances {
902 if use_gpu_instance_buffer_builder {
903 RenderMeshInstances::GpuBuilding(RenderMeshInstancesGpu::default())
904 } else {
905 RenderMeshInstances::CpuBuilding(RenderMeshInstancesCpu::default())
906 }
907 }
908
909 pub fn mesh_asset_id(&self, entity: MainEntity) -> Option<AssetId<Mesh>> {
911 match *self {
912 RenderMeshInstances::CpuBuilding(ref instances) => instances.mesh_asset_id(entity),
913 RenderMeshInstances::GpuBuilding(ref instances) => instances.mesh_asset_id(entity),
914 }
915 }
916
917 pub fn render_mesh_queue_data(&self, entity: MainEntity) -> Option<RenderMeshQueueData<'_>> {
920 match *self {
921 RenderMeshInstances::CpuBuilding(ref instances) => {
922 instances.render_mesh_queue_data(entity)
923 }
924 RenderMeshInstances::GpuBuilding(ref instances) => {
925 instances.render_mesh_queue_data(entity)
926 }
927 }
928 }
929
930 fn insert_mesh_instance_flags(&mut self, entity: MainEntity, flags: RenderMeshInstanceFlags) {
933 match *self {
934 RenderMeshInstances::CpuBuilding(ref mut instances) => {
935 instances.insert_mesh_instance_flags(entity, flags);
936 }
937 RenderMeshInstances::GpuBuilding(ref mut instances) => {
938 instances.insert_mesh_instance_flags(entity, flags);
939 }
940 }
941 }
942}
943
944impl RenderMeshInstancesCpu {
945 fn mesh_asset_id(&self, entity: MainEntity) -> Option<AssetId<Mesh>> {
946 self.get(&entity)
947 .map(|render_mesh_instance| render_mesh_instance.mesh_asset_id)
948 }
949
950 fn render_mesh_queue_data(&self, entity: MainEntity) -> Option<RenderMeshQueueData<'_>> {
951 self.get(&entity)
952 .map(|render_mesh_instance| RenderMeshQueueData {
953 shared: &render_mesh_instance.shared,
954 translation: render_mesh_instance.transforms.world_from_local.translation,
955 current_uniform_index: InputUniformIndex::default(),
956 })
957 }
958
959 fn insert_mesh_instance_flags(&mut self, entity: MainEntity, flags: RenderMeshInstanceFlags) {
962 if let Some(instance) = self.get_mut(&entity) {
963 instance.flags.insert(flags);
964 }
965 }
966}
967
968impl RenderMeshInstancesGpu {
969 fn mesh_asset_id(&self, entity: MainEntity) -> Option<AssetId<Mesh>> {
970 self.get(&entity)
971 .map(|render_mesh_instance| render_mesh_instance.mesh_asset_id)
972 }
973
974 fn render_mesh_queue_data(&self, entity: MainEntity) -> Option<RenderMeshQueueData<'_>> {
975 self.get(&entity)
976 .map(|render_mesh_instance| RenderMeshQueueData {
977 shared: &render_mesh_instance.shared,
978 translation: render_mesh_instance.translation,
979 current_uniform_index: InputUniformIndex(
980 render_mesh_instance.current_uniform_index.into(),
981 ),
982 })
983 }
984
985 fn insert_mesh_instance_flags(&mut self, entity: MainEntity, flags: RenderMeshInstanceFlags) {
988 if let Some(instance) = self.get_mut(&entity) {
989 instance.flags.insert(flags);
990 }
991 }
992}
993
994impl RenderMeshInstanceGpuQueue {
995 fn init(&mut self, any_gpu_culling: bool) {
1001 match (any_gpu_culling, &mut *self) {
1002 (true, RenderMeshInstanceGpuQueue::GpuCulling { changed, removed }) => {
1003 changed.clear();
1004 removed.clear();
1005 }
1006 (true, _) => {
1007 *self = RenderMeshInstanceGpuQueue::GpuCulling {
1008 changed: vec![],
1009 removed: vec![],
1010 }
1011 }
1012 (false, RenderMeshInstanceGpuQueue::CpuCulling { changed, removed }) => {
1013 changed.clear();
1014 removed.clear();
1015 }
1016 (false, _) => {
1017 *self = RenderMeshInstanceGpuQueue::CpuCulling {
1018 changed: vec![],
1019 removed: vec![],
1020 }
1021 }
1022 }
1023 }
1024
1025 fn push(
1027 &mut self,
1028 entity: MainEntity,
1029 instance_builder: RenderMeshInstanceGpuBuilder,
1030 culling_data_builder: Option<MeshCullingData>,
1031 ) {
1032 match (&mut *self, culling_data_builder) {
1033 (
1034 &mut RenderMeshInstanceGpuQueue::CpuCulling {
1035 changed: ref mut queue,
1036 ..
1037 },
1038 None,
1039 ) => {
1040 queue.push((entity, instance_builder));
1041 }
1042 (
1043 &mut RenderMeshInstanceGpuQueue::GpuCulling {
1044 changed: ref mut queue,
1045 ..
1046 },
1047 Some(culling_data_builder),
1048 ) => {
1049 queue.push((entity, instance_builder, culling_data_builder));
1050 }
1051 (_, None) => {
1052 *self = RenderMeshInstanceGpuQueue::CpuCulling {
1053 changed: vec![(entity, instance_builder)],
1054 removed: vec![],
1055 };
1056 }
1057 (_, Some(culling_data_builder)) => {
1058 *self = RenderMeshInstanceGpuQueue::GpuCulling {
1059 changed: vec![(entity, instance_builder, culling_data_builder)],
1060 removed: vec![],
1061 };
1062 }
1063 }
1064 }
1065
1066 fn remove(&mut self, entity: MainEntity, gpu_culling: bool) {
1070 match (&mut *self, gpu_culling) {
1071 (RenderMeshInstanceGpuQueue::None, false) => {
1072 *self = RenderMeshInstanceGpuQueue::CpuCulling {
1073 changed: vec![],
1074 removed: vec![entity],
1075 }
1076 }
1077 (RenderMeshInstanceGpuQueue::None, true) => {
1078 *self = RenderMeshInstanceGpuQueue::GpuCulling {
1079 changed: vec![],
1080 removed: vec![entity],
1081 }
1082 }
1083 (RenderMeshInstanceGpuQueue::CpuCulling { removed, .. }, _)
1084 | (RenderMeshInstanceGpuQueue::GpuCulling { removed, .. }, _) => {
1085 removed.push(entity);
1086 }
1087 }
1088 }
1089}
1090
1091impl RenderMeshInstanceGpuBuilder {
1092 fn update(
1095 mut self,
1096 entity: MainEntity,
1097 render_mesh_instances: &mut MainEntityHashMap<RenderMeshInstanceGpu>,
1098 current_input_buffer: &mut InstanceInputUniformBuffer<MeshInputUniform>,
1099 previous_input_buffer: &mut InstanceInputUniformBuffer<MeshInputUniform>,
1100 mesh_allocator: &MeshAllocator,
1101 mesh_material_ids: &RenderMaterialInstances,
1102 render_material_bindings: &RenderMaterialBindings,
1103 render_lightmaps: &RenderLightmaps,
1104 skin_uniforms: &SkinUniforms,
1105 timestamp: FrameCount,
1106 meshes_to_reextract_next_frame: &mut MeshesToReextractNextFrame,
1107 ) -> Option<u32> {
1108 let (first_vertex_index, vertex_count) =
1109 match mesh_allocator.mesh_vertex_slice(&self.shared.mesh_asset_id) {
1110 Some(mesh_vertex_slice) => (
1111 mesh_vertex_slice.range.start,
1112 mesh_vertex_slice.range.end - mesh_vertex_slice.range.start,
1113 ),
1114 None => (0, 0),
1115 };
1116 let (mesh_is_indexed, first_index_index, index_count) =
1117 match mesh_allocator.mesh_index_slice(&self.shared.mesh_asset_id) {
1118 Some(mesh_index_slice) => (
1119 true,
1120 mesh_index_slice.range.start,
1121 mesh_index_slice.range.end - mesh_index_slice.range.start,
1122 ),
1123 None => (false, 0, 0),
1124 };
1125 let current_skin_index = match skin_uniforms.skin_byte_offset(entity) {
1126 Some(skin_index) => skin_index.index(),
1127 None => u32::MAX,
1128 };
1129
1130 let mesh_material = mesh_material_ids.mesh_material(entity);
1135 let mesh_material_binding_id = if mesh_material != DUMMY_MESH_MATERIAL.untyped() {
1136 match render_material_bindings.get(&mesh_material) {
1137 Some(binding_id) => *binding_id,
1138 None => {
1139 meshes_to_reextract_next_frame.insert(entity);
1140 return None;
1141 }
1142 }
1143 } else {
1144 MaterialBindingId::default()
1146 };
1147 self.shared.material_bindings_index = mesh_material_binding_id;
1148
1149 let lightmap_slot = match render_lightmaps.render_lightmaps.get(&entity) {
1150 Some(render_lightmap) => u16::from(*render_lightmap.slot_index),
1151 None => u16::MAX,
1152 };
1153 let lightmap_slab_index = render_lightmaps
1154 .render_lightmaps
1155 .get(&entity)
1156 .map(|lightmap| lightmap.slab_index);
1157 self.shared.lightmap_slab_index = lightmap_slab_index;
1158
1159 let mut mesh_input_uniform = MeshInputUniform {
1161 world_from_local: self.world_from_local.to_transpose(),
1162 lightmap_uv_rect: self.lightmap_uv_rect,
1163 flags: self.mesh_flags.bits(),
1164 previous_input_index: u32::MAX,
1165 timestamp: timestamp.0,
1166 first_vertex_index,
1167 first_index_index,
1168 index_count: if mesh_is_indexed {
1169 index_count
1170 } else {
1171 vertex_count
1172 },
1173 current_skin_index,
1174 material_and_lightmap_bind_group_slot: u32::from(
1175 self.shared.material_bindings_index.slot,
1176 ) | ((lightmap_slot as u32) << 16),
1177 tag: self.shared.tag,
1178 pad: 0,
1179 };
1180
1181 let current_uniform_index;
1183 match render_mesh_instances.entry(entity) {
1184 Entry::Occupied(mut occupied_entry) => {
1185 current_uniform_index = u32::from(occupied_entry.get_mut().current_uniform_index);
1189
1190 let previous_mesh_input_uniform =
1193 current_input_buffer.get_unchecked(current_uniform_index);
1194 let previous_input_index = previous_input_buffer.add(previous_mesh_input_uniform);
1195 mesh_input_uniform.previous_input_index = previous_input_index;
1196
1197 current_input_buffer.set(current_uniform_index, mesh_input_uniform);
1199
1200 occupied_entry.replace_entry_with(|_, _| {
1201 Some(RenderMeshInstanceGpu {
1202 translation: self.world_from_local.translation,
1203 shared: self.shared,
1204 current_uniform_index: NonMaxU32::new(current_uniform_index)
1205 .unwrap_or_default(),
1206 })
1207 });
1208 }
1209
1210 Entry::Vacant(vacant_entry) => {
1211 current_uniform_index = current_input_buffer.add(mesh_input_uniform);
1213
1214 vacant_entry.insert(RenderMeshInstanceGpu {
1215 translation: self.world_from_local.translation,
1216 shared: self.shared,
1217 current_uniform_index: NonMaxU32::new(current_uniform_index)
1218 .unwrap_or_default(),
1219 });
1220 }
1221 }
1222
1223 Some(current_uniform_index)
1224 }
1225}
1226
1227fn remove_mesh_input_uniform(
1230 entity: MainEntity,
1231 render_mesh_instances: &mut MainEntityHashMap<RenderMeshInstanceGpu>,
1232 current_input_buffer: &mut InstanceInputUniformBuffer<MeshInputUniform>,
1233) -> Option<u32> {
1234 let removed_render_mesh_instance = render_mesh_instances.remove(&entity)?;
1236
1237 let removed_uniform_index = removed_render_mesh_instance.current_uniform_index.get();
1238 current_input_buffer.remove(removed_uniform_index);
1239 Some(removed_uniform_index)
1240}
1241
1242impl MeshCullingData {
1243 fn new(aabb: Option<&Aabb>) -> Self {
1248 match aabb {
1249 Some(aabb) => MeshCullingData {
1250 aabb_center: aabb.center.extend(0.0),
1251 aabb_half_extents: aabb.half_extents.extend(0.0),
1252 },
1253 None => MeshCullingData {
1254 aabb_center: Vec3::ZERO.extend(0.0),
1255 aabb_half_extents: Vec3::INFINITY.extend(0.0),
1256 },
1257 }
1258 }
1259
1260 fn update(
1263 &self,
1264 mesh_culling_data_buffer: &mut MeshCullingDataBuffer,
1265 instance_data_index: usize,
1266 ) {
1267 while mesh_culling_data_buffer.len() < instance_data_index + 1 {
1268 mesh_culling_data_buffer.push(MeshCullingData::default());
1269 }
1270 mesh_culling_data_buffer.values_mut()[instance_data_index] = *self;
1271 }
1272}
1273
1274impl Default for MeshCullingDataBuffer {
1275 #[inline]
1276 fn default() -> Self {
1277 Self(RawBufferVec::new(BufferUsages::STORAGE))
1278 }
1279}
1280
1281#[derive(Deref)]
1284pub struct RenderMeshQueueData<'a> {
1285 #[deref]
1287 pub shared: &'a RenderMeshInstanceShared,
1288 pub translation: Vec3,
1290 pub current_uniform_index: InputUniformIndex,
1293}
1294
1295#[derive(SystemSet, Clone, PartialEq, Eq, Debug, Hash)]
1298pub struct MeshExtractionSystems;
1299
1300#[deprecated(since = "0.17.0", note = "Renamed to `MeshExtractionSystems`.")]
1302pub type ExtractMeshesSet = MeshExtractionSystems;
1303
1304pub fn extract_meshes_for_cpu_building(
1310 mut render_mesh_instances: ResMut<RenderMeshInstances>,
1311 mesh_material_ids: Res<RenderMaterialInstances>,
1312 render_material_bindings: Res<RenderMaterialBindings>,
1313 render_visibility_ranges: Res<RenderVisibilityRanges>,
1314 mut render_mesh_instance_queues: Local<Parallel<Vec<(Entity, RenderMeshInstanceCpu)>>>,
1315 meshes_query: Extract<
1316 Query<(
1317 Entity,
1318 &ViewVisibility,
1319 &GlobalTransform,
1320 Option<&PreviousGlobalTransform>,
1321 &Mesh3d,
1322 Option<&MeshTag>,
1323 Has<NoFrustumCulling>,
1324 Has<NotShadowReceiver>,
1325 Has<TransmittedShadowReceiver>,
1326 Has<NotShadowCaster>,
1327 Has<NoAutomaticBatching>,
1328 Has<VisibilityRange>,
1329 Option<&RenderLayers>,
1330 )>,
1331 >,
1332) {
1333 meshes_query.par_iter().for_each_init(
1334 || render_mesh_instance_queues.borrow_local_mut(),
1335 |queue,
1336 (
1337 entity,
1338 view_visibility,
1339 transform,
1340 previous_transform,
1341 mesh,
1342 tag,
1343 no_frustum_culling,
1344 not_shadow_receiver,
1345 transmitted_receiver,
1346 not_shadow_caster,
1347 no_automatic_batching,
1348 visibility_range,
1349 render_layers,
1350 )| {
1351 if !view_visibility.get() {
1352 return;
1353 }
1354
1355 let mut lod_index = None;
1356 if visibility_range {
1357 lod_index = render_visibility_ranges.lod_index_for_entity(entity.into());
1358 }
1359
1360 let mesh_flags = MeshFlags::from_components(
1361 transform,
1362 lod_index,
1363 no_frustum_culling,
1364 not_shadow_receiver,
1365 transmitted_receiver,
1366 );
1367
1368 let mesh_material = mesh_material_ids.mesh_material(MainEntity::from(entity));
1369
1370 let material_bindings_index = render_material_bindings
1371 .get(&mesh_material)
1372 .copied()
1373 .unwrap_or_default();
1374
1375 let shared = RenderMeshInstanceShared::for_cpu_building(
1376 previous_transform,
1377 mesh,
1378 tag,
1379 material_bindings_index,
1380 not_shadow_caster,
1381 no_automatic_batching,
1382 render_layers,
1383 );
1384
1385 let world_from_local = transform.affine();
1386 queue.push((
1387 entity,
1388 RenderMeshInstanceCpu {
1389 transforms: MeshTransforms {
1390 world_from_local: (&world_from_local).into(),
1391 previous_world_from_local: (&previous_transform
1392 .map(|t| t.0)
1393 .unwrap_or(world_from_local))
1394 .into(),
1395 flags: mesh_flags.bits(),
1396 },
1397 shared,
1398 },
1399 ));
1400 },
1401 );
1402
1403 let RenderMeshInstances::CpuBuilding(ref mut render_mesh_instances) = *render_mesh_instances
1405 else {
1406 panic!(
1407 "`extract_meshes_for_cpu_building` should only be called if we're using CPU \
1408 `MeshUniform` building"
1409 );
1410 };
1411
1412 render_mesh_instances.clear();
1413 for queue in render_mesh_instance_queues.iter_mut() {
1414 for (entity, render_mesh_instance) in queue.drain(..) {
1415 render_mesh_instances.insert(entity.into(), render_mesh_instance);
1416 }
1417 }
1418}
1419
1420type GpuMeshExtractionQuery = (
1422 Entity,
1423 Read<ViewVisibility>,
1424 Read<GlobalTransform>,
1425 Option<Read<PreviousGlobalTransform>>,
1426 Option<Read<Lightmap>>,
1427 Option<Read<Aabb>>,
1428 Read<Mesh3d>,
1429 Option<Read<MeshTag>>,
1430 Has<NoFrustumCulling>,
1431 Has<NotShadowReceiver>,
1432 Has<TransmittedShadowReceiver>,
1433 Has<NotShadowCaster>,
1434 Has<NoAutomaticBatching>,
1435 Has<VisibilityRange>,
1436 Option<Read<RenderLayers>>,
1437);
1438
1439pub fn extract_meshes_for_gpu_building(
1448 mut render_mesh_instances: ResMut<RenderMeshInstances>,
1449 render_visibility_ranges: Res<RenderVisibilityRanges>,
1450 mut render_mesh_instance_queues: ResMut<RenderMeshInstanceGpuQueues>,
1451 changed_meshes_query: Extract<
1452 Query<
1453 GpuMeshExtractionQuery,
1454 Or<(
1455 Changed<ViewVisibility>,
1456 Changed<GlobalTransform>,
1457 Changed<PreviousGlobalTransform>,
1458 Changed<Lightmap>,
1459 Changed<Aabb>,
1460 Changed<Mesh3d>,
1461 Changed<MeshTag>,
1462 Changed<NoFrustumCulling>,
1463 Changed<NotShadowReceiver>,
1464 Changed<TransmittedShadowReceiver>,
1465 Changed<NotShadowCaster>,
1466 Changed<NoAutomaticBatching>,
1467 Changed<VisibilityRange>,
1468 Changed<SkinnedMesh>,
1469 )>,
1470 >,
1471 >,
1472 all_meshes_query: Extract<Query<GpuMeshExtractionQuery>>,
1473 mut removed_meshes_query: Extract<RemovedComponents<Mesh3d>>,
1474 gpu_culling_query: Extract<Query<(), (With<Camera>, Without<NoIndirectDrawing>)>>,
1475 meshes_to_reextract_next_frame: ResMut<MeshesToReextractNextFrame>,
1476) {
1477 let any_gpu_culling = !gpu_culling_query.is_empty();
1478
1479 for render_mesh_instance_queue in render_mesh_instance_queues.iter_mut() {
1480 render_mesh_instance_queue.init(any_gpu_culling);
1481 }
1482
1483 let RenderMeshInstances::GpuBuilding(ref mut render_mesh_instances) = *render_mesh_instances
1486 else {
1487 panic!(
1488 "`extract_meshes_for_gpu_building` should only be called if we're \
1489 using GPU `MeshUniform` building"
1490 );
1491 };
1492
1493 changed_meshes_query.par_iter().for_each_init(
1496 || render_mesh_instance_queues.borrow_local_mut(),
1497 |queue, query_row| {
1498 extract_mesh_for_gpu_building(
1499 query_row,
1500 &render_visibility_ranges,
1501 render_mesh_instances,
1502 queue,
1503 any_gpu_culling,
1504 );
1505 },
1506 );
1507
1508 let mut queue = render_mesh_instance_queues.borrow_local_mut();
1515 for &mesh_entity in &**meshes_to_reextract_next_frame {
1516 if let Ok(query_row) = all_meshes_query.get(*mesh_entity) {
1517 extract_mesh_for_gpu_building(
1518 query_row,
1519 &render_visibility_ranges,
1520 render_mesh_instances,
1521 &mut queue,
1522 any_gpu_culling,
1523 );
1524 }
1525 }
1526
1527 for entity in removed_meshes_query.read() {
1529 let entity = MainEntity::from(entity);
1533 if !changed_meshes_query.contains(*entity)
1534 && !meshes_to_reextract_next_frame.contains(&entity)
1535 {
1536 queue.remove(entity, any_gpu_culling);
1537 }
1538 }
1539}
1540
1541fn extract_mesh_for_gpu_building(
1542 (
1543 entity,
1544 view_visibility,
1545 transform,
1546 previous_transform,
1547 lightmap,
1548 aabb,
1549 mesh,
1550 tag,
1551 no_frustum_culling,
1552 not_shadow_receiver,
1553 transmitted_receiver,
1554 not_shadow_caster,
1555 no_automatic_batching,
1556 visibility_range,
1557 render_layers,
1558 ): <GpuMeshExtractionQuery as QueryData>::Item<'_, '_>,
1559 render_visibility_ranges: &RenderVisibilityRanges,
1560 render_mesh_instances: &RenderMeshInstancesGpu,
1561 queue: &mut RenderMeshInstanceGpuQueue,
1562 any_gpu_culling: bool,
1563) {
1564 if !view_visibility.get() {
1565 queue.remove(entity.into(), any_gpu_culling);
1566 return;
1567 }
1568
1569 let mut lod_index = None;
1570 if visibility_range {
1571 lod_index = render_visibility_ranges.lod_index_for_entity(entity.into());
1572 }
1573
1574 let mesh_flags = MeshFlags::from_components(
1575 transform,
1576 lod_index,
1577 no_frustum_culling,
1578 not_shadow_receiver,
1579 transmitted_receiver,
1580 );
1581
1582 let shared = RenderMeshInstanceShared::for_gpu_building(
1583 previous_transform,
1584 mesh,
1585 tag,
1586 not_shadow_caster,
1587 no_automatic_batching,
1588 render_layers,
1589 );
1590
1591 let lightmap_uv_rect = pack_lightmap_uv_rect(lightmap.map(|lightmap| lightmap.uv_rect));
1592
1593 let gpu_mesh_culling_data = any_gpu_culling.then(|| MeshCullingData::new(aabb));
1594
1595 let previous_input_index = if shared
1596 .flags
1597 .contains(RenderMeshInstanceFlags::HAS_PREVIOUS_TRANSFORM)
1598 {
1599 render_mesh_instances
1600 .get(&MainEntity::from(entity))
1601 .map(|render_mesh_instance| render_mesh_instance.current_uniform_index)
1602 } else {
1603 None
1604 };
1605
1606 let gpu_mesh_instance_builder = RenderMeshInstanceGpuBuilder {
1607 shared,
1608 world_from_local: (&transform.affine()).into(),
1609 lightmap_uv_rect,
1610 mesh_flags,
1611 previous_input_index,
1612 };
1613
1614 queue.push(
1615 entity.into(),
1616 gpu_mesh_instance_builder,
1617 gpu_mesh_culling_data,
1618 );
1619}
1620
1621pub(crate) fn set_mesh_motion_vector_flags(
1636 mut render_mesh_instances: ResMut<RenderMeshInstances>,
1637 skin_uniforms: Res<SkinUniforms>,
1638 morph_indices: Res<MorphIndices>,
1639) {
1640 for &entity in skin_uniforms.all_skins() {
1641 render_mesh_instances
1642 .insert_mesh_instance_flags(entity, RenderMeshInstanceFlags::HAS_PREVIOUS_SKIN);
1643 }
1644 for &entity in morph_indices.prev.keys() {
1645 render_mesh_instances
1646 .insert_mesh_instance_flags(entity, RenderMeshInstanceFlags::HAS_PREVIOUS_MORPH);
1647 }
1648}
1649
1650pub fn collect_meshes_for_gpu_building(
1653 render_mesh_instances: ResMut<RenderMeshInstances>,
1654 batched_instance_buffers: ResMut<
1655 gpu_preprocessing::BatchedInstanceBuffers<MeshUniform, MeshInputUniform>,
1656 >,
1657 mut mesh_culling_data_buffer: ResMut<MeshCullingDataBuffer>,
1658 mut render_mesh_instance_queues: ResMut<RenderMeshInstanceGpuQueues>,
1659 mesh_allocator: Res<MeshAllocator>,
1660 mesh_material_ids: Res<RenderMaterialInstances>,
1661 render_material_bindings: Res<RenderMaterialBindings>,
1662 render_lightmaps: Res<RenderLightmaps>,
1663 skin_uniforms: Res<SkinUniforms>,
1664 frame_count: Res<FrameCount>,
1665 mut meshes_to_reextract_next_frame: ResMut<MeshesToReextractNextFrame>,
1666) {
1667 let RenderMeshInstances::GpuBuilding(render_mesh_instances) =
1668 render_mesh_instances.into_inner()
1669 else {
1670 return;
1671 };
1672
1673 meshes_to_reextract_next_frame.clear();
1675
1676 let gpu_preprocessing::BatchedInstanceBuffers {
1678 current_input_buffer,
1679 previous_input_buffer,
1680 ..
1681 } = batched_instance_buffers.into_inner();
1682
1683 previous_input_buffer.clear();
1684
1685 for queue in render_mesh_instance_queues.iter_mut() {
1688 match *queue {
1689 RenderMeshInstanceGpuQueue::None => {
1690 }
1692
1693 RenderMeshInstanceGpuQueue::CpuCulling {
1694 ref mut changed,
1695 ref mut removed,
1696 } => {
1697 for (entity, mesh_instance_builder) in changed.drain(..) {
1698 mesh_instance_builder.update(
1699 entity,
1700 &mut *render_mesh_instances,
1701 current_input_buffer,
1702 previous_input_buffer,
1703 &mesh_allocator,
1704 &mesh_material_ids,
1705 &render_material_bindings,
1706 &render_lightmaps,
1707 &skin_uniforms,
1708 *frame_count,
1709 &mut meshes_to_reextract_next_frame,
1710 );
1711 }
1712
1713 for entity in removed.drain(..) {
1714 remove_mesh_input_uniform(
1715 entity,
1716 &mut *render_mesh_instances,
1717 current_input_buffer,
1718 );
1719 }
1720 }
1721
1722 RenderMeshInstanceGpuQueue::GpuCulling {
1723 ref mut changed,
1724 ref mut removed,
1725 } => {
1726 for (entity, mesh_instance_builder, mesh_culling_builder) in changed.drain(..) {
1727 let Some(instance_data_index) = mesh_instance_builder.update(
1728 entity,
1729 &mut *render_mesh_instances,
1730 current_input_buffer,
1731 previous_input_buffer,
1732 &mesh_allocator,
1733 &mesh_material_ids,
1734 &render_material_bindings,
1735 &render_lightmaps,
1736 &skin_uniforms,
1737 *frame_count,
1738 &mut meshes_to_reextract_next_frame,
1739 ) else {
1740 continue;
1741 };
1742 mesh_culling_builder
1743 .update(&mut mesh_culling_data_buffer, instance_data_index as usize);
1744 }
1745
1746 for entity in removed.drain(..) {
1747 remove_mesh_input_uniform(
1748 entity,
1749 &mut *render_mesh_instances,
1750 current_input_buffer,
1751 );
1752 }
1753 }
1754 }
1755 }
1756
1757 previous_input_buffer.ensure_nonempty();
1759}
1760
1761#[derive(Resource, Clone)]
1763pub struct MeshPipeline {
1764 pub view_layouts: MeshPipelineViewLayouts,
1766 pub dummy_white_gpu_image: GpuImage,
1768 pub clustered_forward_buffer_binding_type: BufferBindingType,
1769 pub mesh_layouts: MeshLayouts,
1770 pub shader: Handle<Shader>,
1772 pub per_object_buffer_batch_size: Option<u32>,
1784
1785 pub binding_arrays_are_usable: bool,
1790
1791 pub clustered_decals_are_usable: bool,
1793
1794 pub skins_use_uniform_buffers: bool,
1797}
1798
1799impl FromWorld for MeshPipeline {
1800 fn from_world(world: &mut World) -> Self {
1801 let shader = load_embedded_asset!(world, "mesh.wgsl");
1802 let mut system_state: SystemState<(
1803 Res<RenderDevice>,
1804 Res<RenderAdapter>,
1805 Res<DefaultImageSampler>,
1806 Res<RenderQueue>,
1807 Res<MeshPipelineViewLayouts>,
1808 )> = SystemState::new(world);
1809 let (render_device, render_adapter, default_sampler, render_queue, view_layouts) =
1810 system_state.get_mut(world);
1811
1812 let clustered_forward_buffer_binding_type = render_device
1813 .get_supported_read_only_binding_type(CLUSTERED_FORWARD_STORAGE_BUFFER_COUNT);
1814
1815 let dummy_white_gpu_image = {
1817 let image = Image::default();
1818 let texture = render_device.create_texture(&image.texture_descriptor);
1819 let sampler = match image.sampler {
1820 ImageSampler::Default => (**default_sampler).clone(),
1821 ImageSampler::Descriptor(ref descriptor) => {
1822 render_device.create_sampler(&descriptor.as_wgpu())
1823 }
1824 };
1825
1826 if let Ok(format_size) = image.texture_descriptor.format.pixel_size() {
1827 render_queue.write_texture(
1828 texture.as_image_copy(),
1829 image.data.as_ref().expect("Image was created without data"),
1830 TexelCopyBufferLayout {
1831 offset: 0,
1832 bytes_per_row: Some(image.width() * format_size as u32),
1833 rows_per_image: None,
1834 },
1835 image.texture_descriptor.size,
1836 );
1837 }
1838
1839 let texture_view = texture.create_view(&TextureViewDescriptor::default());
1840 GpuImage {
1841 texture,
1842 texture_view,
1843 texture_format: image.texture_descriptor.format,
1844 sampler,
1845 size: image.texture_descriptor.size,
1846 mip_level_count: image.texture_descriptor.mip_level_count,
1847 }
1848 };
1849
1850 MeshPipeline {
1851 view_layouts: view_layouts.clone(),
1852 clustered_forward_buffer_binding_type,
1853 dummy_white_gpu_image,
1854 mesh_layouts: MeshLayouts::new(&render_device, &render_adapter),
1855 shader,
1856 per_object_buffer_batch_size: GpuArrayBuffer::<MeshUniform>::batch_size(&render_device),
1857 binding_arrays_are_usable: binding_arrays_are_usable(&render_device, &render_adapter),
1858 clustered_decals_are_usable: decal::clustered::clustered_decals_are_usable(
1859 &render_device,
1860 &render_adapter,
1861 ),
1862 skins_use_uniform_buffers: skins_use_uniform_buffers(&render_device),
1863 }
1864 }
1865}
1866
1867impl MeshPipeline {
1868 pub fn get_image_texture<'a>(
1869 &'a self,
1870 gpu_images: &'a RenderAssets<GpuImage>,
1871 handle_option: &Option<Handle<Image>>,
1872 ) -> Option<(&'a TextureView, &'a Sampler)> {
1873 if let Some(handle) = handle_option {
1874 let gpu_image = gpu_images.get(handle)?;
1875 Some((&gpu_image.texture_view, &gpu_image.sampler))
1876 } else {
1877 Some((
1878 &self.dummy_white_gpu_image.texture_view,
1879 &self.dummy_white_gpu_image.sampler,
1880 ))
1881 }
1882 }
1883
1884 pub fn get_view_layout(
1885 &self,
1886 layout_key: MeshPipelineViewLayoutKey,
1887 ) -> &MeshPipelineViewLayout {
1888 self.view_layouts.get_view_layout(layout_key)
1889 }
1890}
1891
1892impl GetBatchData for MeshPipeline {
1893 type Param = (
1894 SRes<RenderMeshInstances>,
1895 SRes<RenderLightmaps>,
1896 SRes<RenderAssets<RenderMesh>>,
1897 SRes<MeshAllocator>,
1898 SRes<SkinUniforms>,
1899 );
1900 type CompareData = (
1903 MaterialBindGroupIndex,
1904 AssetId<Mesh>,
1905 Option<LightmapSlabIndex>,
1906 );
1907
1908 type BufferData = MeshUniform;
1909
1910 fn get_batch_data(
1911 (mesh_instances, lightmaps, _, mesh_allocator, skin_uniforms): &SystemParamItem<
1912 Self::Param,
1913 >,
1914 (_entity, main_entity): (Entity, MainEntity),
1915 ) -> Option<(Self::BufferData, Option<Self::CompareData>)> {
1916 let RenderMeshInstances::CpuBuilding(ref mesh_instances) = **mesh_instances else {
1917 error!(
1918 "`get_batch_data` should never be called in GPU mesh uniform \
1919 building mode"
1920 );
1921 return None;
1922 };
1923 let mesh_instance = mesh_instances.get(&main_entity)?;
1924 let first_vertex_index =
1925 match mesh_allocator.mesh_vertex_slice(&mesh_instance.mesh_asset_id) {
1926 Some(mesh_vertex_slice) => mesh_vertex_slice.range.start,
1927 None => 0,
1928 };
1929 let maybe_lightmap = lightmaps.render_lightmaps.get(&main_entity);
1930
1931 let current_skin_index = skin_uniforms.skin_index(main_entity);
1932 let material_bind_group_index = mesh_instance.material_bindings_index;
1933
1934 Some((
1935 MeshUniform::new(
1936 &mesh_instance.transforms,
1937 first_vertex_index,
1938 material_bind_group_index.slot,
1939 maybe_lightmap.map(|lightmap| (lightmap.slot_index, lightmap.uv_rect)),
1940 current_skin_index,
1941 Some(mesh_instance.tag),
1942 ),
1943 mesh_instance.should_batch().then_some((
1944 material_bind_group_index.group,
1945 mesh_instance.mesh_asset_id,
1946 maybe_lightmap.map(|lightmap| lightmap.slab_index),
1947 )),
1948 ))
1949 }
1950}
1951
1952impl GetFullBatchData for MeshPipeline {
1953 type BufferInputData = MeshInputUniform;
1954
1955 fn get_index_and_compare_data(
1956 (mesh_instances, lightmaps, _, _, _): &SystemParamItem<Self::Param>,
1957 main_entity: MainEntity,
1958 ) -> Option<(NonMaxU32, Option<Self::CompareData>)> {
1959 let RenderMeshInstances::GpuBuilding(ref mesh_instances) = **mesh_instances else {
1961 error!(
1962 "`get_index_and_compare_data` should never be called in CPU mesh uniform building \
1963 mode"
1964 );
1965 return None;
1966 };
1967
1968 let mesh_instance = mesh_instances.get(&main_entity)?;
1969 let maybe_lightmap = lightmaps.render_lightmaps.get(&main_entity);
1970
1971 Some((
1972 mesh_instance.current_uniform_index,
1973 mesh_instance.should_batch().then_some((
1974 mesh_instance.material_bindings_index.group,
1975 mesh_instance.mesh_asset_id,
1976 maybe_lightmap.map(|lightmap| lightmap.slab_index),
1977 )),
1978 ))
1979 }
1980
1981 fn get_binned_batch_data(
1982 (mesh_instances, lightmaps, _, mesh_allocator, skin_uniforms): &SystemParamItem<
1983 Self::Param,
1984 >,
1985 main_entity: MainEntity,
1986 ) -> Option<Self::BufferData> {
1987 let RenderMeshInstances::CpuBuilding(ref mesh_instances) = **mesh_instances else {
1988 error!(
1989 "`get_binned_batch_data` should never be called in GPU mesh uniform building mode"
1990 );
1991 return None;
1992 };
1993 let mesh_instance = mesh_instances.get(&main_entity)?;
1994 let first_vertex_index =
1995 match mesh_allocator.mesh_vertex_slice(&mesh_instance.mesh_asset_id) {
1996 Some(mesh_vertex_slice) => mesh_vertex_slice.range.start,
1997 None => 0,
1998 };
1999 let maybe_lightmap = lightmaps.render_lightmaps.get(&main_entity);
2000
2001 let current_skin_index = skin_uniforms.skin_index(main_entity);
2002
2003 Some(MeshUniform::new(
2004 &mesh_instance.transforms,
2005 first_vertex_index,
2006 mesh_instance.material_bindings_index.slot,
2007 maybe_lightmap.map(|lightmap| (lightmap.slot_index, lightmap.uv_rect)),
2008 current_skin_index,
2009 Some(mesh_instance.tag),
2010 ))
2011 }
2012
2013 fn get_binned_index(
2014 (mesh_instances, _, _, _, _): &SystemParamItem<Self::Param>,
2015 main_entity: MainEntity,
2016 ) -> Option<NonMaxU32> {
2017 let RenderMeshInstances::GpuBuilding(ref mesh_instances) = **mesh_instances else {
2019 error!(
2020 "`get_binned_index` should never be called in CPU mesh uniform \
2021 building mode"
2022 );
2023 return None;
2024 };
2025
2026 mesh_instances
2027 .get(&main_entity)
2028 .map(|entity| entity.current_uniform_index)
2029 }
2030
2031 fn write_batch_indirect_parameters_metadata(
2032 indexed: bool,
2033 base_output_index: u32,
2034 batch_set_index: Option<NonMaxU32>,
2035 phase_indirect_parameters_buffers: &mut UntypedPhaseIndirectParametersBuffers,
2036 indirect_parameters_offset: u32,
2037 ) {
2038 let indirect_parameters = IndirectParametersCpuMetadata {
2039 base_output_index,
2040 batch_set_index: match batch_set_index {
2041 Some(batch_set_index) => u32::from(batch_set_index),
2042 None => !0,
2043 },
2044 };
2045
2046 if indexed {
2047 phase_indirect_parameters_buffers
2048 .indexed
2049 .set(indirect_parameters_offset, indirect_parameters);
2050 } else {
2051 phase_indirect_parameters_buffers
2052 .non_indexed
2053 .set(indirect_parameters_offset, indirect_parameters);
2054 }
2055 }
2056}
2057
2058bitflags::bitflags! {
2059 #[derive(Default, Clone, Copy, Debug, PartialEq, Eq, Hash)]
2060 #[repr(transparent)]
2061 pub struct MeshPipelineKey: u64 {
2064 const NONE = 0;
2066
2067 const MORPH_TARGETS = BaseMeshPipelineKey::MORPH_TARGETS.bits();
2069
2070 const HDR = 1 << 0;
2072 const TONEMAP_IN_SHADER = 1 << 1;
2073 const DEBAND_DITHER = 1 << 2;
2074 const DEPTH_PREPASS = 1 << 3;
2075 const NORMAL_PREPASS = 1 << 4;
2076 const DEFERRED_PREPASS = 1 << 5;
2077 const MOTION_VECTOR_PREPASS = 1 << 6;
2078 const MAY_DISCARD = 1 << 7; const ENVIRONMENT_MAP = 1 << 8;
2081 const SCREEN_SPACE_AMBIENT_OCCLUSION = 1 << 9;
2082 const UNCLIPPED_DEPTH_ORTHO = 1 << 10; const TEMPORAL_JITTER = 1 << 11;
2086 const READS_VIEW_TRANSMISSION_TEXTURE = 1 << 12;
2087 const LIGHTMAPPED = 1 << 13;
2088 const LIGHTMAP_BICUBIC_SAMPLING = 1 << 14;
2089 const IRRADIANCE_VOLUME = 1 << 15;
2090 const VISIBILITY_RANGE_DITHER = 1 << 16;
2091 const SCREEN_SPACE_REFLECTIONS = 1 << 17;
2092 const HAS_PREVIOUS_SKIN = 1 << 18;
2093 const HAS_PREVIOUS_MORPH = 1 << 19;
2094 const OIT_ENABLED = 1 << 20;
2095 const DISTANCE_FOG = 1 << 21;
2096 const LAST_FLAG = Self::DISTANCE_FOG.bits();
2097
2098 const MSAA_RESERVED_BITS = Self::MSAA_MASK_BITS << Self::MSAA_SHIFT_BITS;
2100 const BLEND_RESERVED_BITS = Self::BLEND_MASK_BITS << Self::BLEND_SHIFT_BITS; const BLEND_OPAQUE = 0 << Self::BLEND_SHIFT_BITS; const BLEND_PREMULTIPLIED_ALPHA = 1 << Self::BLEND_SHIFT_BITS; const BLEND_MULTIPLY = 2 << Self::BLEND_SHIFT_BITS; const BLEND_ALPHA = 3 << Self::BLEND_SHIFT_BITS; const BLEND_ALPHA_TO_COVERAGE = 4 << Self::BLEND_SHIFT_BITS; const TONEMAP_METHOD_RESERVED_BITS = Self::TONEMAP_METHOD_MASK_BITS << Self::TONEMAP_METHOD_SHIFT_BITS;
2107 const TONEMAP_METHOD_NONE = 0 << Self::TONEMAP_METHOD_SHIFT_BITS;
2108 const TONEMAP_METHOD_REINHARD = 1 << Self::TONEMAP_METHOD_SHIFT_BITS;
2109 const TONEMAP_METHOD_REINHARD_LUMINANCE = 2 << Self::TONEMAP_METHOD_SHIFT_BITS;
2110 const TONEMAP_METHOD_ACES_FITTED = 3 << Self::TONEMAP_METHOD_SHIFT_BITS;
2111 const TONEMAP_METHOD_AGX = 4 << Self::TONEMAP_METHOD_SHIFT_BITS;
2112 const TONEMAP_METHOD_SOMEWHAT_BORING_DISPLAY_TRANSFORM = 5 << Self::TONEMAP_METHOD_SHIFT_BITS;
2113 const TONEMAP_METHOD_TONY_MC_MAPFACE = 6 << Self::TONEMAP_METHOD_SHIFT_BITS;
2114 const TONEMAP_METHOD_BLENDER_FILMIC = 7 << Self::TONEMAP_METHOD_SHIFT_BITS;
2115 const SHADOW_FILTER_METHOD_RESERVED_BITS = Self::SHADOW_FILTER_METHOD_MASK_BITS << Self::SHADOW_FILTER_METHOD_SHIFT_BITS;
2116 const SHADOW_FILTER_METHOD_HARDWARE_2X2 = 0 << Self::SHADOW_FILTER_METHOD_SHIFT_BITS;
2117 const SHADOW_FILTER_METHOD_GAUSSIAN = 1 << Self::SHADOW_FILTER_METHOD_SHIFT_BITS;
2118 const SHADOW_FILTER_METHOD_TEMPORAL = 2 << Self::SHADOW_FILTER_METHOD_SHIFT_BITS;
2119 const VIEW_PROJECTION_RESERVED_BITS = Self::VIEW_PROJECTION_MASK_BITS << Self::VIEW_PROJECTION_SHIFT_BITS;
2120 const VIEW_PROJECTION_NONSTANDARD = 0 << Self::VIEW_PROJECTION_SHIFT_BITS;
2121 const VIEW_PROJECTION_PERSPECTIVE = 1 << Self::VIEW_PROJECTION_SHIFT_BITS;
2122 const VIEW_PROJECTION_ORTHOGRAPHIC = 2 << Self::VIEW_PROJECTION_SHIFT_BITS;
2123 const VIEW_PROJECTION_RESERVED = 3 << Self::VIEW_PROJECTION_SHIFT_BITS;
2124 const SCREEN_SPACE_SPECULAR_TRANSMISSION_RESERVED_BITS = Self::SCREEN_SPACE_SPECULAR_TRANSMISSION_MASK_BITS << Self::SCREEN_SPACE_SPECULAR_TRANSMISSION_SHIFT_BITS;
2125 const SCREEN_SPACE_SPECULAR_TRANSMISSION_LOW = 0 << Self::SCREEN_SPACE_SPECULAR_TRANSMISSION_SHIFT_BITS;
2126 const SCREEN_SPACE_SPECULAR_TRANSMISSION_MEDIUM = 1 << Self::SCREEN_SPACE_SPECULAR_TRANSMISSION_SHIFT_BITS;
2127 const SCREEN_SPACE_SPECULAR_TRANSMISSION_HIGH = 2 << Self::SCREEN_SPACE_SPECULAR_TRANSMISSION_SHIFT_BITS;
2128 const SCREEN_SPACE_SPECULAR_TRANSMISSION_ULTRA = 3 << Self::SCREEN_SPACE_SPECULAR_TRANSMISSION_SHIFT_BITS;
2129 const ALL_RESERVED_BITS =
2130 Self::BLEND_RESERVED_BITS.bits() |
2131 Self::MSAA_RESERVED_BITS.bits() |
2132 Self::TONEMAP_METHOD_RESERVED_BITS.bits() |
2133 Self::SHADOW_FILTER_METHOD_RESERVED_BITS.bits() |
2134 Self::VIEW_PROJECTION_RESERVED_BITS.bits() |
2135 Self::SCREEN_SPACE_SPECULAR_TRANSMISSION_RESERVED_BITS.bits();
2136 }
2137}
2138
2139impl MeshPipelineKey {
2140 const MSAA_MASK_BITS: u64 = 0b111;
2141 const MSAA_SHIFT_BITS: u64 = Self::LAST_FLAG.bits().trailing_zeros() as u64 + 1;
2142
2143 const BLEND_MASK_BITS: u64 = 0b111;
2144 const BLEND_SHIFT_BITS: u64 = Self::MSAA_MASK_BITS.count_ones() as u64 + Self::MSAA_SHIFT_BITS;
2145
2146 const TONEMAP_METHOD_MASK_BITS: u64 = 0b111;
2147 const TONEMAP_METHOD_SHIFT_BITS: u64 =
2148 Self::BLEND_MASK_BITS.count_ones() as u64 + Self::BLEND_SHIFT_BITS;
2149
2150 const SHADOW_FILTER_METHOD_MASK_BITS: u64 = 0b11;
2151 const SHADOW_FILTER_METHOD_SHIFT_BITS: u64 =
2152 Self::TONEMAP_METHOD_MASK_BITS.count_ones() as u64 + Self::TONEMAP_METHOD_SHIFT_BITS;
2153
2154 const VIEW_PROJECTION_MASK_BITS: u64 = 0b11;
2155 const VIEW_PROJECTION_SHIFT_BITS: u64 = Self::SHADOW_FILTER_METHOD_MASK_BITS.count_ones()
2156 as u64
2157 + Self::SHADOW_FILTER_METHOD_SHIFT_BITS;
2158
2159 const SCREEN_SPACE_SPECULAR_TRANSMISSION_MASK_BITS: u64 = 0b11;
2160 const SCREEN_SPACE_SPECULAR_TRANSMISSION_SHIFT_BITS: u64 =
2161 Self::VIEW_PROJECTION_MASK_BITS.count_ones() as u64 + Self::VIEW_PROJECTION_SHIFT_BITS;
2162
2163 pub fn from_msaa_samples(msaa_samples: u32) -> Self {
2164 let msaa_bits =
2165 (msaa_samples.trailing_zeros() as u64 & Self::MSAA_MASK_BITS) << Self::MSAA_SHIFT_BITS;
2166 Self::from_bits_retain(msaa_bits)
2167 }
2168
2169 pub fn from_hdr(hdr: bool) -> Self {
2170 if hdr {
2171 MeshPipelineKey::HDR
2172 } else {
2173 MeshPipelineKey::NONE
2174 }
2175 }
2176
2177 pub fn msaa_samples(&self) -> u32 {
2178 1 << ((self.bits() >> Self::MSAA_SHIFT_BITS) & Self::MSAA_MASK_BITS)
2179 }
2180
2181 pub fn from_primitive_topology(primitive_topology: PrimitiveTopology) -> Self {
2182 let primitive_topology_bits = ((primitive_topology as u64)
2183 & BaseMeshPipelineKey::PRIMITIVE_TOPOLOGY_MASK_BITS)
2184 << BaseMeshPipelineKey::PRIMITIVE_TOPOLOGY_SHIFT_BITS;
2185 Self::from_bits_retain(primitive_topology_bits)
2186 }
2187
2188 pub fn primitive_topology(&self) -> PrimitiveTopology {
2189 let primitive_topology_bits = (self.bits()
2190 >> BaseMeshPipelineKey::PRIMITIVE_TOPOLOGY_SHIFT_BITS)
2191 & BaseMeshPipelineKey::PRIMITIVE_TOPOLOGY_MASK_BITS;
2192 match primitive_topology_bits {
2193 x if x == PrimitiveTopology::PointList as u64 => PrimitiveTopology::PointList,
2194 x if x == PrimitiveTopology::LineList as u64 => PrimitiveTopology::LineList,
2195 x if x == PrimitiveTopology::LineStrip as u64 => PrimitiveTopology::LineStrip,
2196 x if x == PrimitiveTopology::TriangleList as u64 => PrimitiveTopology::TriangleList,
2197 x if x == PrimitiveTopology::TriangleStrip as u64 => PrimitiveTopology::TriangleStrip,
2198 _ => PrimitiveTopology::default(),
2199 }
2200 }
2201}
2202
2203const_assert_eq!(
2205 (((MeshPipelineKey::LAST_FLAG.bits() << 1) - 1) | MeshPipelineKey::ALL_RESERVED_BITS.bits())
2206 & BaseMeshPipelineKey::all().bits(),
2207 0
2208);
2209
2210const_assert_eq!(
2212 (BaseMeshPipelineKey::PRIMITIVE_TOPOLOGY_MASK_BITS
2213 << BaseMeshPipelineKey::PRIMITIVE_TOPOLOGY_SHIFT_BITS)
2214 & MeshPipelineKey::ALL_RESERVED_BITS.bits(),
2215 0
2216);
2217
2218fn is_skinned(layout: &MeshVertexBufferLayoutRef) -> bool {
2219 layout.0.contains(Mesh::ATTRIBUTE_JOINT_INDEX)
2220 && layout.0.contains(Mesh::ATTRIBUTE_JOINT_WEIGHT)
2221}
2222pub fn setup_morph_and_skinning_defs(
2223 mesh_layouts: &MeshLayouts,
2224 layout: &MeshVertexBufferLayoutRef,
2225 offset: u32,
2226 key: &MeshPipelineKey,
2227 shader_defs: &mut Vec<ShaderDefVal>,
2228 vertex_attributes: &mut Vec<VertexAttributeDescriptor>,
2229 skins_use_uniform_buffers: bool,
2230) -> BindGroupLayout {
2231 let is_morphed = key.intersects(MeshPipelineKey::MORPH_TARGETS);
2232 let is_lightmapped = key.intersects(MeshPipelineKey::LIGHTMAPPED);
2233 let motion_vector_prepass = key.intersects(MeshPipelineKey::MOTION_VECTOR_PREPASS);
2234
2235 if skins_use_uniform_buffers {
2236 shader_defs.push("SKINS_USE_UNIFORM_BUFFERS".into());
2237 }
2238
2239 let mut add_skin_data = || {
2240 shader_defs.push("SKINNED".into());
2241 vertex_attributes.push(Mesh::ATTRIBUTE_JOINT_INDEX.at_shader_location(offset));
2242 vertex_attributes.push(Mesh::ATTRIBUTE_JOINT_WEIGHT.at_shader_location(offset + 1));
2243 };
2244
2245 match (
2246 is_skinned(layout),
2247 is_morphed,
2248 is_lightmapped,
2249 motion_vector_prepass,
2250 ) {
2251 (true, false, _, true) => {
2252 add_skin_data();
2253 mesh_layouts.skinned_motion.clone()
2254 }
2255 (true, false, _, false) => {
2256 add_skin_data();
2257 mesh_layouts.skinned.clone()
2258 }
2259 (true, true, _, true) => {
2260 add_skin_data();
2261 shader_defs.push("MORPH_TARGETS".into());
2262 mesh_layouts.morphed_skinned_motion.clone()
2263 }
2264 (true, true, _, false) => {
2265 add_skin_data();
2266 shader_defs.push("MORPH_TARGETS".into());
2267 mesh_layouts.morphed_skinned.clone()
2268 }
2269 (false, true, _, true) => {
2270 shader_defs.push("MORPH_TARGETS".into());
2271 mesh_layouts.morphed_motion.clone()
2272 }
2273 (false, true, _, false) => {
2274 shader_defs.push("MORPH_TARGETS".into());
2275 mesh_layouts.morphed.clone()
2276 }
2277 (false, false, true, _) => mesh_layouts.lightmapped.clone(),
2278 (false, false, false, _) => mesh_layouts.model_only.clone(),
2279 }
2280}
2281
2282impl SpecializedMeshPipeline for MeshPipeline {
2283 type Key = MeshPipelineKey;
2284
2285 fn specialize(
2286 &self,
2287 key: Self::Key,
2288 layout: &MeshVertexBufferLayoutRef,
2289 ) -> Result<RenderPipelineDescriptor, SpecializedMeshPipelineError> {
2290 let mut shader_defs = Vec::new();
2291 let mut vertex_attributes = Vec::new();
2292
2293 shader_defs.push("MESH_PIPELINE".into());
2295
2296 shader_defs.push("VERTEX_OUTPUT_INSTANCE_INDEX".into());
2297
2298 if layout.0.contains(Mesh::ATTRIBUTE_POSITION) {
2299 shader_defs.push("VERTEX_POSITIONS".into());
2300 vertex_attributes.push(Mesh::ATTRIBUTE_POSITION.at_shader_location(0));
2301 }
2302
2303 if layout.0.contains(Mesh::ATTRIBUTE_NORMAL) {
2304 shader_defs.push("VERTEX_NORMALS".into());
2305 vertex_attributes.push(Mesh::ATTRIBUTE_NORMAL.at_shader_location(1));
2306 }
2307
2308 if layout.0.contains(Mesh::ATTRIBUTE_UV_0) {
2309 shader_defs.push("VERTEX_UVS".into());
2310 shader_defs.push("VERTEX_UVS_A".into());
2311 vertex_attributes.push(Mesh::ATTRIBUTE_UV_0.at_shader_location(2));
2312 }
2313
2314 if layout.0.contains(Mesh::ATTRIBUTE_UV_1) {
2315 shader_defs.push("VERTEX_UVS".into());
2316 shader_defs.push("VERTEX_UVS_B".into());
2317 vertex_attributes.push(Mesh::ATTRIBUTE_UV_1.at_shader_location(3));
2318 }
2319
2320 if layout.0.contains(Mesh::ATTRIBUTE_TANGENT) {
2321 shader_defs.push("VERTEX_TANGENTS".into());
2322 vertex_attributes.push(Mesh::ATTRIBUTE_TANGENT.at_shader_location(4));
2323 }
2324
2325 if layout.0.contains(Mesh::ATTRIBUTE_COLOR) {
2326 shader_defs.push("VERTEX_COLORS".into());
2327 vertex_attributes.push(Mesh::ATTRIBUTE_COLOR.at_shader_location(5));
2328 }
2329
2330 if cfg!(feature = "pbr_transmission_textures") {
2331 shader_defs.push("PBR_TRANSMISSION_TEXTURES_SUPPORTED".into());
2332 }
2333 if cfg!(feature = "pbr_multi_layer_material_textures") {
2334 shader_defs.push("PBR_MULTI_LAYER_MATERIAL_TEXTURES_SUPPORTED".into());
2335 }
2336 if cfg!(feature = "pbr_anisotropy_texture") {
2337 shader_defs.push("PBR_ANISOTROPY_TEXTURE_SUPPORTED".into());
2338 }
2339 if cfg!(feature = "pbr_specular_textures") {
2340 shader_defs.push("PBR_SPECULAR_TEXTURES_SUPPORTED".into());
2341 }
2342
2343 let bind_group_layout = self.get_view_layout(key.into());
2344 let mut bind_group_layout = vec![
2345 bind_group_layout.main_layout.clone(),
2346 bind_group_layout.binding_array_layout.clone(),
2347 ];
2348
2349 if key.msaa_samples() > 1 {
2350 shader_defs.push("MULTISAMPLED".into());
2351 };
2352
2353 bind_group_layout.push(setup_morph_and_skinning_defs(
2354 &self.mesh_layouts,
2355 layout,
2356 6,
2357 &key,
2358 &mut shader_defs,
2359 &mut vertex_attributes,
2360 self.skins_use_uniform_buffers,
2361 ));
2362
2363 if key.contains(MeshPipelineKey::SCREEN_SPACE_AMBIENT_OCCLUSION) {
2364 shader_defs.push("SCREEN_SPACE_AMBIENT_OCCLUSION".into());
2365 }
2366
2367 let vertex_buffer_layout = layout.0.get_layout(&vertex_attributes)?;
2368
2369 let (label, blend, depth_write_enabled);
2370 let pass = key.intersection(MeshPipelineKey::BLEND_RESERVED_BITS);
2371 let (mut is_opaque, mut alpha_to_coverage_enabled) = (false, false);
2372 if key.contains(MeshPipelineKey::OIT_ENABLED) && pass == MeshPipelineKey::BLEND_ALPHA {
2373 label = "oit_mesh_pipeline".into();
2374 blend = None;
2376 shader_defs.push("OIT_ENABLED".into());
2377 depth_write_enabled = false;
2380 } else if pass == MeshPipelineKey::BLEND_ALPHA {
2381 label = "alpha_blend_mesh_pipeline".into();
2382 blend = Some(BlendState::ALPHA_BLENDING);
2383 depth_write_enabled = false;
2386 } else if pass == MeshPipelineKey::BLEND_PREMULTIPLIED_ALPHA {
2387 label = "premultiplied_alpha_mesh_pipeline".into();
2388 blend = Some(BlendState::PREMULTIPLIED_ALPHA_BLENDING);
2389 shader_defs.push("PREMULTIPLY_ALPHA".into());
2390 shader_defs.push("BLEND_PREMULTIPLIED_ALPHA".into());
2391 depth_write_enabled = false;
2394 } else if pass == MeshPipelineKey::BLEND_MULTIPLY {
2395 label = "multiply_mesh_pipeline".into();
2396 blend = Some(BlendState {
2397 color: BlendComponent {
2398 src_factor: BlendFactor::Dst,
2399 dst_factor: BlendFactor::OneMinusSrcAlpha,
2400 operation: BlendOperation::Add,
2401 },
2402 alpha: BlendComponent::OVER,
2403 });
2404 shader_defs.push("PREMULTIPLY_ALPHA".into());
2405 shader_defs.push("BLEND_MULTIPLY".into());
2406 depth_write_enabled = false;
2409 } else if pass == MeshPipelineKey::BLEND_ALPHA_TO_COVERAGE {
2410 label = "alpha_to_coverage_mesh_pipeline".into();
2411 blend = None;
2413 depth_write_enabled = true;
2417 is_opaque = !key.contains(MeshPipelineKey::READS_VIEW_TRANSMISSION_TEXTURE);
2418 alpha_to_coverage_enabled = true;
2419 shader_defs.push("ALPHA_TO_COVERAGE".into());
2420 } else {
2421 label = "opaque_mesh_pipeline".into();
2422 blend = None;
2424 depth_write_enabled = true;
2428 is_opaque = !key.contains(MeshPipelineKey::READS_VIEW_TRANSMISSION_TEXTURE);
2429 }
2430
2431 if key.contains(MeshPipelineKey::NORMAL_PREPASS) {
2432 shader_defs.push("NORMAL_PREPASS".into());
2433 }
2434
2435 if key.contains(MeshPipelineKey::DEPTH_PREPASS) {
2436 shader_defs.push("DEPTH_PREPASS".into());
2437 }
2438
2439 if key.contains(MeshPipelineKey::MOTION_VECTOR_PREPASS) {
2440 shader_defs.push("MOTION_VECTOR_PREPASS".into());
2441 }
2442
2443 if key.contains(MeshPipelineKey::HAS_PREVIOUS_SKIN) {
2444 shader_defs.push("HAS_PREVIOUS_SKIN".into());
2445 }
2446
2447 if key.contains(MeshPipelineKey::HAS_PREVIOUS_MORPH) {
2448 shader_defs.push("HAS_PREVIOUS_MORPH".into());
2449 }
2450
2451 if key.contains(MeshPipelineKey::DEFERRED_PREPASS) {
2452 shader_defs.push("DEFERRED_PREPASS".into());
2453 }
2454
2455 if key.contains(MeshPipelineKey::NORMAL_PREPASS) && key.msaa_samples() == 1 && is_opaque {
2456 shader_defs.push("LOAD_PREPASS_NORMALS".into());
2457 }
2458
2459 let view_projection = key.intersection(MeshPipelineKey::VIEW_PROJECTION_RESERVED_BITS);
2460 if view_projection == MeshPipelineKey::VIEW_PROJECTION_NONSTANDARD {
2461 shader_defs.push("VIEW_PROJECTION_NONSTANDARD".into());
2462 } else if view_projection == MeshPipelineKey::VIEW_PROJECTION_PERSPECTIVE {
2463 shader_defs.push("VIEW_PROJECTION_PERSPECTIVE".into());
2464 } else if view_projection == MeshPipelineKey::VIEW_PROJECTION_ORTHOGRAPHIC {
2465 shader_defs.push("VIEW_PROJECTION_ORTHOGRAPHIC".into());
2466 }
2467
2468 #[cfg(all(feature = "webgl", target_arch = "wasm32", not(feature = "webgpu")))]
2469 shader_defs.push("WEBGL2".into());
2470
2471 #[cfg(feature = "experimental_pbr_pcss")]
2472 shader_defs.push("PCSS_SAMPLERS_AVAILABLE".into());
2473
2474 if key.contains(MeshPipelineKey::TONEMAP_IN_SHADER) {
2475 shader_defs.push("TONEMAP_IN_SHADER".into());
2476 shader_defs.push(ShaderDefVal::UInt(
2477 "TONEMAPPING_LUT_TEXTURE_BINDING_INDEX".into(),
2478 TONEMAPPING_LUT_TEXTURE_BINDING_INDEX,
2479 ));
2480 shader_defs.push(ShaderDefVal::UInt(
2481 "TONEMAPPING_LUT_SAMPLER_BINDING_INDEX".into(),
2482 TONEMAPPING_LUT_SAMPLER_BINDING_INDEX,
2483 ));
2484
2485 let method = key.intersection(MeshPipelineKey::TONEMAP_METHOD_RESERVED_BITS);
2486
2487 if method == MeshPipelineKey::TONEMAP_METHOD_NONE {
2488 shader_defs.push("TONEMAP_METHOD_NONE".into());
2489 } else if method == MeshPipelineKey::TONEMAP_METHOD_REINHARD {
2490 shader_defs.push("TONEMAP_METHOD_REINHARD".into());
2491 } else if method == MeshPipelineKey::TONEMAP_METHOD_REINHARD_LUMINANCE {
2492 shader_defs.push("TONEMAP_METHOD_REINHARD_LUMINANCE".into());
2493 } else if method == MeshPipelineKey::TONEMAP_METHOD_ACES_FITTED {
2494 shader_defs.push("TONEMAP_METHOD_ACES_FITTED".into());
2495 } else if method == MeshPipelineKey::TONEMAP_METHOD_AGX {
2496 shader_defs.push("TONEMAP_METHOD_AGX".into());
2497 } else if method == MeshPipelineKey::TONEMAP_METHOD_SOMEWHAT_BORING_DISPLAY_TRANSFORM {
2498 shader_defs.push("TONEMAP_METHOD_SOMEWHAT_BORING_DISPLAY_TRANSFORM".into());
2499 } else if method == MeshPipelineKey::TONEMAP_METHOD_BLENDER_FILMIC {
2500 shader_defs.push("TONEMAP_METHOD_BLENDER_FILMIC".into());
2501 } else if method == MeshPipelineKey::TONEMAP_METHOD_TONY_MC_MAPFACE {
2502 shader_defs.push("TONEMAP_METHOD_TONY_MC_MAPFACE".into());
2503 }
2504
2505 if key.contains(MeshPipelineKey::DEBAND_DITHER) {
2507 shader_defs.push("DEBAND_DITHER".into());
2508 }
2509 }
2510
2511 if key.contains(MeshPipelineKey::MAY_DISCARD) {
2512 shader_defs.push("MAY_DISCARD".into());
2513 }
2514
2515 if key.contains(MeshPipelineKey::ENVIRONMENT_MAP) {
2516 shader_defs.push("ENVIRONMENT_MAP".into());
2517 }
2518
2519 if key.contains(MeshPipelineKey::IRRADIANCE_VOLUME) && IRRADIANCE_VOLUMES_ARE_USABLE {
2520 shader_defs.push("IRRADIANCE_VOLUME".into());
2521 }
2522
2523 if key.contains(MeshPipelineKey::LIGHTMAPPED) {
2524 shader_defs.push("LIGHTMAP".into());
2525 }
2526 if key.contains(MeshPipelineKey::LIGHTMAP_BICUBIC_SAMPLING) {
2527 shader_defs.push("LIGHTMAP_BICUBIC_SAMPLING".into());
2528 }
2529
2530 if key.contains(MeshPipelineKey::TEMPORAL_JITTER) {
2531 shader_defs.push("TEMPORAL_JITTER".into());
2532 }
2533
2534 let shadow_filter_method =
2535 key.intersection(MeshPipelineKey::SHADOW_FILTER_METHOD_RESERVED_BITS);
2536 if shadow_filter_method == MeshPipelineKey::SHADOW_FILTER_METHOD_HARDWARE_2X2 {
2537 shader_defs.push("SHADOW_FILTER_METHOD_HARDWARE_2X2".into());
2538 } else if shadow_filter_method == MeshPipelineKey::SHADOW_FILTER_METHOD_GAUSSIAN {
2539 shader_defs.push("SHADOW_FILTER_METHOD_GAUSSIAN".into());
2540 } else if shadow_filter_method == MeshPipelineKey::SHADOW_FILTER_METHOD_TEMPORAL {
2541 shader_defs.push("SHADOW_FILTER_METHOD_TEMPORAL".into());
2542 }
2543
2544 let blur_quality =
2545 key.intersection(MeshPipelineKey::SCREEN_SPACE_SPECULAR_TRANSMISSION_RESERVED_BITS);
2546
2547 shader_defs.push(ShaderDefVal::Int(
2548 "SCREEN_SPACE_SPECULAR_TRANSMISSION_BLUR_TAPS".into(),
2549 match blur_quality {
2550 MeshPipelineKey::SCREEN_SPACE_SPECULAR_TRANSMISSION_LOW => 4,
2551 MeshPipelineKey::SCREEN_SPACE_SPECULAR_TRANSMISSION_MEDIUM => 8,
2552 MeshPipelineKey::SCREEN_SPACE_SPECULAR_TRANSMISSION_HIGH => 16,
2553 MeshPipelineKey::SCREEN_SPACE_SPECULAR_TRANSMISSION_ULTRA => 32,
2554 _ => unreachable!(), },
2556 ));
2557
2558 if key.contains(MeshPipelineKey::VISIBILITY_RANGE_DITHER) {
2559 shader_defs.push("VISIBILITY_RANGE_DITHER".into());
2560 }
2561
2562 if key.contains(MeshPipelineKey::DISTANCE_FOG) {
2563 shader_defs.push("DISTANCE_FOG".into());
2564 }
2565
2566 if self.binding_arrays_are_usable {
2567 shader_defs.push("MULTIPLE_LIGHT_PROBES_IN_ARRAY".into());
2568 shader_defs.push("MULTIPLE_LIGHTMAPS_IN_ARRAY".into());
2569 }
2570
2571 if IRRADIANCE_VOLUMES_ARE_USABLE {
2572 shader_defs.push("IRRADIANCE_VOLUMES_ARE_USABLE".into());
2573 }
2574
2575 if self.clustered_decals_are_usable {
2576 shader_defs.push("CLUSTERED_DECALS_ARE_USABLE".into());
2577 if cfg!(feature = "pbr_light_textures") {
2578 shader_defs.push("LIGHT_TEXTURES".into());
2579 }
2580 }
2581
2582 let format = if key.contains(MeshPipelineKey::HDR) {
2583 ViewTarget::TEXTURE_FORMAT_HDR
2584 } else {
2585 TextureFormat::bevy_default()
2586 };
2587
2588 if let Some(per_object_buffer_batch_size) = self.per_object_buffer_batch_size {
2592 shader_defs.push(ShaderDefVal::UInt(
2593 "PER_OBJECT_BUFFER_BATCH_SIZE".into(),
2594 per_object_buffer_batch_size,
2595 ));
2596 }
2597
2598 Ok(RenderPipelineDescriptor {
2599 vertex: VertexState {
2600 shader: self.shader.clone(),
2601 shader_defs: shader_defs.clone(),
2602 buffers: vec![vertex_buffer_layout],
2603 ..default()
2604 },
2605 fragment: Some(FragmentState {
2606 shader: self.shader.clone(),
2607 shader_defs,
2608 targets: vec![Some(ColorTargetState {
2609 format,
2610 blend,
2611 write_mask: ColorWrites::ALL,
2612 })],
2613 ..default()
2614 }),
2615 layout: bind_group_layout,
2616 primitive: PrimitiveState {
2617 cull_mode: Some(Face::Back),
2618 unclipped_depth: false,
2619 topology: key.primitive_topology(),
2620 ..default()
2621 },
2622 depth_stencil: Some(DepthStencilState {
2623 format: CORE_3D_DEPTH_FORMAT,
2624 depth_write_enabled,
2625 depth_compare: CompareFunction::GreaterEqual,
2626 stencil: StencilState {
2627 front: StencilFaceState::IGNORE,
2628 back: StencilFaceState::IGNORE,
2629 read_mask: 0,
2630 write_mask: 0,
2631 },
2632 bias: DepthBiasState {
2633 constant: 0,
2634 slope_scale: 0.0,
2635 clamp: 0.0,
2636 },
2637 }),
2638 multisample: MultisampleState {
2639 count: key.msaa_samples(),
2640 mask: !0,
2641 alpha_to_coverage_enabled,
2642 },
2643 label: Some(label),
2644 ..default()
2645 })
2646 }
2647}
2648
2649#[derive(Default)]
2654pub struct MeshPhaseBindGroups {
2655 model_only: Option<BindGroup>,
2656 skinned: Option<MeshBindGroupPair>,
2657 morph_targets: HashMap<AssetId<Mesh>, MeshBindGroupPair>,
2658 lightmaps: HashMap<LightmapSlabIndex, BindGroup>,
2659}
2660
2661pub struct MeshBindGroupPair {
2662 motion_vectors: BindGroup,
2663 no_motion_vectors: BindGroup,
2664}
2665
2666#[derive(Resource)]
2668pub enum MeshBindGroups {
2669 CpuPreprocessing(MeshPhaseBindGroups),
2672 GpuPreprocessing(TypeIdMap<MeshPhaseBindGroups>),
2675}
2676
2677impl MeshPhaseBindGroups {
2678 pub fn reset(&mut self) {
2679 self.model_only = None;
2680 self.skinned = None;
2681 self.morph_targets.clear();
2682 self.lightmaps.clear();
2683 }
2684 pub fn get(
2687 &self,
2688 asset_id: AssetId<Mesh>,
2689 lightmap: Option<LightmapSlabIndex>,
2690 is_skinned: bool,
2691 morph: bool,
2692 motion_vectors: bool,
2693 ) -> Option<&BindGroup> {
2694 match (is_skinned, morph, lightmap) {
2695 (_, true, _) => self
2696 .morph_targets
2697 .get(&asset_id)
2698 .map(|bind_group_pair| bind_group_pair.get(motion_vectors)),
2699 (true, false, _) => self
2700 .skinned
2701 .as_ref()
2702 .map(|bind_group_pair| bind_group_pair.get(motion_vectors)),
2703 (false, false, Some(lightmap_slab)) => self.lightmaps.get(&lightmap_slab),
2704 (false, false, None) => self.model_only.as_ref(),
2705 }
2706 }
2707}
2708
2709impl MeshBindGroupPair {
2710 fn get(&self, motion_vectors: bool) -> &BindGroup {
2711 if motion_vectors {
2712 &self.motion_vectors
2713 } else {
2714 &self.no_motion_vectors
2715 }
2716 }
2717}
2718
2719pub fn prepare_mesh_bind_groups(
2721 mut commands: Commands,
2722 meshes: Res<RenderAssets<RenderMesh>>,
2723 mesh_pipeline: Res<MeshPipeline>,
2724 render_device: Res<RenderDevice>,
2725 cpu_batched_instance_buffer: Option<
2726 Res<no_gpu_preprocessing::BatchedInstanceBuffer<MeshUniform>>,
2727 >,
2728 gpu_batched_instance_buffers: Option<
2729 Res<gpu_preprocessing::BatchedInstanceBuffers<MeshUniform, MeshInputUniform>>,
2730 >,
2731 skins_uniform: Res<SkinUniforms>,
2732 weights_uniform: Res<MorphUniforms>,
2733 mut render_lightmaps: ResMut<RenderLightmaps>,
2734) {
2735 if let Some(cpu_batched_instance_buffer) = cpu_batched_instance_buffer
2737 && let Some(instance_data_binding) = cpu_batched_instance_buffer
2738 .into_inner()
2739 .instance_data_binding()
2740 {
2741 let cpu_preprocessing_mesh_bind_groups = prepare_mesh_bind_groups_for_phase(
2743 instance_data_binding,
2744 &meshes,
2745 &mesh_pipeline,
2746 &render_device,
2747 &skins_uniform,
2748 &weights_uniform,
2749 &mut render_lightmaps,
2750 );
2751
2752 commands.insert_resource(MeshBindGroups::CpuPreprocessing(
2753 cpu_preprocessing_mesh_bind_groups,
2754 ));
2755 return;
2756 }
2757
2758 if let Some(gpu_batched_instance_buffers) = gpu_batched_instance_buffers {
2760 let mut gpu_preprocessing_mesh_bind_groups = TypeIdMap::default();
2761
2762 for (phase_type_id, batched_phase_instance_buffers) in
2764 &gpu_batched_instance_buffers.phase_instance_buffers
2765 {
2766 let Some(instance_data_binding) =
2767 batched_phase_instance_buffers.instance_data_binding()
2768 else {
2769 continue;
2770 };
2771
2772 let mesh_phase_bind_groups = prepare_mesh_bind_groups_for_phase(
2773 instance_data_binding,
2774 &meshes,
2775 &mesh_pipeline,
2776 &render_device,
2777 &skins_uniform,
2778 &weights_uniform,
2779 &mut render_lightmaps,
2780 );
2781
2782 gpu_preprocessing_mesh_bind_groups.insert(*phase_type_id, mesh_phase_bind_groups);
2783 }
2784
2785 commands.insert_resource(MeshBindGroups::GpuPreprocessing(
2786 gpu_preprocessing_mesh_bind_groups,
2787 ));
2788 }
2789}
2790
2791fn prepare_mesh_bind_groups_for_phase(
2793 model: BindingResource,
2794 meshes: &RenderAssets<RenderMesh>,
2795 mesh_pipeline: &MeshPipeline,
2796 render_device: &RenderDevice,
2797 skins_uniform: &SkinUniforms,
2798 weights_uniform: &MorphUniforms,
2799 render_lightmaps: &mut RenderLightmaps,
2800) -> MeshPhaseBindGroups {
2801 let layouts = &mesh_pipeline.mesh_layouts;
2802
2803 let mut groups = MeshPhaseBindGroups {
2805 model_only: Some(layouts.model_only(render_device, &model)),
2806 ..default()
2807 };
2808
2809 let (skin, prev_skin) = (&skins_uniform.current_buffer, &skins_uniform.prev_buffer);
2812 groups.skinned = Some(MeshBindGroupPair {
2813 motion_vectors: layouts.skinned_motion(render_device, &model, skin, prev_skin),
2814 no_motion_vectors: layouts.skinned(render_device, &model, skin),
2815 });
2816
2817 if let Some(weights) = weights_uniform.current_buffer.buffer() {
2820 let prev_weights = weights_uniform.prev_buffer.buffer().unwrap_or(weights);
2821 for (id, gpu_mesh) in meshes.iter() {
2822 if let Some(targets) = gpu_mesh.morph_targets.as_ref() {
2823 let bind_group_pair = if is_skinned(&gpu_mesh.layout) {
2824 let prev_skin = &skins_uniform.prev_buffer;
2825 MeshBindGroupPair {
2826 motion_vectors: layouts.morphed_skinned_motion(
2827 render_device,
2828 &model,
2829 skin,
2830 weights,
2831 targets,
2832 prev_skin,
2833 prev_weights,
2834 ),
2835 no_motion_vectors: layouts.morphed_skinned(
2836 render_device,
2837 &model,
2838 skin,
2839 weights,
2840 targets,
2841 ),
2842 }
2843 } else {
2844 MeshBindGroupPair {
2845 motion_vectors: layouts.morphed_motion(
2846 render_device,
2847 &model,
2848 weights,
2849 targets,
2850 prev_weights,
2851 ),
2852 no_motion_vectors: layouts.morphed(render_device, &model, weights, targets),
2853 }
2854 };
2855 groups.morph_targets.insert(id, bind_group_pair);
2856 }
2857 }
2858 }
2859
2860 let bindless_supported = render_lightmaps.bindless_supported;
2862 for (lightmap_slab_id, lightmap_slab) in render_lightmaps.slabs.iter_mut().enumerate() {
2863 groups.lightmaps.insert(
2864 LightmapSlabIndex(NonMaxU32::new(lightmap_slab_id as u32).unwrap()),
2865 layouts.lightmapped(render_device, &model, lightmap_slab, bindless_supported),
2866 );
2867 }
2868
2869 groups
2870}
2871
2872pub struct SetMeshViewBindGroup<const I: usize>;
2873impl<P: PhaseItem, const I: usize> RenderCommand<P> for SetMeshViewBindGroup<I> {
2874 type Param = ();
2875 type ViewQuery = (
2876 Read<ViewUniformOffset>,
2877 Read<ViewLightsUniformOffset>,
2878 Read<ViewFogUniformOffset>,
2879 Read<ViewLightProbesUniformOffset>,
2880 Read<ViewScreenSpaceReflectionsUniformOffset>,
2881 Read<ViewEnvironmentMapUniformOffset>,
2882 Read<MeshViewBindGroup>,
2883 Option<Read<OrderIndependentTransparencySettingsOffset>>,
2884 );
2885 type ItemQuery = ();
2886
2887 #[inline]
2888 fn render<'w>(
2889 _item: &P,
2890 (
2891 view_uniform,
2892 view_lights,
2893 view_fog,
2894 view_light_probes,
2895 view_ssr,
2896 view_environment_map,
2897 mesh_view_bind_group,
2898 maybe_oit_layers_count_offset,
2899 ): ROQueryItem<'w, '_, Self::ViewQuery>,
2900 _entity: Option<()>,
2901 _: SystemParamItem<'w, '_, Self::Param>,
2902 pass: &mut TrackedRenderPass<'w>,
2903 ) -> RenderCommandResult {
2904 let mut offsets: SmallVec<[u32; 8]> = smallvec![
2905 view_uniform.offset,
2906 view_lights.offset,
2907 view_fog.offset,
2908 **view_light_probes,
2909 **view_ssr,
2910 **view_environment_map,
2911 ];
2912 if let Some(layers_count_offset) = maybe_oit_layers_count_offset {
2913 offsets.push(layers_count_offset.offset);
2914 }
2915 pass.set_bind_group(I, &mesh_view_bind_group.main, &offsets);
2916
2917 RenderCommandResult::Success
2918 }
2919}
2920
2921pub struct SetMeshViewBindingArrayBindGroup<const I: usize>;
2922impl<P: PhaseItem, const I: usize> RenderCommand<P> for SetMeshViewBindingArrayBindGroup<I> {
2923 type Param = ();
2924 type ViewQuery = (Read<MeshViewBindGroup>,);
2925 type ItemQuery = ();
2926
2927 #[inline]
2928 fn render<'w>(
2929 _item: &P,
2930 (mesh_view_bind_group,): ROQueryItem<'w, '_, Self::ViewQuery>,
2931 _entity: Option<()>,
2932 _: SystemParamItem<'w, '_, Self::Param>,
2933 pass: &mut TrackedRenderPass<'w>,
2934 ) -> RenderCommandResult {
2935 pass.set_bind_group(I, &mesh_view_bind_group.binding_array, &[]);
2936
2937 RenderCommandResult::Success
2938 }
2939}
2940
2941pub struct SetMeshViewEmptyBindGroup<const I: usize>;
2942impl<P: PhaseItem, const I: usize> RenderCommand<P> for SetMeshViewEmptyBindGroup<I> {
2943 type Param = ();
2944 type ViewQuery = (Read<MeshViewBindGroup>,);
2945 type ItemQuery = ();
2946
2947 #[inline]
2948 fn render<'w>(
2949 _item: &P,
2950 (mesh_view_bind_group,): ROQueryItem<'w, '_, Self::ViewQuery>,
2951 _entity: Option<()>,
2952 _: SystemParamItem<'w, '_, Self::Param>,
2953 pass: &mut TrackedRenderPass<'w>,
2954 ) -> RenderCommandResult {
2955 pass.set_bind_group(I, &mesh_view_bind_group.empty, &[]);
2956
2957 RenderCommandResult::Success
2958 }
2959}
2960
2961pub struct SetMeshBindGroup<const I: usize>;
2962impl<P: PhaseItem, const I: usize> RenderCommand<P> for SetMeshBindGroup<I> {
2963 type Param = (
2964 SRes<RenderDevice>,
2965 SRes<MeshBindGroups>,
2966 SRes<RenderMeshInstances>,
2967 SRes<SkinUniforms>,
2968 SRes<MorphIndices>,
2969 SRes<RenderLightmaps>,
2970 );
2971 type ViewQuery = Has<MotionVectorPrepass>;
2972 type ItemQuery = ();
2973
2974 #[inline]
2975 fn render<'w>(
2976 item: &P,
2977 has_motion_vector_prepass: bool,
2978 _item_query: Option<()>,
2979 (
2980 render_device,
2981 bind_groups,
2982 mesh_instances,
2983 skin_uniforms,
2984 morph_indices,
2985 lightmaps,
2986 ): SystemParamItem<'w, '_, Self::Param>,
2987 pass: &mut TrackedRenderPass<'w>,
2988 ) -> RenderCommandResult {
2989 let bind_groups = bind_groups.into_inner();
2990 let mesh_instances = mesh_instances.into_inner();
2991 let skin_uniforms = skin_uniforms.into_inner();
2992 let morph_indices = morph_indices.into_inner();
2993
2994 let entity = &item.main_entity();
2995
2996 let Some(mesh_asset_id) = mesh_instances.mesh_asset_id(*entity) else {
2997 return RenderCommandResult::Success;
2998 };
2999
3000 let current_skin_byte_offset = skin_uniforms.skin_byte_offset(*entity);
3001 let current_morph_index = morph_indices.current.get(entity);
3002 let prev_morph_index = morph_indices.prev.get(entity);
3003
3004 let is_skinned = current_skin_byte_offset.is_some();
3005 let is_morphed = current_morph_index.is_some();
3006
3007 let lightmap_slab_index = lightmaps
3008 .render_lightmaps
3009 .get(entity)
3010 .map(|render_lightmap| render_lightmap.slab_index);
3011
3012 let Some(mesh_phase_bind_groups) = (match *bind_groups {
3013 MeshBindGroups::CpuPreprocessing(ref mesh_phase_bind_groups) => {
3014 Some(mesh_phase_bind_groups)
3015 }
3016 MeshBindGroups::GpuPreprocessing(ref mesh_phase_bind_groups) => {
3017 mesh_phase_bind_groups.get(&TypeId::of::<P>())
3018 }
3019 }) else {
3020 return RenderCommandResult::Success;
3023 };
3024
3025 let Some(bind_group) = mesh_phase_bind_groups.get(
3026 mesh_asset_id,
3027 lightmap_slab_index,
3028 is_skinned,
3029 is_morphed,
3030 has_motion_vector_prepass,
3031 ) else {
3032 return RenderCommandResult::Failure(
3033 "The MeshBindGroups resource wasn't set in the render phase. \
3034 It should be set by the prepare_mesh_bind_group system.\n\
3035 This is a bevy bug! Please open an issue.",
3036 );
3037 };
3038
3039 let mut dynamic_offsets: [u32; 5] = Default::default();
3040 let mut offset_count = 0;
3041 if let PhaseItemExtraIndex::DynamicOffset(dynamic_offset) = item.extra_index() {
3042 dynamic_offsets[offset_count] = dynamic_offset;
3043 offset_count += 1;
3044 }
3045 if let Some(current_skin_index) = current_skin_byte_offset
3046 && skins_use_uniform_buffers(&render_device)
3047 {
3048 dynamic_offsets[offset_count] = current_skin_index.byte_offset;
3049 offset_count += 1;
3050 }
3051 if let Some(current_morph_index) = current_morph_index {
3052 dynamic_offsets[offset_count] = current_morph_index.index;
3053 offset_count += 1;
3054 }
3055
3056 if has_motion_vector_prepass {
3058 if skins_use_uniform_buffers(&render_device)
3060 && let Some(current_skin_byte_offset) = current_skin_byte_offset
3061 {
3062 dynamic_offsets[offset_count] = current_skin_byte_offset.byte_offset;
3063 offset_count += 1;
3064 }
3065
3066 if current_morph_index.is_some() {
3069 match prev_morph_index {
3070 Some(prev_morph_index) => {
3071 dynamic_offsets[offset_count] = prev_morph_index.index;
3072 }
3073 None => dynamic_offsets[offset_count] = 0,
3074 }
3075 offset_count += 1;
3076 }
3077 }
3078
3079 pass.set_bind_group(I, bind_group, &dynamic_offsets[0..offset_count]);
3080
3081 RenderCommandResult::Success
3082 }
3083}
3084
3085pub struct DrawMesh;
3086impl<P: PhaseItem> RenderCommand<P> for DrawMesh {
3087 type Param = (
3088 SRes<RenderAssets<RenderMesh>>,
3089 SRes<RenderMeshInstances>,
3090 SRes<IndirectParametersBuffers>,
3091 SRes<PipelineCache>,
3092 SRes<MeshAllocator>,
3093 Option<SRes<PreprocessPipelines>>,
3094 SRes<GpuPreprocessingSupport>,
3095 );
3096 type ViewQuery = Has<PreprocessBindGroups>;
3097 type ItemQuery = ();
3098 #[inline]
3099 fn render<'w>(
3100 item: &P,
3101 has_preprocess_bind_group: ROQueryItem<Self::ViewQuery>,
3102 _item_query: Option<()>,
3103 (
3104 meshes,
3105 mesh_instances,
3106 indirect_parameters_buffer,
3107 pipeline_cache,
3108 mesh_allocator,
3109 preprocess_pipelines,
3110 preprocessing_support,
3111 ): SystemParamItem<'w, '_, Self::Param>,
3112 pass: &mut TrackedRenderPass<'w>,
3113 ) -> RenderCommandResult {
3114 if let Some(preprocess_pipelines) = preprocess_pipelines
3118 && (!has_preprocess_bind_group
3119 || !preprocess_pipelines
3120 .pipelines_are_loaded(&pipeline_cache, &preprocessing_support))
3121 {
3122 return RenderCommandResult::Skip;
3123 }
3124
3125 let meshes = meshes.into_inner();
3126 let mesh_instances = mesh_instances.into_inner();
3127 let indirect_parameters_buffer = indirect_parameters_buffer.into_inner();
3128 let mesh_allocator = mesh_allocator.into_inner();
3129
3130 let Some(mesh_asset_id) = mesh_instances.mesh_asset_id(item.main_entity()) else {
3131 return RenderCommandResult::Skip;
3132 };
3133 let Some(gpu_mesh) = meshes.get(mesh_asset_id) else {
3134 return RenderCommandResult::Skip;
3135 };
3136 let Some(vertex_buffer_slice) = mesh_allocator.mesh_vertex_slice(&mesh_asset_id) else {
3137 return RenderCommandResult::Skip;
3138 };
3139
3140 pass.set_vertex_buffer(0, vertex_buffer_slice.buffer.slice(..));
3141
3142 let batch_range = item.batch_range();
3143
3144 match &gpu_mesh.buffer_info {
3148 RenderMeshBufferInfo::Indexed {
3149 index_format,
3150 count,
3151 } => {
3152 let Some(index_buffer_slice) = mesh_allocator.mesh_index_slice(&mesh_asset_id)
3153 else {
3154 return RenderCommandResult::Skip;
3155 };
3156
3157 pass.set_index_buffer(index_buffer_slice.buffer.slice(..), 0, *index_format);
3158
3159 match item.extra_index() {
3160 PhaseItemExtraIndex::None | PhaseItemExtraIndex::DynamicOffset(_) => {
3161 pass.draw_indexed(
3162 index_buffer_slice.range.start
3163 ..(index_buffer_slice.range.start + *count),
3164 vertex_buffer_slice.range.start as i32,
3165 batch_range.clone(),
3166 );
3167 }
3168 PhaseItemExtraIndex::IndirectParametersIndex {
3169 range: indirect_parameters_range,
3170 batch_set_index,
3171 } => {
3172 let Some(phase_indirect_parameters_buffers) =
3176 indirect_parameters_buffer.get(&TypeId::of::<P>())
3177 else {
3178 warn!(
3179 "Not rendering mesh because indexed indirect parameters buffer \
3180 wasn't present for this phase",
3181 );
3182 return RenderCommandResult::Skip;
3183 };
3184 let (Some(indirect_parameters_buffer), Some(batch_sets_buffer)) = (
3185 phase_indirect_parameters_buffers.indexed.data_buffer(),
3186 phase_indirect_parameters_buffers
3187 .indexed
3188 .batch_sets_buffer(),
3189 ) else {
3190 warn!(
3191 "Not rendering mesh because indexed indirect parameters buffer \
3192 wasn't present",
3193 );
3194 return RenderCommandResult::Skip;
3195 };
3196
3197 let indirect_parameters_offset = indirect_parameters_range.start as u64
3200 * size_of::<IndirectParametersIndexed>() as u64;
3201 let indirect_parameters_count =
3202 indirect_parameters_range.end - indirect_parameters_range.start;
3203
3204 match batch_set_index {
3209 Some(batch_set_index) => {
3210 let count_offset = u32::from(batch_set_index)
3211 * (size_of::<IndirectBatchSet>() as u32);
3212 pass.multi_draw_indexed_indirect_count(
3213 indirect_parameters_buffer,
3214 indirect_parameters_offset,
3215 batch_sets_buffer,
3216 count_offset as u64,
3217 indirect_parameters_count,
3218 );
3219 }
3220 None => {
3221 pass.multi_draw_indexed_indirect(
3222 indirect_parameters_buffer,
3223 indirect_parameters_offset,
3224 indirect_parameters_count,
3225 );
3226 }
3227 }
3228 }
3229 }
3230 }
3231
3232 RenderMeshBufferInfo::NonIndexed => match item.extra_index() {
3233 PhaseItemExtraIndex::None | PhaseItemExtraIndex::DynamicOffset(_) => {
3234 pass.draw(vertex_buffer_slice.range, batch_range.clone());
3235 }
3236 PhaseItemExtraIndex::IndirectParametersIndex {
3237 range: indirect_parameters_range,
3238 batch_set_index,
3239 } => {
3240 let Some(phase_indirect_parameters_buffers) =
3244 indirect_parameters_buffer.get(&TypeId::of::<P>())
3245 else {
3246 warn!(
3247 "Not rendering mesh because non-indexed indirect parameters buffer \
3248 wasn't present for this phase",
3249 );
3250 return RenderCommandResult::Skip;
3251 };
3252 let (Some(indirect_parameters_buffer), Some(batch_sets_buffer)) = (
3253 phase_indirect_parameters_buffers.non_indexed.data_buffer(),
3254 phase_indirect_parameters_buffers
3255 .non_indexed
3256 .batch_sets_buffer(),
3257 ) else {
3258 warn!(
3259 "Not rendering mesh because non-indexed indirect parameters buffer \
3260 wasn't present"
3261 );
3262 return RenderCommandResult::Skip;
3263 };
3264
3265 let indirect_parameters_offset = indirect_parameters_range.start as u64
3268 * size_of::<IndirectParametersNonIndexed>() as u64;
3269 let indirect_parameters_count =
3270 indirect_parameters_range.end - indirect_parameters_range.start;
3271
3272 match batch_set_index {
3277 Some(batch_set_index) => {
3278 let count_offset =
3279 u32::from(batch_set_index) * (size_of::<IndirectBatchSet>() as u32);
3280 pass.multi_draw_indirect_count(
3281 indirect_parameters_buffer,
3282 indirect_parameters_offset,
3283 batch_sets_buffer,
3284 count_offset as u64,
3285 indirect_parameters_count,
3286 );
3287 }
3288 None => {
3289 pass.multi_draw_indirect(
3290 indirect_parameters_buffer,
3291 indirect_parameters_offset,
3292 indirect_parameters_count,
3293 );
3294 }
3295 }
3296 }
3297 },
3298 }
3299 RenderCommandResult::Success
3300 }
3301}
3302
3303#[cfg(test)]
3304mod tests {
3305 use super::MeshPipelineKey;
3306 #[test]
3307 fn mesh_key_msaa_samples() {
3308 for i in [1, 2, 4, 8, 16, 32, 64, 128] {
3309 assert_eq!(MeshPipelineKey::from_msaa_samples(i).msaa_samples(), i);
3310 }
3311 }
3312}