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