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 for_gpu_building(
843 previous_transform: Option<&PreviousGlobalTransform>,
844 mesh: &Mesh3d,
845 tag: Option<&MeshTag>,
846 not_shadow_caster: bool,
847 no_automatic_batching: bool,
848 ) -> Self {
849 Self::for_cpu_building(
850 previous_transform,
851 mesh,
852 tag,
853 default(),
854 not_shadow_caster,
855 no_automatic_batching,
856 )
857 }
858
859 fn for_cpu_building(
861 previous_transform: Option<&PreviousGlobalTransform>,
862 mesh: &Mesh3d,
863 tag: Option<&MeshTag>,
864 material_bindings_index: MaterialBindingId,
865 not_shadow_caster: bool,
866 no_automatic_batching: bool,
867 ) -> Self {
868 let mut mesh_instance_flags = RenderMeshInstanceFlags::empty();
869 mesh_instance_flags.set(RenderMeshInstanceFlags::SHADOW_CASTER, !not_shadow_caster);
870 mesh_instance_flags.set(
871 RenderMeshInstanceFlags::AUTOMATIC_BATCHING,
872 !no_automatic_batching,
873 );
874 mesh_instance_flags.set(
875 RenderMeshInstanceFlags::HAS_PREVIOUS_TRANSFORM,
876 previous_transform.is_some(),
877 );
878
879 RenderMeshInstanceShared {
880 mesh_asset_id: mesh.id(),
881 flags: mesh_instance_flags,
882 material_bindings_index,
883 lightmap_slab_index: None,
884 tag: tag.map_or(0, |i| **i),
885 }
886 }
887
888 #[inline]
891 pub fn should_batch(&self) -> bool {
892 self.flags
893 .contains(RenderMeshInstanceFlags::AUTOMATIC_BATCHING)
894 }
895}
896
897#[derive(Resource)]
903pub enum RenderMeshInstances {
904 CpuBuilding(RenderMeshInstancesCpu),
906 GpuBuilding(RenderMeshInstancesGpu),
908}
909
910#[derive(Default, Deref, DerefMut)]
913pub struct RenderMeshInstancesCpu(MainEntityHashMap<RenderMeshInstanceCpu>);
914
915#[derive(Default, Deref, DerefMut)]
918pub struct RenderMeshInstancesGpu(MainEntityHashMap<RenderMeshInstanceGpu>);
919
920impl RenderMeshInstances {
921 fn new(use_gpu_instance_buffer_builder: bool) -> RenderMeshInstances {
923 if use_gpu_instance_buffer_builder {
924 RenderMeshInstances::GpuBuilding(RenderMeshInstancesGpu::default())
925 } else {
926 RenderMeshInstances::CpuBuilding(RenderMeshInstancesCpu::default())
927 }
928 }
929
930 pub fn mesh_asset_id(&self, entity: MainEntity) -> Option<AssetId<Mesh>> {
932 match *self {
933 RenderMeshInstances::CpuBuilding(ref instances) => instances.mesh_asset_id(entity),
934 RenderMeshInstances::GpuBuilding(ref instances) => instances.mesh_asset_id(entity),
935 }
936 }
937
938 pub fn render_mesh_queue_data(&self, entity: MainEntity) -> Option<RenderMeshQueueData> {
941 match *self {
942 RenderMeshInstances::CpuBuilding(ref instances) => {
943 instances.render_mesh_queue_data(entity)
944 }
945 RenderMeshInstances::GpuBuilding(ref instances) => {
946 instances.render_mesh_queue_data(entity)
947 }
948 }
949 }
950
951 fn insert_mesh_instance_flags(&mut self, entity: MainEntity, flags: RenderMeshInstanceFlags) {
954 match *self {
955 RenderMeshInstances::CpuBuilding(ref mut instances) => {
956 instances.insert_mesh_instance_flags(entity, flags);
957 }
958 RenderMeshInstances::GpuBuilding(ref mut instances) => {
959 instances.insert_mesh_instance_flags(entity, flags);
960 }
961 }
962 }
963}
964
965impl RenderMeshInstancesCpu {
966 fn mesh_asset_id(&self, entity: MainEntity) -> Option<AssetId<Mesh>> {
967 self.get(&entity)
968 .map(|render_mesh_instance| render_mesh_instance.mesh_asset_id)
969 }
970
971 fn render_mesh_queue_data(&self, entity: MainEntity) -> Option<RenderMeshQueueData> {
972 self.get(&entity)
973 .map(|render_mesh_instance| RenderMeshQueueData {
974 shared: &render_mesh_instance.shared,
975 translation: render_mesh_instance.transforms.world_from_local.translation,
976 current_uniform_index: InputUniformIndex::default(),
977 })
978 }
979
980 fn insert_mesh_instance_flags(&mut self, entity: MainEntity, flags: RenderMeshInstanceFlags) {
983 if let Some(instance) = self.get_mut(&entity) {
984 instance.flags.insert(flags);
985 }
986 }
987}
988
989impl RenderMeshInstancesGpu {
990 fn mesh_asset_id(&self, entity: MainEntity) -> Option<AssetId<Mesh>> {
991 self.get(&entity)
992 .map(|render_mesh_instance| render_mesh_instance.mesh_asset_id)
993 }
994
995 fn render_mesh_queue_data(&self, entity: MainEntity) -> Option<RenderMeshQueueData> {
996 self.get(&entity)
997 .map(|render_mesh_instance| RenderMeshQueueData {
998 shared: &render_mesh_instance.shared,
999 translation: render_mesh_instance.translation,
1000 current_uniform_index: InputUniformIndex(
1001 render_mesh_instance.current_uniform_index.into(),
1002 ),
1003 })
1004 }
1005
1006 fn insert_mesh_instance_flags(&mut self, entity: MainEntity, flags: RenderMeshInstanceFlags) {
1009 if let Some(instance) = self.get_mut(&entity) {
1010 instance.flags.insert(flags);
1011 }
1012 }
1013}
1014
1015impl RenderMeshInstanceGpuQueue {
1016 fn init(&mut self, any_gpu_culling: bool) {
1022 match (any_gpu_culling, &mut *self) {
1023 (true, RenderMeshInstanceGpuQueue::GpuCulling { changed, removed }) => {
1024 changed.clear();
1025 removed.clear();
1026 }
1027 (true, _) => {
1028 *self = RenderMeshInstanceGpuQueue::GpuCulling {
1029 changed: vec![],
1030 removed: vec![],
1031 }
1032 }
1033 (false, RenderMeshInstanceGpuQueue::CpuCulling { changed, removed }) => {
1034 changed.clear();
1035 removed.clear();
1036 }
1037 (false, _) => {
1038 *self = RenderMeshInstanceGpuQueue::CpuCulling {
1039 changed: vec![],
1040 removed: vec![],
1041 }
1042 }
1043 }
1044 }
1045
1046 fn push(
1048 &mut self,
1049 entity: MainEntity,
1050 instance_builder: RenderMeshInstanceGpuBuilder,
1051 culling_data_builder: Option<MeshCullingData>,
1052 ) {
1053 match (&mut *self, culling_data_builder) {
1054 (
1055 &mut RenderMeshInstanceGpuQueue::CpuCulling {
1056 changed: ref mut queue,
1057 ..
1058 },
1059 None,
1060 ) => {
1061 queue.push((entity, instance_builder));
1062 }
1063 (
1064 &mut RenderMeshInstanceGpuQueue::GpuCulling {
1065 changed: ref mut queue,
1066 ..
1067 },
1068 Some(culling_data_builder),
1069 ) => {
1070 queue.push((entity, instance_builder, culling_data_builder));
1071 }
1072 (_, None) => {
1073 *self = RenderMeshInstanceGpuQueue::CpuCulling {
1074 changed: vec![(entity, instance_builder)],
1075 removed: vec![],
1076 };
1077 }
1078 (_, Some(culling_data_builder)) => {
1079 *self = RenderMeshInstanceGpuQueue::GpuCulling {
1080 changed: vec![(entity, instance_builder, culling_data_builder)],
1081 removed: vec![],
1082 };
1083 }
1084 }
1085 }
1086
1087 fn remove(&mut self, entity: MainEntity, gpu_culling: bool) {
1091 match (&mut *self, gpu_culling) {
1092 (RenderMeshInstanceGpuQueue::None, false) => {
1093 *self = RenderMeshInstanceGpuQueue::CpuCulling {
1094 changed: vec![],
1095 removed: vec![entity],
1096 }
1097 }
1098 (RenderMeshInstanceGpuQueue::None, true) => {
1099 *self = RenderMeshInstanceGpuQueue::GpuCulling {
1100 changed: vec![],
1101 removed: vec![entity],
1102 }
1103 }
1104 (RenderMeshInstanceGpuQueue::CpuCulling { removed, .. }, _)
1105 | (RenderMeshInstanceGpuQueue::GpuCulling { removed, .. }, _) => {
1106 removed.push(entity);
1107 }
1108 }
1109 }
1110}
1111
1112impl RenderMeshInstanceGpuBuilder {
1113 fn update(
1116 mut self,
1117 entity: MainEntity,
1118 render_mesh_instances: &mut MainEntityHashMap<RenderMeshInstanceGpu>,
1119 current_input_buffer: &mut InstanceInputUniformBuffer<MeshInputUniform>,
1120 previous_input_buffer: &mut InstanceInputUniformBuffer<MeshInputUniform>,
1121 mesh_allocator: &MeshAllocator,
1122 mesh_material_ids: &RenderMaterialInstances,
1123 render_material_bindings: &RenderMaterialBindings,
1124 render_lightmaps: &RenderLightmaps,
1125 skin_uniforms: &SkinUniforms,
1126 timestamp: FrameCount,
1127 meshes_to_reextract_next_frame: &mut MeshesToReextractNextFrame,
1128 ) -> Option<u32> {
1129 let (first_vertex_index, vertex_count) =
1130 match mesh_allocator.mesh_vertex_slice(&self.shared.mesh_asset_id) {
1131 Some(mesh_vertex_slice) => (
1132 mesh_vertex_slice.range.start,
1133 mesh_vertex_slice.range.end - mesh_vertex_slice.range.start,
1134 ),
1135 None => (0, 0),
1136 };
1137 let (mesh_is_indexed, first_index_index, index_count) =
1138 match mesh_allocator.mesh_index_slice(&self.shared.mesh_asset_id) {
1139 Some(mesh_index_slice) => (
1140 true,
1141 mesh_index_slice.range.start,
1142 mesh_index_slice.range.end - mesh_index_slice.range.start,
1143 ),
1144 None => (false, 0, 0),
1145 };
1146 let current_skin_index = match skin_uniforms.skin_byte_offset(entity) {
1147 Some(skin_index) => skin_index.index(),
1148 None => u32::MAX,
1149 };
1150
1151 let mesh_material = mesh_material_ids.mesh_material(entity);
1156 let mesh_material_binding_id = if mesh_material != DUMMY_MESH_MATERIAL.untyped() {
1157 match render_material_bindings.get(&mesh_material) {
1158 Some(binding_id) => *binding_id,
1159 None => {
1160 meshes_to_reextract_next_frame.insert(entity);
1161 return None;
1162 }
1163 }
1164 } else {
1165 MaterialBindingId::default()
1167 };
1168 self.shared.material_bindings_index = mesh_material_binding_id;
1169
1170 let lightmap_slot = match render_lightmaps.render_lightmaps.get(&entity) {
1171 Some(render_lightmap) => u16::from(*render_lightmap.slot_index),
1172 None => u16::MAX,
1173 };
1174 let lightmap_slab_index = render_lightmaps
1175 .render_lightmaps
1176 .get(&entity)
1177 .map(|lightmap| lightmap.slab_index);
1178 self.shared.lightmap_slab_index = lightmap_slab_index;
1179
1180 let mut mesh_input_uniform = MeshInputUniform {
1182 world_from_local: self.world_from_local.to_transpose(),
1183 lightmap_uv_rect: self.lightmap_uv_rect,
1184 flags: self.mesh_flags.bits(),
1185 previous_input_index: u32::MAX,
1186 timestamp: timestamp.0,
1187 first_vertex_index,
1188 first_index_index,
1189 index_count: if mesh_is_indexed {
1190 index_count
1191 } else {
1192 vertex_count
1193 },
1194 current_skin_index,
1195 material_and_lightmap_bind_group_slot: u32::from(
1196 self.shared.material_bindings_index.slot,
1197 ) | ((lightmap_slot as u32) << 16),
1198 tag: self.shared.tag,
1199 pad: 0,
1200 };
1201
1202 let current_uniform_index;
1204 match render_mesh_instances.entry(entity) {
1205 Entry::Occupied(mut occupied_entry) => {
1206 current_uniform_index = u32::from(occupied_entry.get_mut().current_uniform_index);
1210
1211 let previous_mesh_input_uniform =
1214 current_input_buffer.get_unchecked(current_uniform_index);
1215 let previous_input_index = previous_input_buffer.add(previous_mesh_input_uniform);
1216 mesh_input_uniform.previous_input_index = previous_input_index;
1217
1218 current_input_buffer.set(current_uniform_index, mesh_input_uniform);
1220
1221 occupied_entry.replace_entry_with(|_, _| {
1222 Some(RenderMeshInstanceGpu {
1223 translation: self.world_from_local.translation,
1224 shared: self.shared,
1225 current_uniform_index: NonMaxU32::new(current_uniform_index)
1226 .unwrap_or_default(),
1227 })
1228 });
1229 }
1230
1231 Entry::Vacant(vacant_entry) => {
1232 current_uniform_index = current_input_buffer.add(mesh_input_uniform);
1234
1235 vacant_entry.insert(RenderMeshInstanceGpu {
1236 translation: self.world_from_local.translation,
1237 shared: self.shared,
1238 current_uniform_index: NonMaxU32::new(current_uniform_index)
1239 .unwrap_or_default(),
1240 });
1241 }
1242 }
1243
1244 Some(current_uniform_index)
1245 }
1246}
1247
1248fn remove_mesh_input_uniform(
1251 entity: MainEntity,
1252 render_mesh_instances: &mut MainEntityHashMap<RenderMeshInstanceGpu>,
1253 current_input_buffer: &mut InstanceInputUniformBuffer<MeshInputUniform>,
1254) -> Option<u32> {
1255 let removed_render_mesh_instance = render_mesh_instances.remove(&entity)?;
1257
1258 let removed_uniform_index = removed_render_mesh_instance.current_uniform_index.get();
1259 current_input_buffer.remove(removed_uniform_index);
1260 Some(removed_uniform_index)
1261}
1262
1263impl MeshCullingData {
1264 fn new(aabb: Option<&Aabb>) -> Self {
1269 match aabb {
1270 Some(aabb) => MeshCullingData {
1271 aabb_center: aabb.center.extend(0.0),
1272 aabb_half_extents: aabb.half_extents.extend(0.0),
1273 },
1274 None => MeshCullingData {
1275 aabb_center: Vec3::ZERO.extend(0.0),
1276 aabb_half_extents: Vec3::INFINITY.extend(0.0),
1277 },
1278 }
1279 }
1280
1281 fn update(
1284 &self,
1285 mesh_culling_data_buffer: &mut MeshCullingDataBuffer,
1286 instance_data_index: usize,
1287 ) {
1288 while mesh_culling_data_buffer.len() < instance_data_index + 1 {
1289 mesh_culling_data_buffer.push(MeshCullingData::default());
1290 }
1291 mesh_culling_data_buffer.values_mut()[instance_data_index] = *self;
1292 }
1293}
1294
1295impl Default for MeshCullingDataBuffer {
1296 #[inline]
1297 fn default() -> Self {
1298 Self(RawBufferVec::new(BufferUsages::STORAGE))
1299 }
1300}
1301
1302#[derive(Deref)]
1305pub struct RenderMeshQueueData<'a> {
1306 #[deref]
1308 pub shared: &'a RenderMeshInstanceShared,
1309 pub translation: Vec3,
1311 pub current_uniform_index: InputUniformIndex,
1314}
1315
1316#[derive(SystemSet, Clone, PartialEq, Eq, Debug, Hash)]
1319pub struct ExtractMeshesSet;
1320
1321pub fn extract_meshes_for_cpu_building(
1327 mut render_mesh_instances: ResMut<RenderMeshInstances>,
1328 mesh_material_ids: Res<RenderMaterialInstances>,
1329 render_material_bindings: Res<RenderMaterialBindings>,
1330 render_visibility_ranges: Res<RenderVisibilityRanges>,
1331 mut render_mesh_instance_queues: Local<Parallel<Vec<(Entity, RenderMeshInstanceCpu)>>>,
1332 meshes_query: Extract<
1333 Query<(
1334 Entity,
1335 &ViewVisibility,
1336 &GlobalTransform,
1337 Option<&PreviousGlobalTransform>,
1338 &Mesh3d,
1339 Option<&MeshTag>,
1340 Has<NoFrustumCulling>,
1341 Has<NotShadowReceiver>,
1342 Has<TransmittedShadowReceiver>,
1343 Has<NotShadowCaster>,
1344 Has<NoAutomaticBatching>,
1345 Has<VisibilityRange>,
1346 )>,
1347 >,
1348) {
1349 meshes_query.par_iter().for_each_init(
1350 || render_mesh_instance_queues.borrow_local_mut(),
1351 |queue,
1352 (
1353 entity,
1354 view_visibility,
1355 transform,
1356 previous_transform,
1357 mesh,
1358 tag,
1359 no_frustum_culling,
1360 not_shadow_receiver,
1361 transmitted_receiver,
1362 not_shadow_caster,
1363 no_automatic_batching,
1364 visibility_range,
1365 )| {
1366 if !view_visibility.get() {
1367 return;
1368 }
1369
1370 let mut lod_index = None;
1371 if visibility_range {
1372 lod_index = render_visibility_ranges.lod_index_for_entity(entity.into());
1373 }
1374
1375 let mesh_flags = MeshFlags::from_components(
1376 transform,
1377 lod_index,
1378 no_frustum_culling,
1379 not_shadow_receiver,
1380 transmitted_receiver,
1381 );
1382
1383 let mesh_material = mesh_material_ids.mesh_material(MainEntity::from(entity));
1384
1385 let material_bindings_index = render_material_bindings
1386 .get(&mesh_material)
1387 .copied()
1388 .unwrap_or_default();
1389
1390 let shared = RenderMeshInstanceShared::for_cpu_building(
1391 previous_transform,
1392 mesh,
1393 tag,
1394 material_bindings_index,
1395 not_shadow_caster,
1396 no_automatic_batching,
1397 );
1398
1399 let world_from_local = transform.affine();
1400 queue.push((
1401 entity,
1402 RenderMeshInstanceCpu {
1403 transforms: MeshTransforms {
1404 world_from_local: (&world_from_local).into(),
1405 previous_world_from_local: (&previous_transform
1406 .map(|t| t.0)
1407 .unwrap_or(world_from_local))
1408 .into(),
1409 flags: mesh_flags.bits(),
1410 },
1411 shared,
1412 },
1413 ));
1414 },
1415 );
1416
1417 let RenderMeshInstances::CpuBuilding(ref mut render_mesh_instances) = *render_mesh_instances
1419 else {
1420 panic!(
1421 "`extract_meshes_for_cpu_building` should only be called if we're using CPU \
1422 `MeshUniform` building"
1423 );
1424 };
1425
1426 render_mesh_instances.clear();
1427 for queue in render_mesh_instance_queues.iter_mut() {
1428 for (entity, render_mesh_instance) in queue.drain(..) {
1429 render_mesh_instances.insert(entity.into(), render_mesh_instance);
1430 }
1431 }
1432}
1433
1434type GpuMeshExtractionQuery = (
1436 Entity,
1437 Read<ViewVisibility>,
1438 Read<GlobalTransform>,
1439 Option<Read<PreviousGlobalTransform>>,
1440 Option<Read<Lightmap>>,
1441 Option<Read<Aabb>>,
1442 Read<Mesh3d>,
1443 Option<Read<MeshTag>>,
1444 Has<NoFrustumCulling>,
1445 Has<NotShadowReceiver>,
1446 Has<TransmittedShadowReceiver>,
1447 Has<NotShadowCaster>,
1448 Has<NoAutomaticBatching>,
1449 Has<VisibilityRange>,
1450);
1451
1452pub fn extract_meshes_for_gpu_building(
1461 mut render_mesh_instances: ResMut<RenderMeshInstances>,
1462 render_visibility_ranges: Res<RenderVisibilityRanges>,
1463 mut render_mesh_instance_queues: ResMut<RenderMeshInstanceGpuQueues>,
1464 changed_meshes_query: Extract<
1465 Query<
1466 GpuMeshExtractionQuery,
1467 Or<(
1468 Changed<ViewVisibility>,
1469 Changed<GlobalTransform>,
1470 Changed<PreviousGlobalTransform>,
1471 Changed<Lightmap>,
1472 Changed<Aabb>,
1473 Changed<Mesh3d>,
1474 Changed<NoFrustumCulling>,
1475 Changed<NotShadowReceiver>,
1476 Changed<TransmittedShadowReceiver>,
1477 Changed<NotShadowCaster>,
1478 Changed<NoAutomaticBatching>,
1479 Changed<VisibilityRange>,
1480 Changed<SkinnedMesh>,
1481 )>,
1482 >,
1483 >,
1484 all_meshes_query: Extract<Query<GpuMeshExtractionQuery>>,
1485 mut removed_visibilities_query: Extract<RemovedComponents<ViewVisibility>>,
1486 mut removed_global_transforms_query: Extract<RemovedComponents<GlobalTransform>>,
1487 mut removed_meshes_query: Extract<RemovedComponents<Mesh3d>>,
1488 gpu_culling_query: Extract<Query<(), (With<Camera>, Without<NoIndirectDrawing>)>>,
1489 meshes_to_reextract_next_frame: ResMut<MeshesToReextractNextFrame>,
1490) {
1491 let any_gpu_culling = !gpu_culling_query.is_empty();
1492
1493 for render_mesh_instance_queue in render_mesh_instance_queues.iter_mut() {
1494 render_mesh_instance_queue.init(any_gpu_culling);
1495 }
1496
1497 let RenderMeshInstances::GpuBuilding(ref mut render_mesh_instances) = *render_mesh_instances
1500 else {
1501 panic!(
1502 "`extract_meshes_for_gpu_building` should only be called if we're \
1503 using GPU `MeshUniform` building"
1504 );
1505 };
1506
1507 changed_meshes_query.par_iter().for_each_init(
1510 || render_mesh_instance_queues.borrow_local_mut(),
1511 |queue, query_row| {
1512 extract_mesh_for_gpu_building(
1513 query_row,
1514 &render_visibility_ranges,
1515 render_mesh_instances,
1516 queue,
1517 any_gpu_culling,
1518 );
1519 },
1520 );
1521
1522 let mut queue = render_mesh_instance_queues.borrow_local_mut();
1529 for &mesh_entity in &**meshes_to_reextract_next_frame {
1530 if let Ok(query_row) = all_meshes_query.get(*mesh_entity) {
1531 extract_mesh_for_gpu_building(
1532 query_row,
1533 &render_visibility_ranges,
1534 render_mesh_instances,
1535 &mut queue,
1536 any_gpu_culling,
1537 );
1538 }
1539 }
1540
1541 for entity in removed_visibilities_query
1543 .read()
1544 .chain(removed_global_transforms_query.read())
1545 .chain(removed_meshes_query.read())
1546 {
1547 let entity = MainEntity::from(entity);
1551 if !changed_meshes_query.contains(*entity)
1552 && !meshes_to_reextract_next_frame.contains(&entity)
1553 {
1554 queue.remove(entity, any_gpu_culling);
1555 }
1556 }
1557}
1558
1559fn extract_mesh_for_gpu_building(
1560 (
1561 entity,
1562 view_visibility,
1563 transform,
1564 previous_transform,
1565 lightmap,
1566 aabb,
1567 mesh,
1568 tag,
1569 no_frustum_culling,
1570 not_shadow_receiver,
1571 transmitted_receiver,
1572 not_shadow_caster,
1573 no_automatic_batching,
1574 visibility_range,
1575 ): <GpuMeshExtractionQuery as QueryData>::Item<'_>,
1576 render_visibility_ranges: &RenderVisibilityRanges,
1577 render_mesh_instances: &RenderMeshInstancesGpu,
1578 queue: &mut RenderMeshInstanceGpuQueue,
1579 any_gpu_culling: bool,
1580) {
1581 if !view_visibility.get() {
1582 queue.remove(entity.into(), any_gpu_culling);
1583 return;
1584 }
1585
1586 let mut lod_index = None;
1587 if visibility_range {
1588 lod_index = render_visibility_ranges.lod_index_for_entity(entity.into());
1589 }
1590
1591 let mesh_flags = MeshFlags::from_components(
1592 transform,
1593 lod_index,
1594 no_frustum_culling,
1595 not_shadow_receiver,
1596 transmitted_receiver,
1597 );
1598
1599 let shared = RenderMeshInstanceShared::for_gpu_building(
1600 previous_transform,
1601 mesh,
1602 tag,
1603 not_shadow_caster,
1604 no_automatic_batching,
1605 );
1606
1607 let lightmap_uv_rect = pack_lightmap_uv_rect(lightmap.map(|lightmap| lightmap.uv_rect));
1608
1609 let gpu_mesh_culling_data = any_gpu_culling.then(|| MeshCullingData::new(aabb));
1610
1611 let previous_input_index = if shared
1612 .flags
1613 .contains(RenderMeshInstanceFlags::HAS_PREVIOUS_TRANSFORM)
1614 {
1615 render_mesh_instances
1616 .get(&MainEntity::from(entity))
1617 .map(|render_mesh_instance| render_mesh_instance.current_uniform_index)
1618 } else {
1619 None
1620 };
1621
1622 let gpu_mesh_instance_builder = RenderMeshInstanceGpuBuilder {
1623 shared,
1624 world_from_local: (&transform.affine()).into(),
1625 lightmap_uv_rect,
1626 mesh_flags,
1627 previous_input_index,
1628 };
1629
1630 queue.push(
1631 entity.into(),
1632 gpu_mesh_instance_builder,
1633 gpu_mesh_culling_data,
1634 );
1635}
1636
1637pub(crate) fn set_mesh_motion_vector_flags(
1652 mut render_mesh_instances: ResMut<RenderMeshInstances>,
1653 skin_uniforms: Res<SkinUniforms>,
1654 morph_indices: Res<MorphIndices>,
1655) {
1656 for &entity in skin_uniforms.all_skins() {
1657 render_mesh_instances
1658 .insert_mesh_instance_flags(entity, RenderMeshInstanceFlags::HAS_PREVIOUS_SKIN);
1659 }
1660 for &entity in morph_indices.prev.keys() {
1661 render_mesh_instances
1662 .insert_mesh_instance_flags(entity, RenderMeshInstanceFlags::HAS_PREVIOUS_MORPH);
1663 }
1664}
1665
1666pub fn collect_meshes_for_gpu_building(
1669 render_mesh_instances: ResMut<RenderMeshInstances>,
1670 batched_instance_buffers: ResMut<
1671 gpu_preprocessing::BatchedInstanceBuffers<MeshUniform, MeshInputUniform>,
1672 >,
1673 mut mesh_culling_data_buffer: ResMut<MeshCullingDataBuffer>,
1674 mut render_mesh_instance_queues: ResMut<RenderMeshInstanceGpuQueues>,
1675 mesh_allocator: Res<MeshAllocator>,
1676 mesh_material_ids: Res<RenderMaterialInstances>,
1677 render_material_bindings: Res<RenderMaterialBindings>,
1678 render_lightmaps: Res<RenderLightmaps>,
1679 skin_uniforms: Res<SkinUniforms>,
1680 frame_count: Res<FrameCount>,
1681 mut meshes_to_reextract_next_frame: ResMut<MeshesToReextractNextFrame>,
1682) {
1683 let RenderMeshInstances::GpuBuilding(render_mesh_instances) =
1684 render_mesh_instances.into_inner()
1685 else {
1686 return;
1687 };
1688
1689 meshes_to_reextract_next_frame.clear();
1691
1692 let gpu_preprocessing::BatchedInstanceBuffers {
1694 current_input_buffer,
1695 previous_input_buffer,
1696 ..
1697 } = batched_instance_buffers.into_inner();
1698
1699 previous_input_buffer.clear();
1700
1701 for queue in render_mesh_instance_queues.iter_mut() {
1704 match *queue {
1705 RenderMeshInstanceGpuQueue::None => {
1706 }
1708
1709 RenderMeshInstanceGpuQueue::CpuCulling {
1710 ref mut changed,
1711 ref mut removed,
1712 } => {
1713 for (entity, mesh_instance_builder) in changed.drain(..) {
1714 mesh_instance_builder.update(
1715 entity,
1716 &mut *render_mesh_instances,
1717 current_input_buffer,
1718 previous_input_buffer,
1719 &mesh_allocator,
1720 &mesh_material_ids,
1721 &render_material_bindings,
1722 &render_lightmaps,
1723 &skin_uniforms,
1724 *frame_count,
1725 &mut meshes_to_reextract_next_frame,
1726 );
1727 }
1728
1729 for entity in removed.drain(..) {
1730 remove_mesh_input_uniform(
1731 entity,
1732 &mut *render_mesh_instances,
1733 current_input_buffer,
1734 );
1735 }
1736 }
1737
1738 RenderMeshInstanceGpuQueue::GpuCulling {
1739 ref mut changed,
1740 ref mut removed,
1741 } => {
1742 for (entity, mesh_instance_builder, mesh_culling_builder) in changed.drain(..) {
1743 let Some(instance_data_index) = mesh_instance_builder.update(
1744 entity,
1745 &mut *render_mesh_instances,
1746 current_input_buffer,
1747 previous_input_buffer,
1748 &mesh_allocator,
1749 &mesh_material_ids,
1750 &render_material_bindings,
1751 &render_lightmaps,
1752 &skin_uniforms,
1753 *frame_count,
1754 &mut meshes_to_reextract_next_frame,
1755 ) else {
1756 continue;
1757 };
1758 mesh_culling_builder
1759 .update(&mut mesh_culling_data_buffer, instance_data_index as usize);
1760 }
1761
1762 for entity in removed.drain(..) {
1763 remove_mesh_input_uniform(
1764 entity,
1765 &mut *render_mesh_instances,
1766 current_input_buffer,
1767 );
1768 }
1769 }
1770 }
1771 }
1772
1773 previous_input_buffer.ensure_nonempty();
1775}
1776
1777#[derive(Resource, Clone)]
1779pub struct MeshPipeline {
1780 pub view_layouts: MeshPipelineViewLayouts,
1782 pub dummy_white_gpu_image: GpuImage,
1784 pub clustered_forward_buffer_binding_type: BufferBindingType,
1785 pub mesh_layouts: MeshLayouts,
1786 pub per_object_buffer_batch_size: Option<u32>,
1798
1799 pub binding_arrays_are_usable: bool,
1804
1805 pub clustered_decals_are_usable: bool,
1807
1808 pub skins_use_uniform_buffers: bool,
1811}
1812
1813impl FromWorld for MeshPipeline {
1814 fn from_world(world: &mut World) -> Self {
1815 let mut system_state: SystemState<(
1816 Res<RenderDevice>,
1817 Res<RenderAdapter>,
1818 Res<DefaultImageSampler>,
1819 Res<RenderQueue>,
1820 Res<MeshPipelineViewLayouts>,
1821 )> = SystemState::new(world);
1822 let (render_device, render_adapter, default_sampler, render_queue, view_layouts) =
1823 system_state.get_mut(world);
1824
1825 let clustered_forward_buffer_binding_type = render_device
1826 .get_supported_read_only_binding_type(CLUSTERED_FORWARD_STORAGE_BUFFER_COUNT);
1827
1828 let dummy_white_gpu_image = {
1830 let image = Image::default();
1831 let texture = render_device.create_texture(&image.texture_descriptor);
1832 let sampler = match image.sampler {
1833 ImageSampler::Default => (**default_sampler).clone(),
1834 ImageSampler::Descriptor(ref descriptor) => {
1835 render_device.create_sampler(&descriptor.as_wgpu())
1836 }
1837 };
1838
1839 let format_size = image.texture_descriptor.format.pixel_size();
1840 render_queue.write_texture(
1841 texture.as_image_copy(),
1842 image.data.as_ref().expect("Image was created without data"),
1843 TexelCopyBufferLayout {
1844 offset: 0,
1845 bytes_per_row: Some(image.width() * format_size as u32),
1846 rows_per_image: None,
1847 },
1848 image.texture_descriptor.size,
1849 );
1850
1851 let texture_view = texture.create_view(&TextureViewDescriptor::default());
1852 GpuImage {
1853 texture,
1854 texture_view,
1855 texture_format: image.texture_descriptor.format,
1856 sampler,
1857 size: image.texture_descriptor.size,
1858 mip_level_count: image.texture_descriptor.mip_level_count,
1859 }
1860 };
1861
1862 MeshPipeline {
1863 view_layouts: view_layouts.clone(),
1864 clustered_forward_buffer_binding_type,
1865 dummy_white_gpu_image,
1866 mesh_layouts: MeshLayouts::new(&render_device, &render_adapter),
1867 per_object_buffer_batch_size: GpuArrayBuffer::<MeshUniform>::batch_size(&render_device),
1868 binding_arrays_are_usable: binding_arrays_are_usable(&render_device, &render_adapter),
1869 clustered_decals_are_usable: decal::clustered::clustered_decals_are_usable(
1870 &render_device,
1871 &render_adapter,
1872 ),
1873 skins_use_uniform_buffers: skins_use_uniform_buffers(&render_device),
1874 }
1875 }
1876}
1877
1878impl MeshPipeline {
1879 pub fn get_image_texture<'a>(
1880 &'a self,
1881 gpu_images: &'a RenderAssets<GpuImage>,
1882 handle_option: &Option<Handle<Image>>,
1883 ) -> Option<(&'a TextureView, &'a Sampler)> {
1884 if let Some(handle) = handle_option {
1885 let gpu_image = gpu_images.get(handle)?;
1886 Some((&gpu_image.texture_view, &gpu_image.sampler))
1887 } else {
1888 Some((
1889 &self.dummy_white_gpu_image.texture_view,
1890 &self.dummy_white_gpu_image.sampler,
1891 ))
1892 }
1893 }
1894
1895 pub fn get_view_layout(&self, layout_key: MeshPipelineViewLayoutKey) -> &BindGroupLayout {
1896 self.view_layouts.get_view_layout(layout_key)
1897 }
1898}
1899
1900impl GetBatchData for MeshPipeline {
1901 type Param = (
1902 SRes<RenderMeshInstances>,
1903 SRes<RenderLightmaps>,
1904 SRes<RenderAssets<RenderMesh>>,
1905 SRes<MeshAllocator>,
1906 SRes<SkinUniforms>,
1907 );
1908 type CompareData = (
1911 MaterialBindGroupIndex,
1912 AssetId<Mesh>,
1913 Option<LightmapSlabIndex>,
1914 );
1915
1916 type BufferData = MeshUniform;
1917
1918 fn get_batch_data(
1919 (mesh_instances, lightmaps, _, mesh_allocator, skin_uniforms): &SystemParamItem<
1920 Self::Param,
1921 >,
1922 (_entity, main_entity): (Entity, MainEntity),
1923 ) -> Option<(Self::BufferData, Option<Self::CompareData>)> {
1924 let RenderMeshInstances::CpuBuilding(ref mesh_instances) = **mesh_instances else {
1925 error!(
1926 "`get_batch_data` should never be called in GPU mesh uniform \
1927 building mode"
1928 );
1929 return None;
1930 };
1931 let mesh_instance = mesh_instances.get(&main_entity)?;
1932 let first_vertex_index =
1933 match mesh_allocator.mesh_vertex_slice(&mesh_instance.mesh_asset_id) {
1934 Some(mesh_vertex_slice) => mesh_vertex_slice.range.start,
1935 None => 0,
1936 };
1937 let maybe_lightmap = lightmaps.render_lightmaps.get(&main_entity);
1938
1939 let current_skin_index = skin_uniforms.skin_index(main_entity);
1940 let material_bind_group_index = mesh_instance.material_bindings_index;
1941
1942 Some((
1943 MeshUniform::new(
1944 &mesh_instance.transforms,
1945 first_vertex_index,
1946 material_bind_group_index.slot,
1947 maybe_lightmap.map(|lightmap| (lightmap.slot_index, lightmap.uv_rect)),
1948 current_skin_index,
1949 Some(mesh_instance.tag),
1950 ),
1951 mesh_instance.should_batch().then_some((
1952 material_bind_group_index.group,
1953 mesh_instance.mesh_asset_id,
1954 maybe_lightmap.map(|lightmap| lightmap.slab_index),
1955 )),
1956 ))
1957 }
1958}
1959
1960impl GetFullBatchData for MeshPipeline {
1961 type BufferInputData = MeshInputUniform;
1962
1963 fn get_index_and_compare_data(
1964 (mesh_instances, lightmaps, _, _, _): &SystemParamItem<Self::Param>,
1965 main_entity: MainEntity,
1966 ) -> Option<(NonMaxU32, Option<Self::CompareData>)> {
1967 let RenderMeshInstances::GpuBuilding(ref mesh_instances) = **mesh_instances else {
1969 error!(
1970 "`get_index_and_compare_data` should never be called in CPU mesh uniform building \
1971 mode"
1972 );
1973 return None;
1974 };
1975
1976 let mesh_instance = mesh_instances.get(&main_entity)?;
1977 let maybe_lightmap = lightmaps.render_lightmaps.get(&main_entity);
1978
1979 Some((
1980 mesh_instance.current_uniform_index,
1981 mesh_instance.should_batch().then_some((
1982 mesh_instance.material_bindings_index.group,
1983 mesh_instance.mesh_asset_id,
1984 maybe_lightmap.map(|lightmap| lightmap.slab_index),
1985 )),
1986 ))
1987 }
1988
1989 fn get_binned_batch_data(
1990 (mesh_instances, lightmaps, _, mesh_allocator, skin_uniforms): &SystemParamItem<
1991 Self::Param,
1992 >,
1993 main_entity: MainEntity,
1994 ) -> Option<Self::BufferData> {
1995 let RenderMeshInstances::CpuBuilding(ref mesh_instances) = **mesh_instances else {
1996 error!(
1997 "`get_binned_batch_data` should never be called in GPU mesh uniform building mode"
1998 );
1999 return None;
2000 };
2001 let mesh_instance = mesh_instances.get(&main_entity)?;
2002 let first_vertex_index =
2003 match mesh_allocator.mesh_vertex_slice(&mesh_instance.mesh_asset_id) {
2004 Some(mesh_vertex_slice) => mesh_vertex_slice.range.start,
2005 None => 0,
2006 };
2007 let maybe_lightmap = lightmaps.render_lightmaps.get(&main_entity);
2008
2009 let current_skin_index = skin_uniforms.skin_index(main_entity);
2010
2011 Some(MeshUniform::new(
2012 &mesh_instance.transforms,
2013 first_vertex_index,
2014 mesh_instance.material_bindings_index.slot,
2015 maybe_lightmap.map(|lightmap| (lightmap.slot_index, lightmap.uv_rect)),
2016 current_skin_index,
2017 Some(mesh_instance.tag),
2018 ))
2019 }
2020
2021 fn get_binned_index(
2022 (mesh_instances, _, _, _, _): &SystemParamItem<Self::Param>,
2023 main_entity: MainEntity,
2024 ) -> Option<NonMaxU32> {
2025 let RenderMeshInstances::GpuBuilding(ref mesh_instances) = **mesh_instances else {
2027 error!(
2028 "`get_binned_index` should never be called in CPU mesh uniform \
2029 building mode"
2030 );
2031 return None;
2032 };
2033
2034 mesh_instances
2035 .get(&main_entity)
2036 .map(|entity| entity.current_uniform_index)
2037 }
2038
2039 fn write_batch_indirect_parameters_metadata(
2040 indexed: bool,
2041 base_output_index: u32,
2042 batch_set_index: Option<NonMaxU32>,
2043 phase_indirect_parameters_buffers: &mut UntypedPhaseIndirectParametersBuffers,
2044 indirect_parameters_offset: u32,
2045 ) {
2046 let indirect_parameters = IndirectParametersCpuMetadata {
2047 base_output_index,
2048 batch_set_index: match batch_set_index {
2049 Some(batch_set_index) => u32::from(batch_set_index),
2050 None => !0,
2051 },
2052 };
2053
2054 if indexed {
2055 phase_indirect_parameters_buffers
2056 .indexed
2057 .set(indirect_parameters_offset, indirect_parameters);
2058 } else {
2059 phase_indirect_parameters_buffers
2060 .non_indexed
2061 .set(indirect_parameters_offset, indirect_parameters);
2062 }
2063 }
2064}
2065
2066bitflags::bitflags! {
2067 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
2068 #[repr(transparent)]
2069 pub struct MeshPipelineKey: u64 {
2072 const NONE = 0;
2074
2075 const MORPH_TARGETS = BaseMeshPipelineKey::MORPH_TARGETS.bits();
2077
2078 const HDR = 1 << 0;
2080 const TONEMAP_IN_SHADER = 1 << 1;
2081 const DEBAND_DITHER = 1 << 2;
2082 const DEPTH_PREPASS = 1 << 3;
2083 const NORMAL_PREPASS = 1 << 4;
2084 const DEFERRED_PREPASS = 1 << 5;
2085 const MOTION_VECTOR_PREPASS = 1 << 6;
2086 const MAY_DISCARD = 1 << 7; const ENVIRONMENT_MAP = 1 << 8;
2089 const SCREEN_SPACE_AMBIENT_OCCLUSION = 1 << 9;
2090 const UNCLIPPED_DEPTH_ORTHO = 1 << 10; const TEMPORAL_JITTER = 1 << 11;
2094 const READS_VIEW_TRANSMISSION_TEXTURE = 1 << 12;
2095 const LIGHTMAPPED = 1 << 13;
2096 const LIGHTMAP_BICUBIC_SAMPLING = 1 << 14;
2097 const IRRADIANCE_VOLUME = 1 << 15;
2098 const VISIBILITY_RANGE_DITHER = 1 << 16;
2099 const SCREEN_SPACE_REFLECTIONS = 1 << 17;
2100 const HAS_PREVIOUS_SKIN = 1 << 18;
2101 const HAS_PREVIOUS_MORPH = 1 << 19;
2102 const OIT_ENABLED = 1 << 20;
2103 const DISTANCE_FOG = 1 << 21;
2104 const LAST_FLAG = Self::DISTANCE_FOG.bits();
2105
2106 const MSAA_RESERVED_BITS = Self::MSAA_MASK_BITS << Self::MSAA_SHIFT_BITS;
2108 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;
2115 const TONEMAP_METHOD_NONE = 0 << Self::TONEMAP_METHOD_SHIFT_BITS;
2116 const TONEMAP_METHOD_REINHARD = 1 << Self::TONEMAP_METHOD_SHIFT_BITS;
2117 const TONEMAP_METHOD_REINHARD_LUMINANCE = 2 << Self::TONEMAP_METHOD_SHIFT_BITS;
2118 const TONEMAP_METHOD_ACES_FITTED = 3 << Self::TONEMAP_METHOD_SHIFT_BITS;
2119 const TONEMAP_METHOD_AGX = 4 << Self::TONEMAP_METHOD_SHIFT_BITS;
2120 const TONEMAP_METHOD_SOMEWHAT_BORING_DISPLAY_TRANSFORM = 5 << Self::TONEMAP_METHOD_SHIFT_BITS;
2121 const TONEMAP_METHOD_TONY_MC_MAPFACE = 6 << Self::TONEMAP_METHOD_SHIFT_BITS;
2122 const TONEMAP_METHOD_BLENDER_FILMIC = 7 << Self::TONEMAP_METHOD_SHIFT_BITS;
2123 const SHADOW_FILTER_METHOD_RESERVED_BITS = Self::SHADOW_FILTER_METHOD_MASK_BITS << Self::SHADOW_FILTER_METHOD_SHIFT_BITS;
2124 const SHADOW_FILTER_METHOD_HARDWARE_2X2 = 0 << Self::SHADOW_FILTER_METHOD_SHIFT_BITS;
2125 const SHADOW_FILTER_METHOD_GAUSSIAN = 1 << Self::SHADOW_FILTER_METHOD_SHIFT_BITS;
2126 const SHADOW_FILTER_METHOD_TEMPORAL = 2 << Self::SHADOW_FILTER_METHOD_SHIFT_BITS;
2127 const VIEW_PROJECTION_RESERVED_BITS = Self::VIEW_PROJECTION_MASK_BITS << Self::VIEW_PROJECTION_SHIFT_BITS;
2128 const VIEW_PROJECTION_NONSTANDARD = 0 << Self::VIEW_PROJECTION_SHIFT_BITS;
2129 const VIEW_PROJECTION_PERSPECTIVE = 1 << Self::VIEW_PROJECTION_SHIFT_BITS;
2130 const VIEW_PROJECTION_ORTHOGRAPHIC = 2 << Self::VIEW_PROJECTION_SHIFT_BITS;
2131 const VIEW_PROJECTION_RESERVED = 3 << Self::VIEW_PROJECTION_SHIFT_BITS;
2132 const SCREEN_SPACE_SPECULAR_TRANSMISSION_RESERVED_BITS = Self::SCREEN_SPACE_SPECULAR_TRANSMISSION_MASK_BITS << Self::SCREEN_SPACE_SPECULAR_TRANSMISSION_SHIFT_BITS;
2133 const SCREEN_SPACE_SPECULAR_TRANSMISSION_LOW = 0 << Self::SCREEN_SPACE_SPECULAR_TRANSMISSION_SHIFT_BITS;
2134 const SCREEN_SPACE_SPECULAR_TRANSMISSION_MEDIUM = 1 << Self::SCREEN_SPACE_SPECULAR_TRANSMISSION_SHIFT_BITS;
2135 const SCREEN_SPACE_SPECULAR_TRANSMISSION_HIGH = 2 << Self::SCREEN_SPACE_SPECULAR_TRANSMISSION_SHIFT_BITS;
2136 const SCREEN_SPACE_SPECULAR_TRANSMISSION_ULTRA = 3 << Self::SCREEN_SPACE_SPECULAR_TRANSMISSION_SHIFT_BITS;
2137 const ALL_RESERVED_BITS =
2138 Self::BLEND_RESERVED_BITS.bits() |
2139 Self::MSAA_RESERVED_BITS.bits() |
2140 Self::TONEMAP_METHOD_RESERVED_BITS.bits() |
2141 Self::SHADOW_FILTER_METHOD_RESERVED_BITS.bits() |
2142 Self::VIEW_PROJECTION_RESERVED_BITS.bits() |
2143 Self::SCREEN_SPACE_SPECULAR_TRANSMISSION_RESERVED_BITS.bits();
2144 }
2145}
2146
2147impl MeshPipelineKey {
2148 const MSAA_MASK_BITS: u64 = 0b111;
2149 const MSAA_SHIFT_BITS: u64 = Self::LAST_FLAG.bits().trailing_zeros() as u64 + 1;
2150
2151 const BLEND_MASK_BITS: u64 = 0b111;
2152 const BLEND_SHIFT_BITS: u64 = Self::MSAA_MASK_BITS.count_ones() as u64 + Self::MSAA_SHIFT_BITS;
2153
2154 const TONEMAP_METHOD_MASK_BITS: u64 = 0b111;
2155 const TONEMAP_METHOD_SHIFT_BITS: u64 =
2156 Self::BLEND_MASK_BITS.count_ones() as u64 + Self::BLEND_SHIFT_BITS;
2157
2158 const SHADOW_FILTER_METHOD_MASK_BITS: u64 = 0b11;
2159 const SHADOW_FILTER_METHOD_SHIFT_BITS: u64 =
2160 Self::TONEMAP_METHOD_MASK_BITS.count_ones() as u64 + Self::TONEMAP_METHOD_SHIFT_BITS;
2161
2162 const VIEW_PROJECTION_MASK_BITS: u64 = 0b11;
2163 const VIEW_PROJECTION_SHIFT_BITS: u64 = Self::SHADOW_FILTER_METHOD_MASK_BITS.count_ones()
2164 as u64
2165 + Self::SHADOW_FILTER_METHOD_SHIFT_BITS;
2166
2167 const SCREEN_SPACE_SPECULAR_TRANSMISSION_MASK_BITS: u64 = 0b11;
2168 const SCREEN_SPACE_SPECULAR_TRANSMISSION_SHIFT_BITS: u64 =
2169 Self::VIEW_PROJECTION_MASK_BITS.count_ones() as u64 + Self::VIEW_PROJECTION_SHIFT_BITS;
2170
2171 pub fn from_msaa_samples(msaa_samples: u32) -> Self {
2172 let msaa_bits =
2173 (msaa_samples.trailing_zeros() as u64 & Self::MSAA_MASK_BITS) << Self::MSAA_SHIFT_BITS;
2174 Self::from_bits_retain(msaa_bits)
2175 }
2176
2177 pub fn from_hdr(hdr: bool) -> Self {
2178 if hdr {
2179 MeshPipelineKey::HDR
2180 } else {
2181 MeshPipelineKey::NONE
2182 }
2183 }
2184
2185 pub fn msaa_samples(&self) -> u32 {
2186 1 << ((self.bits() >> Self::MSAA_SHIFT_BITS) & Self::MSAA_MASK_BITS)
2187 }
2188
2189 pub fn from_primitive_topology(primitive_topology: PrimitiveTopology) -> Self {
2190 let primitive_topology_bits = ((primitive_topology as u64)
2191 & BaseMeshPipelineKey::PRIMITIVE_TOPOLOGY_MASK_BITS)
2192 << BaseMeshPipelineKey::PRIMITIVE_TOPOLOGY_SHIFT_BITS;
2193 Self::from_bits_retain(primitive_topology_bits)
2194 }
2195
2196 pub fn primitive_topology(&self) -> PrimitiveTopology {
2197 let primitive_topology_bits = (self.bits()
2198 >> BaseMeshPipelineKey::PRIMITIVE_TOPOLOGY_SHIFT_BITS)
2199 & BaseMeshPipelineKey::PRIMITIVE_TOPOLOGY_MASK_BITS;
2200 match primitive_topology_bits {
2201 x if x == PrimitiveTopology::PointList as u64 => PrimitiveTopology::PointList,
2202 x if x == PrimitiveTopology::LineList as u64 => PrimitiveTopology::LineList,
2203 x if x == PrimitiveTopology::LineStrip as u64 => PrimitiveTopology::LineStrip,
2204 x if x == PrimitiveTopology::TriangleList as u64 => PrimitiveTopology::TriangleList,
2205 x if x == PrimitiveTopology::TriangleStrip as u64 => PrimitiveTopology::TriangleStrip,
2206 _ => PrimitiveTopology::default(),
2207 }
2208 }
2209}
2210
2211const_assert_eq!(
2213 (((MeshPipelineKey::LAST_FLAG.bits() << 1) - 1) | MeshPipelineKey::ALL_RESERVED_BITS.bits())
2214 & BaseMeshPipelineKey::all().bits(),
2215 0
2216);
2217
2218const_assert_eq!(
2220 (BaseMeshPipelineKey::PRIMITIVE_TOPOLOGY_MASK_BITS
2221 << BaseMeshPipelineKey::PRIMITIVE_TOPOLOGY_SHIFT_BITS)
2222 & MeshPipelineKey::ALL_RESERVED_BITS.bits(),
2223 0
2224);
2225
2226fn is_skinned(layout: &MeshVertexBufferLayoutRef) -> bool {
2227 layout.0.contains(Mesh::ATTRIBUTE_JOINT_INDEX)
2228 && layout.0.contains(Mesh::ATTRIBUTE_JOINT_WEIGHT)
2229}
2230pub fn setup_morph_and_skinning_defs(
2231 mesh_layouts: &MeshLayouts,
2232 layout: &MeshVertexBufferLayoutRef,
2233 offset: u32,
2234 key: &MeshPipelineKey,
2235 shader_defs: &mut Vec<ShaderDefVal>,
2236 vertex_attributes: &mut Vec<VertexAttributeDescriptor>,
2237 skins_use_uniform_buffers: bool,
2238) -> BindGroupLayout {
2239 let is_morphed = key.intersects(MeshPipelineKey::MORPH_TARGETS);
2240 let is_lightmapped = key.intersects(MeshPipelineKey::LIGHTMAPPED);
2241 let motion_vector_prepass = key.intersects(MeshPipelineKey::MOTION_VECTOR_PREPASS);
2242
2243 if skins_use_uniform_buffers {
2244 shader_defs.push("SKINS_USE_UNIFORM_BUFFERS".into());
2245 }
2246
2247 let mut add_skin_data = || {
2248 shader_defs.push("SKINNED".into());
2249 vertex_attributes.push(Mesh::ATTRIBUTE_JOINT_INDEX.at_shader_location(offset));
2250 vertex_attributes.push(Mesh::ATTRIBUTE_JOINT_WEIGHT.at_shader_location(offset + 1));
2251 };
2252
2253 match (
2254 is_skinned(layout),
2255 is_morphed,
2256 is_lightmapped,
2257 motion_vector_prepass,
2258 ) {
2259 (true, false, _, true) => {
2260 add_skin_data();
2261 mesh_layouts.skinned_motion.clone()
2262 }
2263 (true, false, _, false) => {
2264 add_skin_data();
2265 mesh_layouts.skinned.clone()
2266 }
2267 (true, true, _, true) => {
2268 add_skin_data();
2269 shader_defs.push("MORPH_TARGETS".into());
2270 mesh_layouts.morphed_skinned_motion.clone()
2271 }
2272 (true, true, _, false) => {
2273 add_skin_data();
2274 shader_defs.push("MORPH_TARGETS".into());
2275 mesh_layouts.morphed_skinned.clone()
2276 }
2277 (false, true, _, true) => {
2278 shader_defs.push("MORPH_TARGETS".into());
2279 mesh_layouts.morphed_motion.clone()
2280 }
2281 (false, true, _, false) => {
2282 shader_defs.push("MORPH_TARGETS".into());
2283 mesh_layouts.morphed.clone()
2284 }
2285 (false, false, true, _) => mesh_layouts.lightmapped.clone(),
2286 (false, false, false, _) => mesh_layouts.model_only.clone(),
2287 }
2288}
2289
2290impl SpecializedMeshPipeline for MeshPipeline {
2291 type Key = MeshPipelineKey;
2292
2293 fn specialize(
2294 &self,
2295 key: Self::Key,
2296 layout: &MeshVertexBufferLayoutRef,
2297 ) -> Result<RenderPipelineDescriptor, SpecializedMeshPipelineError> {
2298 let mut shader_defs = Vec::new();
2299 let mut vertex_attributes = Vec::new();
2300
2301 shader_defs.push("MESH_PIPELINE".into());
2303
2304 shader_defs.push("VERTEX_OUTPUT_INSTANCE_INDEX".into());
2305
2306 if layout.0.contains(Mesh::ATTRIBUTE_POSITION) {
2307 shader_defs.push("VERTEX_POSITIONS".into());
2308 vertex_attributes.push(Mesh::ATTRIBUTE_POSITION.at_shader_location(0));
2309 }
2310
2311 if layout.0.contains(Mesh::ATTRIBUTE_NORMAL) {
2312 shader_defs.push("VERTEX_NORMALS".into());
2313 vertex_attributes.push(Mesh::ATTRIBUTE_NORMAL.at_shader_location(1));
2314 }
2315
2316 if layout.0.contains(Mesh::ATTRIBUTE_UV_0) {
2317 shader_defs.push("VERTEX_UVS".into());
2318 shader_defs.push("VERTEX_UVS_A".into());
2319 vertex_attributes.push(Mesh::ATTRIBUTE_UV_0.at_shader_location(2));
2320 }
2321
2322 if layout.0.contains(Mesh::ATTRIBUTE_UV_1) {
2323 shader_defs.push("VERTEX_UVS".into());
2324 shader_defs.push("VERTEX_UVS_B".into());
2325 vertex_attributes.push(Mesh::ATTRIBUTE_UV_1.at_shader_location(3));
2326 }
2327
2328 if layout.0.contains(Mesh::ATTRIBUTE_TANGENT) {
2329 shader_defs.push("VERTEX_TANGENTS".into());
2330 vertex_attributes.push(Mesh::ATTRIBUTE_TANGENT.at_shader_location(4));
2331 }
2332
2333 if layout.0.contains(Mesh::ATTRIBUTE_COLOR) {
2334 shader_defs.push("VERTEX_COLORS".into());
2335 vertex_attributes.push(Mesh::ATTRIBUTE_COLOR.at_shader_location(5));
2336 }
2337
2338 if cfg!(feature = "pbr_transmission_textures") {
2339 shader_defs.push("PBR_TRANSMISSION_TEXTURES_SUPPORTED".into());
2340 }
2341 if cfg!(feature = "pbr_multi_layer_material_textures") {
2342 shader_defs.push("PBR_MULTI_LAYER_MATERIAL_TEXTURES_SUPPORTED".into());
2343 }
2344 if cfg!(feature = "pbr_anisotropy_texture") {
2345 shader_defs.push("PBR_ANISOTROPY_TEXTURE_SUPPORTED".into());
2346 }
2347 if cfg!(feature = "pbr_specular_textures") {
2348 shader_defs.push("PBR_SPECULAR_TEXTURES_SUPPORTED".into());
2349 }
2350
2351 let mut bind_group_layout = vec![self.get_view_layout(key.into()).clone()];
2352
2353 if key.msaa_samples() > 1 {
2354 shader_defs.push("MULTISAMPLED".into());
2355 };
2356
2357 bind_group_layout.push(setup_morph_and_skinning_defs(
2358 &self.mesh_layouts,
2359 layout,
2360 6,
2361 &key,
2362 &mut shader_defs,
2363 &mut vertex_attributes,
2364 self.skins_use_uniform_buffers,
2365 ));
2366
2367 if key.contains(MeshPipelineKey::SCREEN_SPACE_AMBIENT_OCCLUSION) {
2368 shader_defs.push("SCREEN_SPACE_AMBIENT_OCCLUSION".into());
2369 }
2370
2371 let vertex_buffer_layout = layout.0.get_layout(&vertex_attributes)?;
2372
2373 let (label, blend, depth_write_enabled);
2374 let pass = key.intersection(MeshPipelineKey::BLEND_RESERVED_BITS);
2375 let (mut is_opaque, mut alpha_to_coverage_enabled) = (false, false);
2376 if key.contains(MeshPipelineKey::OIT_ENABLED) && pass == MeshPipelineKey::BLEND_ALPHA {
2377 label = "oit_mesh_pipeline".into();
2378 blend = None;
2380 shader_defs.push("OIT_ENABLED".into());
2381 depth_write_enabled = false;
2384 } else if pass == MeshPipelineKey::BLEND_ALPHA {
2385 label = "alpha_blend_mesh_pipeline".into();
2386 blend = Some(BlendState::ALPHA_BLENDING);
2387 depth_write_enabled = false;
2390 } else if pass == MeshPipelineKey::BLEND_PREMULTIPLIED_ALPHA {
2391 label = "premultiplied_alpha_mesh_pipeline".into();
2392 blend = Some(BlendState::PREMULTIPLIED_ALPHA_BLENDING);
2393 shader_defs.push("PREMULTIPLY_ALPHA".into());
2394 shader_defs.push("BLEND_PREMULTIPLIED_ALPHA".into());
2395 depth_write_enabled = false;
2398 } else if pass == MeshPipelineKey::BLEND_MULTIPLY {
2399 label = "multiply_mesh_pipeline".into();
2400 blend = Some(BlendState {
2401 color: BlendComponent {
2402 src_factor: BlendFactor::Dst,
2403 dst_factor: BlendFactor::OneMinusSrcAlpha,
2404 operation: BlendOperation::Add,
2405 },
2406 alpha: BlendComponent::OVER,
2407 });
2408 shader_defs.push("PREMULTIPLY_ALPHA".into());
2409 shader_defs.push("BLEND_MULTIPLY".into());
2410 depth_write_enabled = false;
2413 } else if pass == MeshPipelineKey::BLEND_ALPHA_TO_COVERAGE {
2414 label = "alpha_to_coverage_mesh_pipeline".into();
2415 blend = None;
2417 depth_write_enabled = true;
2421 is_opaque = !key.contains(MeshPipelineKey::READS_VIEW_TRANSMISSION_TEXTURE);
2422 alpha_to_coverage_enabled = true;
2423 shader_defs.push("ALPHA_TO_COVERAGE".into());
2424 } else {
2425 label = "opaque_mesh_pipeline".into();
2426 blend = None;
2428 depth_write_enabled = true;
2432 is_opaque = !key.contains(MeshPipelineKey::READS_VIEW_TRANSMISSION_TEXTURE);
2433 }
2434
2435 if key.contains(MeshPipelineKey::NORMAL_PREPASS) {
2436 shader_defs.push("NORMAL_PREPASS".into());
2437 }
2438
2439 if key.contains(MeshPipelineKey::DEPTH_PREPASS) {
2440 shader_defs.push("DEPTH_PREPASS".into());
2441 }
2442
2443 if key.contains(MeshPipelineKey::MOTION_VECTOR_PREPASS) {
2444 shader_defs.push("MOTION_VECTOR_PREPASS".into());
2445 }
2446
2447 if key.contains(MeshPipelineKey::HAS_PREVIOUS_SKIN) {
2448 shader_defs.push("HAS_PREVIOUS_SKIN".into());
2449 }
2450
2451 if key.contains(MeshPipelineKey::HAS_PREVIOUS_MORPH) {
2452 shader_defs.push("HAS_PREVIOUS_MORPH".into());
2453 }
2454
2455 if key.contains(MeshPipelineKey::DEFERRED_PREPASS) {
2456 shader_defs.push("DEFERRED_PREPASS".into());
2457 }
2458
2459 if key.contains(MeshPipelineKey::NORMAL_PREPASS) && key.msaa_samples() == 1 && is_opaque {
2460 shader_defs.push("LOAD_PREPASS_NORMALS".into());
2461 }
2462
2463 let view_projection = key.intersection(MeshPipelineKey::VIEW_PROJECTION_RESERVED_BITS);
2464 if view_projection == MeshPipelineKey::VIEW_PROJECTION_NONSTANDARD {
2465 shader_defs.push("VIEW_PROJECTION_NONSTANDARD".into());
2466 } else if view_projection == MeshPipelineKey::VIEW_PROJECTION_PERSPECTIVE {
2467 shader_defs.push("VIEW_PROJECTION_PERSPECTIVE".into());
2468 } else if view_projection == MeshPipelineKey::VIEW_PROJECTION_ORTHOGRAPHIC {
2469 shader_defs.push("VIEW_PROJECTION_ORTHOGRAPHIC".into());
2470 }
2471
2472 #[cfg(all(feature = "webgl", target_arch = "wasm32", not(feature = "webgpu")))]
2473 shader_defs.push("WEBGL2".into());
2474
2475 #[cfg(feature = "experimental_pbr_pcss")]
2476 shader_defs.push("PCSS_SAMPLERS_AVAILABLE".into());
2477
2478 if key.contains(MeshPipelineKey::TONEMAP_IN_SHADER) {
2479 shader_defs.push("TONEMAP_IN_SHADER".into());
2480 shader_defs.push(ShaderDefVal::UInt(
2481 "TONEMAPPING_LUT_TEXTURE_BINDING_INDEX".into(),
2482 TONEMAPPING_LUT_TEXTURE_BINDING_INDEX,
2483 ));
2484 shader_defs.push(ShaderDefVal::UInt(
2485 "TONEMAPPING_LUT_SAMPLER_BINDING_INDEX".into(),
2486 TONEMAPPING_LUT_SAMPLER_BINDING_INDEX,
2487 ));
2488
2489 let method = key.intersection(MeshPipelineKey::TONEMAP_METHOD_RESERVED_BITS);
2490
2491 if method == MeshPipelineKey::TONEMAP_METHOD_NONE {
2492 shader_defs.push("TONEMAP_METHOD_NONE".into());
2493 } else if method == MeshPipelineKey::TONEMAP_METHOD_REINHARD {
2494 shader_defs.push("TONEMAP_METHOD_REINHARD".into());
2495 } else if method == MeshPipelineKey::TONEMAP_METHOD_REINHARD_LUMINANCE {
2496 shader_defs.push("TONEMAP_METHOD_REINHARD_LUMINANCE".into());
2497 } else if method == MeshPipelineKey::TONEMAP_METHOD_ACES_FITTED {
2498 shader_defs.push("TONEMAP_METHOD_ACES_FITTED".into());
2499 } else if method == MeshPipelineKey::TONEMAP_METHOD_AGX {
2500 shader_defs.push("TONEMAP_METHOD_AGX".into());
2501 } else if method == MeshPipelineKey::TONEMAP_METHOD_SOMEWHAT_BORING_DISPLAY_TRANSFORM {
2502 shader_defs.push("TONEMAP_METHOD_SOMEWHAT_BORING_DISPLAY_TRANSFORM".into());
2503 } else if method == MeshPipelineKey::TONEMAP_METHOD_BLENDER_FILMIC {
2504 shader_defs.push("TONEMAP_METHOD_BLENDER_FILMIC".into());
2505 } else if method == MeshPipelineKey::TONEMAP_METHOD_TONY_MC_MAPFACE {
2506 shader_defs.push("TONEMAP_METHOD_TONY_MC_MAPFACE".into());
2507 }
2508
2509 if key.contains(MeshPipelineKey::DEBAND_DITHER) {
2511 shader_defs.push("DEBAND_DITHER".into());
2512 }
2513 }
2514
2515 if key.contains(MeshPipelineKey::MAY_DISCARD) {
2516 shader_defs.push("MAY_DISCARD".into());
2517 }
2518
2519 if key.contains(MeshPipelineKey::ENVIRONMENT_MAP) {
2520 shader_defs.push("ENVIRONMENT_MAP".into());
2521 }
2522
2523 if key.contains(MeshPipelineKey::IRRADIANCE_VOLUME) && IRRADIANCE_VOLUMES_ARE_USABLE {
2524 shader_defs.push("IRRADIANCE_VOLUME".into());
2525 }
2526
2527 if key.contains(MeshPipelineKey::LIGHTMAPPED) {
2528 shader_defs.push("LIGHTMAP".into());
2529 }
2530 if key.contains(MeshPipelineKey::LIGHTMAP_BICUBIC_SAMPLING) {
2531 shader_defs.push("LIGHTMAP_BICUBIC_SAMPLING".into());
2532 }
2533
2534 if key.contains(MeshPipelineKey::TEMPORAL_JITTER) {
2535 shader_defs.push("TEMPORAL_JITTER".into());
2536 }
2537
2538 let shadow_filter_method =
2539 key.intersection(MeshPipelineKey::SHADOW_FILTER_METHOD_RESERVED_BITS);
2540 if shadow_filter_method == MeshPipelineKey::SHADOW_FILTER_METHOD_HARDWARE_2X2 {
2541 shader_defs.push("SHADOW_FILTER_METHOD_HARDWARE_2X2".into());
2542 } else if shadow_filter_method == MeshPipelineKey::SHADOW_FILTER_METHOD_GAUSSIAN {
2543 shader_defs.push("SHADOW_FILTER_METHOD_GAUSSIAN".into());
2544 } else if shadow_filter_method == MeshPipelineKey::SHADOW_FILTER_METHOD_TEMPORAL {
2545 shader_defs.push("SHADOW_FILTER_METHOD_TEMPORAL".into());
2546 }
2547
2548 let blur_quality =
2549 key.intersection(MeshPipelineKey::SCREEN_SPACE_SPECULAR_TRANSMISSION_RESERVED_BITS);
2550
2551 shader_defs.push(ShaderDefVal::Int(
2552 "SCREEN_SPACE_SPECULAR_TRANSMISSION_BLUR_TAPS".into(),
2553 match blur_quality {
2554 MeshPipelineKey::SCREEN_SPACE_SPECULAR_TRANSMISSION_LOW => 4,
2555 MeshPipelineKey::SCREEN_SPACE_SPECULAR_TRANSMISSION_MEDIUM => 8,
2556 MeshPipelineKey::SCREEN_SPACE_SPECULAR_TRANSMISSION_HIGH => 16,
2557 MeshPipelineKey::SCREEN_SPACE_SPECULAR_TRANSMISSION_ULTRA => 32,
2558 _ => unreachable!(), },
2560 ));
2561
2562 if key.contains(MeshPipelineKey::VISIBILITY_RANGE_DITHER) {
2563 shader_defs.push("VISIBILITY_RANGE_DITHER".into());
2564 }
2565
2566 if key.contains(MeshPipelineKey::DISTANCE_FOG) {
2567 shader_defs.push("DISTANCE_FOG".into());
2568 }
2569
2570 if self.binding_arrays_are_usable {
2571 shader_defs.push("MULTIPLE_LIGHT_PROBES_IN_ARRAY".into());
2572 shader_defs.push("MULTIPLE_LIGHTMAPS_IN_ARRAY".into());
2573 }
2574
2575 if IRRADIANCE_VOLUMES_ARE_USABLE {
2576 shader_defs.push("IRRADIANCE_VOLUMES_ARE_USABLE".into());
2577 }
2578
2579 if self.clustered_decals_are_usable {
2580 shader_defs.push("CLUSTERED_DECALS_ARE_USABLE".into());
2581 }
2582
2583 let format = if key.contains(MeshPipelineKey::HDR) {
2584 ViewTarget::TEXTURE_FORMAT_HDR
2585 } else {
2586 TextureFormat::bevy_default()
2587 };
2588
2589 if let Some(per_object_buffer_batch_size) = self.per_object_buffer_batch_size {
2593 shader_defs.push(ShaderDefVal::UInt(
2594 "PER_OBJECT_BUFFER_BATCH_SIZE".into(),
2595 per_object_buffer_batch_size,
2596 ));
2597 }
2598
2599 Ok(RenderPipelineDescriptor {
2600 vertex: VertexState {
2601 shader: MESH_SHADER_HANDLE,
2602 entry_point: "vertex".into(),
2603 shader_defs: shader_defs.clone(),
2604 buffers: vec![vertex_buffer_layout],
2605 },
2606 fragment: Some(FragmentState {
2607 shader: MESH_SHADER_HANDLE,
2608 shader_defs,
2609 entry_point: "fragment".into(),
2610 targets: vec![Some(ColorTargetState {
2611 format,
2612 blend,
2613 write_mask: ColorWrites::ALL,
2614 })],
2615 }),
2616 layout: bind_group_layout,
2617 push_constant_ranges: vec![],
2618 primitive: PrimitiveState {
2619 front_face: FrontFace::Ccw,
2620 cull_mode: Some(Face::Back),
2621 unclipped_depth: false,
2622 polygon_mode: PolygonMode::Fill,
2623 conservative: false,
2624 topology: key.primitive_topology(),
2625 strip_index_format: None,
2626 },
2627 depth_stencil: Some(DepthStencilState {
2628 format: CORE_3D_DEPTH_FORMAT,
2629 depth_write_enabled,
2630 depth_compare: CompareFunction::GreaterEqual,
2631 stencil: StencilState {
2632 front: StencilFaceState::IGNORE,
2633 back: StencilFaceState::IGNORE,
2634 read_mask: 0,
2635 write_mask: 0,
2636 },
2637 bias: DepthBiasState {
2638 constant: 0,
2639 slope_scale: 0.0,
2640 clamp: 0.0,
2641 },
2642 }),
2643 multisample: MultisampleState {
2644 count: key.msaa_samples(),
2645 mask: !0,
2646 alpha_to_coverage_enabled,
2647 },
2648 label: Some(label),
2649 zero_initialize_workgroup_memory: false,
2650 })
2651 }
2652}
2653
2654#[derive(Default)]
2659pub struct MeshPhaseBindGroups {
2660 model_only: Option<BindGroup>,
2661 skinned: Option<MeshBindGroupPair>,
2662 morph_targets: HashMap<AssetId<Mesh>, MeshBindGroupPair>,
2663 lightmaps: HashMap<LightmapSlabIndex, BindGroup>,
2664}
2665
2666pub struct MeshBindGroupPair {
2667 motion_vectors: BindGroup,
2668 no_motion_vectors: BindGroup,
2669}
2670
2671#[derive(Resource)]
2673pub enum MeshBindGroups {
2674 CpuPreprocessing(MeshPhaseBindGroups),
2677 GpuPreprocessing(TypeIdMap<MeshPhaseBindGroups>),
2680}
2681
2682impl MeshPhaseBindGroups {
2683 pub fn reset(&mut self) {
2684 self.model_only = None;
2685 self.skinned = None;
2686 self.morph_targets.clear();
2687 self.lightmaps.clear();
2688 }
2689 pub fn get(
2692 &self,
2693 asset_id: AssetId<Mesh>,
2694 lightmap: Option<LightmapSlabIndex>,
2695 is_skinned: bool,
2696 morph: bool,
2697 motion_vectors: bool,
2698 ) -> Option<&BindGroup> {
2699 match (is_skinned, morph, lightmap) {
2700 (_, true, _) => self
2701 .morph_targets
2702 .get(&asset_id)
2703 .map(|bind_group_pair| bind_group_pair.get(motion_vectors)),
2704 (true, false, _) => self
2705 .skinned
2706 .as_ref()
2707 .map(|bind_group_pair| bind_group_pair.get(motion_vectors)),
2708 (false, false, Some(lightmap_slab)) => self.lightmaps.get(&lightmap_slab),
2709 (false, false, None) => self.model_only.as_ref(),
2710 }
2711 }
2712}
2713
2714impl MeshBindGroupPair {
2715 fn get(&self, motion_vectors: bool) -> &BindGroup {
2716 if motion_vectors {
2717 &self.motion_vectors
2718 } else {
2719 &self.no_motion_vectors
2720 }
2721 }
2722}
2723
2724pub fn prepare_mesh_bind_groups(
2726 mut commands: Commands,
2727 meshes: Res<RenderAssets<RenderMesh>>,
2728 mesh_pipeline: Res<MeshPipeline>,
2729 render_device: Res<RenderDevice>,
2730 cpu_batched_instance_buffer: Option<
2731 Res<no_gpu_preprocessing::BatchedInstanceBuffer<MeshUniform>>,
2732 >,
2733 gpu_batched_instance_buffers: Option<
2734 Res<gpu_preprocessing::BatchedInstanceBuffers<MeshUniform, MeshInputUniform>>,
2735 >,
2736 skins_uniform: Res<SkinUniforms>,
2737 weights_uniform: Res<MorphUniforms>,
2738 mut render_lightmaps: ResMut<RenderLightmaps>,
2739) {
2740 if let Some(cpu_batched_instance_buffer) = cpu_batched_instance_buffer {
2742 if let Some(instance_data_binding) = cpu_batched_instance_buffer
2743 .into_inner()
2744 .instance_data_binding()
2745 {
2746 let cpu_preprocessing_mesh_bind_groups = prepare_mesh_bind_groups_for_phase(
2748 instance_data_binding,
2749 &meshes,
2750 &mesh_pipeline,
2751 &render_device,
2752 &skins_uniform,
2753 &weights_uniform,
2754 &mut render_lightmaps,
2755 );
2756
2757 commands.insert_resource(MeshBindGroups::CpuPreprocessing(
2758 cpu_preprocessing_mesh_bind_groups,
2759 ));
2760 return;
2761 }
2762 }
2763
2764 if let Some(gpu_batched_instance_buffers) = gpu_batched_instance_buffers {
2766 let mut gpu_preprocessing_mesh_bind_groups = TypeIdMap::default();
2767
2768 for (phase_type_id, batched_phase_instance_buffers) in
2770 &gpu_batched_instance_buffers.phase_instance_buffers
2771 {
2772 let Some(instance_data_binding) =
2773 batched_phase_instance_buffers.instance_data_binding()
2774 else {
2775 continue;
2776 };
2777
2778 let mesh_phase_bind_groups = prepare_mesh_bind_groups_for_phase(
2779 instance_data_binding,
2780 &meshes,
2781 &mesh_pipeline,
2782 &render_device,
2783 &skins_uniform,
2784 &weights_uniform,
2785 &mut render_lightmaps,
2786 );
2787
2788 gpu_preprocessing_mesh_bind_groups.insert(*phase_type_id, mesh_phase_bind_groups);
2789 }
2790
2791 commands.insert_resource(MeshBindGroups::GpuPreprocessing(
2792 gpu_preprocessing_mesh_bind_groups,
2793 ));
2794 }
2795}
2796
2797fn prepare_mesh_bind_groups_for_phase(
2799 model: BindingResource,
2800 meshes: &RenderAssets<RenderMesh>,
2801 mesh_pipeline: &MeshPipeline,
2802 render_device: &RenderDevice,
2803 skins_uniform: &SkinUniforms,
2804 weights_uniform: &MorphUniforms,
2805 render_lightmaps: &mut RenderLightmaps,
2806) -> MeshPhaseBindGroups {
2807 let layouts = &mesh_pipeline.mesh_layouts;
2808
2809 let mut groups = MeshPhaseBindGroups {
2811 model_only: Some(layouts.model_only(render_device, &model)),
2812 ..default()
2813 };
2814
2815 let (skin, prev_skin) = (&skins_uniform.current_buffer, &skins_uniform.prev_buffer);
2818 groups.skinned = Some(MeshBindGroupPair {
2819 motion_vectors: layouts.skinned_motion(render_device, &model, skin, prev_skin),
2820 no_motion_vectors: layouts.skinned(render_device, &model, skin),
2821 });
2822
2823 if let Some(weights) = weights_uniform.current_buffer.buffer() {
2826 let prev_weights = weights_uniform.prev_buffer.buffer().unwrap_or(weights);
2827 for (id, gpu_mesh) in meshes.iter() {
2828 if let Some(targets) = gpu_mesh.morph_targets.as_ref() {
2829 let bind_group_pair = if is_skinned(&gpu_mesh.layout) {
2830 let prev_skin = &skins_uniform.prev_buffer;
2831 MeshBindGroupPair {
2832 motion_vectors: layouts.morphed_skinned_motion(
2833 render_device,
2834 &model,
2835 skin,
2836 weights,
2837 targets,
2838 prev_skin,
2839 prev_weights,
2840 ),
2841 no_motion_vectors: layouts.morphed_skinned(
2842 render_device,
2843 &model,
2844 skin,
2845 weights,
2846 targets,
2847 ),
2848 }
2849 } else {
2850 MeshBindGroupPair {
2851 motion_vectors: layouts.morphed_motion(
2852 render_device,
2853 &model,
2854 weights,
2855 targets,
2856 prev_weights,
2857 ),
2858 no_motion_vectors: layouts.morphed(render_device, &model, weights, targets),
2859 }
2860 };
2861 groups.morph_targets.insert(id, bind_group_pair);
2862 }
2863 }
2864 }
2865
2866 let bindless_supported = render_lightmaps.bindless_supported;
2868 for (lightmap_slab_id, lightmap_slab) in render_lightmaps.slabs.iter_mut().enumerate() {
2869 groups.lightmaps.insert(
2870 LightmapSlabIndex(NonMaxU32::new(lightmap_slab_id as u32).unwrap()),
2871 layouts.lightmapped(render_device, &model, lightmap_slab, bindless_supported),
2872 );
2873 }
2874
2875 groups
2876}
2877
2878pub struct SetMeshViewBindGroup<const I: usize>;
2879impl<P: PhaseItem, const I: usize> RenderCommand<P> for SetMeshViewBindGroup<I> {
2880 type Param = ();
2881 type ViewQuery = (
2882 Read<ViewUniformOffset>,
2883 Read<ViewLightsUniformOffset>,
2884 Read<ViewFogUniformOffset>,
2885 Read<ViewLightProbesUniformOffset>,
2886 Read<ViewScreenSpaceReflectionsUniformOffset>,
2887 Read<ViewEnvironmentMapUniformOffset>,
2888 Read<MeshViewBindGroup>,
2889 Option<Read<OrderIndependentTransparencySettingsOffset>>,
2890 );
2891 type ItemQuery = ();
2892
2893 #[inline]
2894 fn render<'w>(
2895 _item: &P,
2896 (
2897 view_uniform,
2898 view_lights,
2899 view_fog,
2900 view_light_probes,
2901 view_ssr,
2902 view_environment_map,
2903 mesh_view_bind_group,
2904 maybe_oit_layers_count_offset,
2905 ): ROQueryItem<'w, Self::ViewQuery>,
2906 _entity: Option<()>,
2907 _: SystemParamItem<'w, '_, Self::Param>,
2908 pass: &mut TrackedRenderPass<'w>,
2909 ) -> RenderCommandResult {
2910 let mut offsets: SmallVec<[u32; 8]> = smallvec![
2911 view_uniform.offset,
2912 view_lights.offset,
2913 view_fog.offset,
2914 **view_light_probes,
2915 **view_ssr,
2916 **view_environment_map,
2917 ];
2918 if let Some(layers_count_offset) = maybe_oit_layers_count_offset {
2919 offsets.push(layers_count_offset.offset);
2920 }
2921 pass.set_bind_group(I, &mesh_view_bind_group.value, &offsets);
2922
2923 RenderCommandResult::Success
2924 }
2925}
2926
2927pub struct SetMeshBindGroup<const I: usize>;
2928impl<P: PhaseItem, const I: usize> RenderCommand<P> for SetMeshBindGroup<I> {
2929 type Param = (
2930 SRes<RenderDevice>,
2931 SRes<MeshBindGroups>,
2932 SRes<RenderMeshInstances>,
2933 SRes<SkinUniforms>,
2934 SRes<MorphIndices>,
2935 SRes<RenderLightmaps>,
2936 );
2937 type ViewQuery = Has<MotionVectorPrepass>;
2938 type ItemQuery = ();
2939
2940 #[inline]
2941 fn render<'w>(
2942 item: &P,
2943 has_motion_vector_prepass: bool,
2944 _item_query: Option<()>,
2945 (
2946 render_device,
2947 bind_groups,
2948 mesh_instances,
2949 skin_uniforms,
2950 morph_indices,
2951 lightmaps,
2952 ): SystemParamItem<'w, '_, Self::Param>,
2953 pass: &mut TrackedRenderPass<'w>,
2954 ) -> RenderCommandResult {
2955 let bind_groups = bind_groups.into_inner();
2956 let mesh_instances = mesh_instances.into_inner();
2957 let skin_uniforms = skin_uniforms.into_inner();
2958 let morph_indices = morph_indices.into_inner();
2959
2960 let entity = &item.main_entity();
2961
2962 let Some(mesh_asset_id) = mesh_instances.mesh_asset_id(*entity) else {
2963 return RenderCommandResult::Success;
2964 };
2965
2966 let current_skin_byte_offset = skin_uniforms.skin_byte_offset(*entity);
2967 let current_morph_index = morph_indices.current.get(entity);
2968 let prev_morph_index = morph_indices.prev.get(entity);
2969
2970 let is_skinned = current_skin_byte_offset.is_some();
2971 let is_morphed = current_morph_index.is_some();
2972
2973 let lightmap_slab_index = lightmaps
2974 .render_lightmaps
2975 .get(entity)
2976 .map(|render_lightmap| render_lightmap.slab_index);
2977
2978 let Some(mesh_phase_bind_groups) = (match *bind_groups {
2979 MeshBindGroups::CpuPreprocessing(ref mesh_phase_bind_groups) => {
2980 Some(mesh_phase_bind_groups)
2981 }
2982 MeshBindGroups::GpuPreprocessing(ref mesh_phase_bind_groups) => {
2983 mesh_phase_bind_groups.get(&TypeId::of::<P>())
2984 }
2985 }) else {
2986 return RenderCommandResult::Success;
2989 };
2990
2991 let Some(bind_group) = mesh_phase_bind_groups.get(
2992 mesh_asset_id,
2993 lightmap_slab_index,
2994 is_skinned,
2995 is_morphed,
2996 has_motion_vector_prepass,
2997 ) else {
2998 return RenderCommandResult::Failure(
2999 "The MeshBindGroups resource wasn't set in the render phase. \
3000 It should be set by the prepare_mesh_bind_group system.\n\
3001 This is a bevy bug! Please open an issue.",
3002 );
3003 };
3004
3005 let mut dynamic_offsets: [u32; 3] = Default::default();
3006 let mut offset_count = 0;
3007 if let PhaseItemExtraIndex::DynamicOffset(dynamic_offset) = item.extra_index() {
3008 dynamic_offsets[offset_count] = dynamic_offset;
3009 offset_count += 1;
3010 }
3011 if let Some(current_skin_index) = current_skin_byte_offset {
3012 if skins_use_uniform_buffers(&render_device) {
3013 dynamic_offsets[offset_count] = current_skin_index.byte_offset;
3014 offset_count += 1;
3015 }
3016 }
3017 if let Some(current_morph_index) = current_morph_index {
3018 dynamic_offsets[offset_count] = current_morph_index.index;
3019 offset_count += 1;
3020 }
3021
3022 if has_motion_vector_prepass {
3024 if skins_use_uniform_buffers(&render_device) {
3026 if let Some(current_skin_byte_offset) = current_skin_byte_offset {
3027 dynamic_offsets[offset_count] = current_skin_byte_offset.byte_offset;
3028 offset_count += 1;
3029 }
3030 }
3031
3032 if current_morph_index.is_some() {
3035 match prev_morph_index {
3036 Some(prev_morph_index) => {
3037 dynamic_offsets[offset_count] = prev_morph_index.index;
3038 }
3039 None => dynamic_offsets[offset_count] = 0,
3040 }
3041 offset_count += 1;
3042 }
3043 }
3044
3045 pass.set_bind_group(I, bind_group, &dynamic_offsets[0..offset_count]);
3046
3047 RenderCommandResult::Success
3048 }
3049}
3050
3051pub struct DrawMesh;
3052impl<P: PhaseItem> RenderCommand<P> for DrawMesh {
3053 type Param = (
3054 SRes<RenderAssets<RenderMesh>>,
3055 SRes<RenderMeshInstances>,
3056 SRes<IndirectParametersBuffers>,
3057 SRes<PipelineCache>,
3058 SRes<MeshAllocator>,
3059 Option<SRes<PreprocessPipelines>>,
3060 SRes<GpuPreprocessingSupport>,
3061 );
3062 type ViewQuery = Has<PreprocessBindGroups>;
3063 type ItemQuery = ();
3064 #[inline]
3065 fn render<'w>(
3066 item: &P,
3067 has_preprocess_bind_group: ROQueryItem<Self::ViewQuery>,
3068 _item_query: Option<()>,
3069 (
3070 meshes,
3071 mesh_instances,
3072 indirect_parameters_buffer,
3073 pipeline_cache,
3074 mesh_allocator,
3075 preprocess_pipelines,
3076 preprocessing_support,
3077 ): SystemParamItem<'w, '_, Self::Param>,
3078 pass: &mut TrackedRenderPass<'w>,
3079 ) -> RenderCommandResult {
3080 if let Some(preprocess_pipelines) = preprocess_pipelines {
3084 if !has_preprocess_bind_group
3085 || !preprocess_pipelines
3086 .pipelines_are_loaded(&pipeline_cache, &preprocessing_support)
3087 {
3088 return RenderCommandResult::Skip;
3089 }
3090 }
3091
3092 let meshes = meshes.into_inner();
3093 let mesh_instances = mesh_instances.into_inner();
3094 let indirect_parameters_buffer = indirect_parameters_buffer.into_inner();
3095 let mesh_allocator = mesh_allocator.into_inner();
3096
3097 let Some(mesh_asset_id) = mesh_instances.mesh_asset_id(item.main_entity()) else {
3098 return RenderCommandResult::Skip;
3099 };
3100 let Some(gpu_mesh) = meshes.get(mesh_asset_id) else {
3101 return RenderCommandResult::Skip;
3102 };
3103 let Some(vertex_buffer_slice) = mesh_allocator.mesh_vertex_slice(&mesh_asset_id) else {
3104 return RenderCommandResult::Skip;
3105 };
3106
3107 pass.set_vertex_buffer(0, vertex_buffer_slice.buffer.slice(..));
3108
3109 let batch_range = item.batch_range();
3110
3111 match &gpu_mesh.buffer_info {
3115 RenderMeshBufferInfo::Indexed {
3116 index_format,
3117 count,
3118 } => {
3119 let Some(index_buffer_slice) = mesh_allocator.mesh_index_slice(&mesh_asset_id)
3120 else {
3121 return RenderCommandResult::Skip;
3122 };
3123
3124 pass.set_index_buffer(index_buffer_slice.buffer.slice(..), 0, *index_format);
3125
3126 match item.extra_index() {
3127 PhaseItemExtraIndex::None | PhaseItemExtraIndex::DynamicOffset(_) => {
3128 pass.draw_indexed(
3129 index_buffer_slice.range.start
3130 ..(index_buffer_slice.range.start + *count),
3131 vertex_buffer_slice.range.start as i32,
3132 batch_range.clone(),
3133 );
3134 }
3135 PhaseItemExtraIndex::IndirectParametersIndex {
3136 range: indirect_parameters_range,
3137 batch_set_index,
3138 } => {
3139 let Some(phase_indirect_parameters_buffers) =
3143 indirect_parameters_buffer.get(&TypeId::of::<P>())
3144 else {
3145 warn!(
3146 "Not rendering mesh because indexed indirect parameters buffer \
3147 wasn't present for this phase",
3148 );
3149 return RenderCommandResult::Skip;
3150 };
3151 let (Some(indirect_parameters_buffer), Some(batch_sets_buffer)) = (
3152 phase_indirect_parameters_buffers.indexed.data_buffer(),
3153 phase_indirect_parameters_buffers
3154 .indexed
3155 .batch_sets_buffer(),
3156 ) else {
3157 warn!(
3158 "Not rendering mesh because indexed indirect parameters buffer \
3159 wasn't present",
3160 );
3161 return RenderCommandResult::Skip;
3162 };
3163
3164 let indirect_parameters_offset = indirect_parameters_range.start as u64
3167 * size_of::<IndirectParametersIndexed>() as u64;
3168 let indirect_parameters_count =
3169 indirect_parameters_range.end - indirect_parameters_range.start;
3170
3171 match batch_set_index {
3176 Some(batch_set_index) => {
3177 let count_offset = u32::from(batch_set_index)
3178 * (size_of::<IndirectBatchSet>() as u32);
3179 pass.multi_draw_indexed_indirect_count(
3180 indirect_parameters_buffer,
3181 indirect_parameters_offset,
3182 batch_sets_buffer,
3183 count_offset as u64,
3184 indirect_parameters_count,
3185 );
3186 }
3187 None => {
3188 pass.multi_draw_indexed_indirect(
3189 indirect_parameters_buffer,
3190 indirect_parameters_offset,
3191 indirect_parameters_count,
3192 );
3193 }
3194 }
3195 }
3196 }
3197 }
3198
3199 RenderMeshBufferInfo::NonIndexed => match item.extra_index() {
3200 PhaseItemExtraIndex::None | PhaseItemExtraIndex::DynamicOffset(_) => {
3201 pass.draw(vertex_buffer_slice.range, batch_range.clone());
3202 }
3203 PhaseItemExtraIndex::IndirectParametersIndex {
3204 range: indirect_parameters_range,
3205 batch_set_index,
3206 } => {
3207 let Some(phase_indirect_parameters_buffers) =
3211 indirect_parameters_buffer.get(&TypeId::of::<P>())
3212 else {
3213 warn!(
3214 "Not rendering mesh because non-indexed indirect parameters buffer \
3215 wasn't present for this phase",
3216 );
3217 return RenderCommandResult::Skip;
3218 };
3219 let (Some(indirect_parameters_buffer), Some(batch_sets_buffer)) = (
3220 phase_indirect_parameters_buffers.non_indexed.data_buffer(),
3221 phase_indirect_parameters_buffers
3222 .non_indexed
3223 .batch_sets_buffer(),
3224 ) else {
3225 warn!(
3226 "Not rendering mesh because non-indexed indirect parameters buffer \
3227 wasn't present"
3228 );
3229 return RenderCommandResult::Skip;
3230 };
3231
3232 let indirect_parameters_offset = indirect_parameters_range.start as u64
3235 * size_of::<IndirectParametersNonIndexed>() as u64;
3236 let indirect_parameters_count =
3237 indirect_parameters_range.end - indirect_parameters_range.start;
3238
3239 match batch_set_index {
3244 Some(batch_set_index) => {
3245 let count_offset =
3246 u32::from(batch_set_index) * (size_of::<IndirectBatchSet>() as u32);
3247 pass.multi_draw_indirect_count(
3248 indirect_parameters_buffer,
3249 indirect_parameters_offset,
3250 batch_sets_buffer,
3251 count_offset as u64,
3252 indirect_parameters_count,
3253 );
3254 }
3255 None => {
3256 pass.multi_draw_indirect(
3257 indirect_parameters_buffer,
3258 indirect_parameters_offset,
3259 indirect_parameters_count,
3260 );
3261 }
3262 }
3263 }
3264 },
3265 }
3266 RenderCommandResult::Success
3267 }
3268}
3269
3270#[cfg(test)]
3271mod tests {
3272 use super::MeshPipelineKey;
3273 #[test]
3274 fn mesh_key_msaa_samples() {
3275 for i in [1, 2, 4, 8, 16, 32, 64, 128] {
3276 assert_eq!(MeshPipelineKey::from_msaa_samples(i).msaa_samples(), i);
3277 }
3278 }
3279}