Skip to main content

bevy_pbr/render/
mesh.rs

1use crate::contact_shadows::ContactShadows;
2use crate::{resources::prepare_atmosphere_buffers, skin::skin_uniforms_from_world};
3use alloc::sync::Arc;
4use bevy_asset::uuid::Uuid;
5use bevy_asset::{embedded_asset, load_embedded_asset, AssetId, AssetIndex, AssetServer};
6use bevy_camera::visibility::NoCpuCulling;
7use bevy_camera::{
8    primitives::Aabb,
9    visibility::{NoFrustumCulling, RenderLayers, ViewVisibility, VisibilityRange},
10    Camera, Projection,
11};
12use bevy_core_pipeline::{
13    core_3d::{AlphaMask3d, Opaque3d, Transparent3d, CORE_3D_DEPTH_FORMAT},
14    deferred::{AlphaMask3dDeferred, Opaque3dDeferred},
15    oit::prepare_oit_buffers,
16    prepass::MotionVectorPrepass,
17};
18use bevy_derive::{Deref, DerefMut};
19use bevy_diagnostic::FrameCount;
20use bevy_ecs::entity::EntityHash;
21use bevy_ecs::{
22    entity::EntityHashSet,
23    prelude::*,
24    query::{QueryData, ROQueryItem},
25    relationship::RelationshipSourceCollection,
26    system::{lifetimeless::*, SystemParamItem},
27};
28use bevy_image::TextureFormatPixelInfo;
29use bevy_light::{
30    EnvironmentMapLight, IrradianceVolume, NotShadowCaster, NotShadowReceiver,
31    ShadowFilteringMethod, TransmittedShadowReceiver,
32};
33use bevy_math::{Affine3, Affine3Ext, Rect, UVec2, Vec3, Vec4};
34use bevy_mesh::{
35    skinning::SkinnedMesh, BaseMeshPipelineKey, Mesh, Mesh3d, MeshAttributeCompressionFlags,
36    MeshTag, MeshVertexBufferLayoutRef, VertexAttributeDescriptor,
37};
38use bevy_platform::collections::HashSet;
39use bevy_platform::collections::{hash_map::Entry, HashMap};
40use bevy_render::batching::gpu_preprocessing::{
41    BufferDataInput, PreviousInstanceInputUniformBuffer,
42};
43use bevy_render::impl_atomic_pod;
44use bevy_render::material_bind_groups::{
45    MaterialBindGroupIndex, MaterialBindGroupSlot, MaterialBindingId, RenderMaterialBindings,
46};
47use bevy_render::mesh::allocator::{MeshSlabId, MeshSlabs};
48use bevy_render::mesh::morph::{
49    MorphTargetImage, MorphTargetsResource, RenderMorphTargetAllocator,
50};
51use bevy_render::mesh::MeshMetadataFallbackBuffer;
52use bevy_render::{
53    batching::{
54        gpu_preprocessing::{
55            self, GpuPreprocessingSupport, IndirectBatchSet, IndirectParametersBuffers,
56            IndirectParametersIndexed, IndirectParametersMetadata, IndirectParametersNonIndexed,
57            InstanceInputUniformBuffer, UntypedPhaseIndirectParametersBuffers,
58        },
59        no_gpu_preprocessing, GetBatchData, GetFullBatchData, NoAutomaticBatching,
60    },
61    mesh::{allocator::MeshAllocator, RenderMesh, RenderMeshBufferInfo},
62    render_asset::RenderAssets,
63    render_phase::{
64        BinnedRenderPhasePlugin, InputUniformIndex, PhaseItem, PhaseItemExtraIndex, RenderCommand,
65        RenderCommandResult, SortedRenderPhasePlugin, TrackedRenderPass,
66    },
67    render_resource::*,
68    renderer::{RenderAdapter, RenderDevice, RenderQueue},
69    sync_world::MainEntityHashSet,
70    texture::{DefaultImageSampler, GpuImage},
71    view::{self, NoIndirectDrawing, RenderVisibilityRanges, RetainedViewEntity},
72    Extract,
73};
74use bevy_shader::{load_shader_library, Shader, ShaderDefVal, ShaderSettings};
75use bevy_transform::components::GlobalTransform;
76use bevy_utils::{default, Parallel, TypeIdHashMap};
77use core::any::TypeId;
78use core::iter;
79use core::mem::size_of;
80use core::sync::atomic::{AtomicU64, Ordering};
81use indexmap::IndexSet;
82use static_assertions::const_assert_eq;
83use std::sync::mpsc;
84#[cfg(feature = "trace")]
85use tracing::info_span;
86use tracing::{error, warn};
87
88use self::irradiance_volume::IRRADIANCE_VOLUMES_ARE_USABLE;
89use crate::{
90    render::{
91        morph::{
92            extract_morphs, no_automatic_morph_batching, write_morph_buffers, MorphIndices,
93            MorphUniforms,
94        },
95        skin::no_automatic_skin_batching,
96    },
97    *,
98};
99use bevy_core_pipeline::oit::OrderIndependentTransparencySettings;
100use bevy_core_pipeline::prepass::{DeferredPrepass, DepthPrepass, NormalPrepass};
101use bevy_core_pipeline::tonemapping::{DebandDither, Tonemapping};
102use bevy_render::camera::{DirtySpecializations, ExtractedCamera, TemporalJitter};
103use bevy_render::prelude::Msaa;
104use bevy_render::sync_world::{MainEntity, MainEntityHashMap};
105use bevy_render::view::{
106    texture_format_from_code, texture_format_to_code, ExtractedView,
107    RenderShadowMapVisibleEntities, RenderVisibleEntities,
108};
109use bevy_render::RenderSystems::PrepareAssets;
110use bevy_tasks::ComputeTaskPool;
111
112use bytemuck::{Pod, Zeroable};
113use nonmax::{NonMaxU16, NonMaxU32};
114
115/// Provides support for rendering 3D meshes.
116pub struct MeshRenderPlugin {
117    /// Whether we're building [`MeshUniform`]s on GPU.
118    ///
119    /// This requires compute shader support and so will be forcibly disabled if
120    /// the platform doesn't support those.
121    pub use_gpu_instance_buffer_builder: bool,
122    /// Debugging flags that can optionally be set when constructing the renderer.
123    pub debug_flags: RenderDebugFlags,
124}
125
126impl MeshRenderPlugin {
127    /// Creates a new [`MeshRenderPlugin`] with the given debug flags.
128    pub fn new(debug_flags: RenderDebugFlags) -> MeshRenderPlugin {
129        MeshRenderPlugin {
130            use_gpu_instance_buffer_builder: false,
131            debug_flags,
132        }
133    }
134}
135
136/// How many textures are allowed in the view bind group layout (`@group(0)`) before
137/// broader compatibility with WebGL and WebGPU is at risk, due to the minimum guaranteed
138/// values for `MAX_TEXTURE_IMAGE_UNITS` (in WebGL) and `maxSampledTexturesPerShaderStage` (in WebGPU),
139/// currently both at 16.
140///
141/// We use 10 here because it still leaves us, in a worst case scenario, with 6 textures for the other bind groups.
142///
143/// See: <https://gpuweb.github.io/gpuweb/#limits>
144#[cfg(debug_assertions)]
145pub const MESH_PIPELINE_VIEW_LAYOUT_SAFE_MAX_TEXTURES: usize = 10;
146
147#[derive(Debug, Hash, PartialEq, Eq, Clone, SystemSet)]
148pub struct MeshPipelineSystems;
149
150impl Plugin for MeshRenderPlugin {
151    fn build(&self, app: &mut App) {
152        load_shader_library!(app, "forward_io.wesl");
153        load_shader_library!(app, "mesh_view_types.wesl", |settings| *settings =
154            ShaderSettings {
155                shader_defs: vec![
156                    ShaderDefVal::UInt(
157                        "MAX_DIRECTIONAL_LIGHTS".into(),
158                        MAX_DIRECTIONAL_LIGHTS as u32
159                    ),
160                    ShaderDefVal::UInt(
161                        "MAX_CASCADES_PER_LIGHT".into(),
162                        MAX_CASCADES_PER_LIGHT as u32,
163                    ),
164                    ShaderDefVal::UInt("MAX_RECT_LIGHTS".into(), MAX_RECT_LIGHTS as u32,),
165                ],
166            });
167        load_shader_library!(app, "mesh_view_bindings.wesl");
168        load_shader_library!(app, "mesh_types.wesl");
169        load_shader_library!(app, "mesh_functions.wesl");
170        load_shader_library!(app, "skinning.wesl");
171        load_shader_library!(app, "morph.wesl");
172        load_shader_library!(app, "occlusion_culling.wesl");
173
174        embedded_asset!(app, "mesh.wesl");
175
176        if app.get_sub_app(RenderApp).is_none() {
177            return;
178        }
179
180        app.add_systems(
181            PostUpdate,
182            (no_automatic_skin_batching, no_automatic_morph_batching),
183        )
184        .add_plugins((
185            BinnedRenderPhasePlugin::<Opaque3d, MeshPipeline>::new(self.debug_flags),
186            BinnedRenderPhasePlugin::<AlphaMask3d, MeshPipeline>::new(self.debug_flags),
187            BinnedRenderPhasePlugin::<Shadow, MeshPipeline>::new(self.debug_flags),
188            BinnedRenderPhasePlugin::<Opaque3dDeferred, MeshPipeline>::new(self.debug_flags),
189            BinnedRenderPhasePlugin::<AlphaMask3dDeferred, MeshPipeline>::new(self.debug_flags),
190            SortedRenderPhasePlugin::<Transmissive3d, MeshPipeline>::new(self.debug_flags),
191            SortedRenderPhasePlugin::<Transparent3d, MeshPipeline>::new(self.debug_flags),
192        ));
193
194        if let Some(render_app) = app.get_sub_app_mut(RenderApp) {
195            render_app
196                .init_gpu_resource::<MeshCullingDataBuffer>()
197                .init_resource::<RenderMaterialInstances>()
198                .configure_sets(
199                    ExtractSchedule,
200                    MeshExtractionSystems.after_weak(view::extract_visibility_ranges),
201                )
202                .add_systems(
203                    ExtractSchedule,
204                    (
205                        extract_skins,
206                        extract_morphs,
207                        gpu_preprocessing::clear_batched_gpu_instance_buffers::<MeshPipeline>
208                            .before(MeshExtractionSystems),
209                    ),
210                )
211                .add_systems(
212                    Render,
213                    (
214                        set_mesh_motion_vector_flags.in_set(RenderSystems::PrepareMeshes),
215                        prepare_skins.in_set(RenderSystems::PrepareResources),
216                        write_morph_buffers.in_set(RenderSystems::PrepareResourcesFlush),
217                        prepare_mesh_bind_groups.in_set(RenderSystems::PrepareBindGroups),
218                        prepare_mesh_view_bind_groups
219                            .in_set(RenderSystems::PrepareBindGroups)
220                            .after(prepare_oit_buffers)
221                            .after(prepare_atmosphere_buffers),
222                        no_gpu_preprocessing::clear_batched_cpu_instance_buffers::<MeshPipeline>
223                            .in_set(RenderSystems::Cleanup)
224                            .after(RenderSystems::Render),
225                        prepare_morph_descriptors.in_set(RenderSystems::PrepareMeshes),
226                    ),
227                );
228        }
229    }
230
231    fn finish(&self, app: &mut App) {
232        let mut mesh_bindings_shader_defs = Vec::with_capacity(1);
233
234        if let Some(render_app) = app.get_sub_app_mut(RenderApp) {
235            render_app
236                .init_gpu_resource::<MorphIndices>()
237                .init_gpu_resource::<MorphUniforms>()
238                .init_gpu_resource::<ViewKeyCache>()
239                .init_resource::<GpuPreprocessingSupport>()
240                .init_resource::<RenderGpuCulledEntities>()
241                .add_systems(RenderStartup, skin_uniforms_from_world)
242                .add_systems(
243                    Render,
244                    check_views_need_specialization.in_set(PrepareAssets),
245                );
246
247            let gpu_preprocessing_support =
248                render_app.world().resource::<GpuPreprocessingSupport>();
249            let use_gpu_instance_buffer_builder =
250                self.use_gpu_instance_buffer_builder && gpu_preprocessing_support.is_available();
251
252            let render_mesh_instances = RenderMeshInstances::new(use_gpu_instance_buffer_builder);
253            render_app
254                .allow_ambiguous_resource::<no_gpu_preprocessing::BatchedInstanceBuffer::<MeshUniform>>()
255                .allow_ambiguous_resource::<gpu_preprocessing::BatchedInstanceBuffers<MeshUniform, MeshInputUniform>>()
256                .insert_resource(render_mesh_instances);
257
258            if use_gpu_instance_buffer_builder {
259                render_app
260                    .init_gpu_resource::<gpu_preprocessing::BatchedInstanceBuffers<
261                        MeshUniform,
262                        MeshInputUniform
263                    >>()
264                    .init_gpu_resource::<RenderMeshInstanceGpuQueues>()
265                    .init_resource::<MeshesToReextractNextFrame>()
266                    .add_systems(
267                        RenderStartup,
268                        mark_all_meshes_for_reextraction,
269                    )
270                    .add_systems(
271                        ExtractSchedule,
272                            extract_meshes_for_gpu_building.in_set(MeshExtractionSystems),
273                    )
274                    .add_systems(
275                        Render,
276                        (
277                            gpu_preprocessing::write_batched_instance_buffers::<MeshPipeline>
278                                .in_set(RenderSystems::PrepareResourcesFlush)
279                                .after(write_mesh_culling_data_buffer),
280                            gpu_preprocessing::delete_old_work_item_buffers::<MeshPipeline>
281                                .in_set(RenderSystems::PrepareResources),
282                            collect_meshes_for_gpu_building
283                                .in_set(RenderSystems::PrepareMeshes)
284                                // This must be before
285                                // `set_mesh_motion_vector_flags` so it doesn't
286                                // overwrite those flags.
287                                .before(set_mesh_motion_vector_flags)
288                                // This must be after
289                                // `prepare_morph_descriptors` because it needs
290                                // the indices of the morph descriptors in the
291                                // buffer.
292                                .after(prepare_morph_descriptors),
293                            collect_gpu_culled_meshes.in_set(RenderSystems::PrepareMeshes)
294                                .after(collect_meshes_for_gpu_building)
295                                .before(set_mesh_motion_vector_flags),
296                        ),
297                    );
298            } else {
299                render_app
300                    .init_gpu_resource::<no_gpu_preprocessing::BatchedInstanceBuffer<MeshUniform>>()
301                    .add_systems(
302                        ExtractSchedule,
303                        extract_meshes_for_cpu_building.in_set(MeshExtractionSystems),
304                    )
305                    .add_systems(
306                        Render,
307                        no_gpu_preprocessing::write_batched_instance_buffer::<MeshPipeline>
308                            .in_set(RenderSystems::PrepareResourcesFlush),
309                    );
310            };
311
312            let render_device = render_app.world().resource::<RenderDevice>();
313            if let Some(per_object_buffer_batch_size) =
314                GpuArrayBuffer::<MeshUniform>::batch_size(&render_device.limits())
315            {
316                mesh_bindings_shader_defs.push(ShaderDefVal::UInt(
317                    "PER_OBJECT_BUFFER_BATCH_SIZE".into(),
318                    per_object_buffer_batch_size,
319                ));
320            }
321
322            render_app.add_systems(
323                RenderStartup,
324                (init_mesh_pipeline_view_layouts, init_mesh_pipeline)
325                    .chain()
326                    .in_set(MeshPipelineSystems),
327            );
328        }
329
330        // Load the mesh_bindings shader module here as it depends on runtime information about
331        // whether storage buffers are supported, or the maximum uniform buffer binding size.
332        load_shader_library!(app, "mesh_bindings.wesl", move |settings| *settings =
333            ShaderSettings {
334                shader_defs: mesh_bindings_shader_defs.clone(),
335            });
336    }
337}
338
339/// Drains all entities from [`RenderMeshInstances`] into [`MeshesToReextractNextFrame`].
340fn mark_all_meshes_for_reextraction(
341    mut render_mesh_instances: ResMut<RenderMeshInstances>,
342    mut meshes_to_reextract: ResMut<MeshesToReextractNextFrame>,
343) {
344    match *render_mesh_instances {
345        RenderMeshInstances::CpuBuilding(ref mut cpu) => {
346            meshes_to_reextract.extend(cpu.keys());
347            cpu.clear();
348        }
349        RenderMeshInstances::GpuBuilding(ref mut gpu) => {
350            meshes_to_reextract.extend(gpu.keys());
351            gpu.clear();
352        }
353    }
354}
355
356/// This resource caches [`MeshPipelineKey`]s for each view with pre-enabled features needed to properly
357/// setup the [`MeshViewBindGroup`] layout in specialized [`MeshPipeline`]s.
358#[derive(Resource, Deref, DerefMut, Default, Debug, Clone)]
359pub struct ViewKeyCache(HashMap<RetainedViewEntity, MeshPipelineKey>);
360
361pub fn check_views_need_specialization(
362    mut view_key_cache: ResMut<ViewKeyCache>,
363    mut dirty_specializations: ResMut<DirtySpecializations>,
364    mut views: Query<(
365        &ExtractedView,
366        Option<&ExtractedCamera>,
367        &Msaa,
368        (Option<&Tonemapping>, Option<&DebandDither>),
369        Option<&ShadowFilteringMethod>,
370        Has<ScreenSpaceAmbientOcclusion>,
371        (
372            Has<NormalPrepass>,
373            Has<DepthPrepass>,
374            Has<MotionVectorPrepass>,
375            Has<DeferredPrepass>,
376        ),
377        Option<&ScreenSpaceTransmission>,
378        Has<TemporalJitter>,
379        Option<&Projection>,
380        Has<DistanceFog>,
381        (
382            Has<RenderViewLightProbes<EnvironmentMapLight>>,
383            Has<RenderViewLightProbes<IrradianceVolume>>,
384        ),
385        (
386            Has<OrderIndependentTransparencySettings>,
387            Has<ExtractedAtmosphere>,
388            Has<ScreenSpaceReflectionsUniform>,
389            Has<ContactShadows>,
390        ),
391    )>,
392    mut seen_views: Local<HashSet<RetainedViewEntity>>,
393) {
394    seen_views.clear();
395
396    for (
397        view,
398        camera,
399        msaa,
400        (tonemapping, dither),
401        shadow_filter_method,
402        ssao,
403        (normal_prepass, depth_prepass, motion_vector_prepass, deferred_prepass),
404        transmission,
405        temporal_jitter,
406        projection,
407        distance_fog,
408        (has_environment_maps, has_irradiance_volumes),
409        (has_oit, has_atmosphere, has_ssr, has_contact_shadows),
410    ) in views.iter_mut()
411    {
412        seen_views.insert(view.retained_view_entity);
413
414        let mut view_key = MeshPipelineKey::from_msaa_samples(msaa.samples())
415            | MeshPipelineKey::from_target_format(view.target_format);
416
417        if normal_prepass {
418            view_key |= MeshPipelineKey::NORMAL_PREPASS;
419        }
420
421        if depth_prepass {
422            view_key |= MeshPipelineKey::DEPTH_PREPASS;
423        }
424
425        if motion_vector_prepass {
426            view_key |= MeshPipelineKey::MOTION_VECTOR_PREPASS;
427        }
428
429        if deferred_prepass {
430            view_key |= MeshPipelineKey::DEFERRED_PREPASS;
431        }
432
433        if temporal_jitter {
434            view_key |= MeshPipelineKey::TEMPORAL_JITTER;
435        }
436
437        if has_environment_maps {
438            view_key |= MeshPipelineKey::ENVIRONMENT_MAP;
439        }
440
441        if has_irradiance_volumes {
442            view_key |= MeshPipelineKey::IRRADIANCE_VOLUME;
443        }
444
445        if has_ssr {
446            view_key |= MeshPipelineKey::SCREEN_SPACE_REFLECTIONS;
447        }
448
449        if has_oit {
450            view_key |= MeshPipelineKey::OIT_ENABLED;
451        }
452
453        if has_atmosphere {
454            view_key |= MeshPipelineKey::ATMOSPHERE;
455        }
456
457        if has_contact_shadows {
458            view_key |= MeshPipelineKey::CONTACT_SHADOWS;
459        }
460
461        if view.invert_culling {
462            view_key |= MeshPipelineKey::INVERT_CULLING;
463        }
464
465        if let Some(projection) = projection {
466            view_key |= match projection {
467                Projection::Perspective(_) => MeshPipelineKey::VIEW_PROJECTION_PERSPECTIVE,
468                Projection::Orthographic(_) => MeshPipelineKey::VIEW_PROJECTION_ORTHOGRAPHIC,
469                Projection::Custom(_) => MeshPipelineKey::VIEW_PROJECTION_NONSTANDARD,
470            };
471        }
472
473        match shadow_filter_method.unwrap_or(&ShadowFilteringMethod::default()) {
474            ShadowFilteringMethod::Hardware2x2 => {
475                view_key |= MeshPipelineKey::SHADOW_FILTER_METHOD_HARDWARE_2X2;
476            }
477            ShadowFilteringMethod::Gaussian => {
478                view_key |= MeshPipelineKey::SHADOW_FILTER_METHOD_GAUSSIAN;
479            }
480            ShadowFilteringMethod::Temporal => {
481                view_key |= MeshPipelineKey::SHADOW_FILTER_METHOD_TEMPORAL;
482            }
483        }
484
485        if camera.is_none_or(|camera| !camera.hdr)
486            && let Some(tonemapping) = tonemapping
487            && tonemapping.is_enabled()
488        {
489            view_key |= MeshPipelineKey::TONEMAP_IN_SHADER;
490            view_key |= tonemapping_pipeline_key(*tonemapping);
491            if let Some(DebandDither::Enabled) = dither {
492                view_key |= MeshPipelineKey::DEBAND_DITHER;
493            }
494        }
495        if ssao {
496            view_key |= MeshPipelineKey::SCREEN_SPACE_AMBIENT_OCCLUSION;
497        }
498        if distance_fog {
499            view_key |= MeshPipelineKey::DISTANCE_FOG;
500        }
501        if let Some(transmission) = transmission {
502            view_key |= MeshPipelineKey::VIEW_TRANSMISSION_TEXTURE;
503            view_key |= transmission.quality.pipeline_key();
504        }
505        if !view_key_cache
506            .get_mut(&view.retained_view_entity)
507            .is_some_and(|current_key| *current_key == view_key)
508        {
509            view_key_cache.insert(view.retained_view_entity, view_key);
510            dirty_specializations
511                .views
512                .insert(view.retained_view_entity);
513        }
514    }
515
516    view_key_cache.retain(|view, _| seen_views.contains(view));
517}
518
519#[derive(Component)]
520pub struct MeshTransforms {
521    pub world_from_local: Affine3,
522    pub previous_world_from_local: Affine3,
523    pub flags: u32,
524}
525
526#[derive(ShaderType, Clone)]
527pub struct MeshUniform {
528    // Affine 4x3 matrices transposed to 3x4
529    pub world_from_local: [Vec4; 3],
530    pub previous_world_from_local: [Vec4; 3],
531    // 3x3 matrix packed in mat2x4 and f32 as:
532    //   [0].xyz, [1].x,
533    //   [1].yz, [2].xy
534    //   [2].z
535    pub local_from_world_transpose_a: [Vec4; 2],
536    pub local_from_world_transpose_b: f32,
537    pub flags: u32,
538    // Four 16-bit unsigned normalized UV values packed into a `UVec2`:
539    //
540    //                         <--- MSB                   LSB --->
541    //                         +---- min v ----+ +---- min u ----+
542    //     lightmap_uv_rect.x: vvvvvvvv vvvvvvvv uuuuuuuu uuuuuuuu,
543    //                         +---- max v ----+ +---- max u ----+
544    //     lightmap_uv_rect.y: VVVVVVVV VVVVVVVV UUUUUUUU UUUUUUUU,
545    //
546    // (MSB: most significant bit; LSB: least significant bit.)
547    pub lightmap_uv_rect: UVec2,
548    /// The index of this mesh's first vertex in the vertex buffer.
549    ///
550    /// Multiple meshes can be packed into a single vertex buffer (see
551    /// [`MeshAllocator`]). This value stores the offset of the first vertex in
552    /// this mesh in that buffer.
553    pub first_vertex_index: u32,
554    /// The current skin index, or `u32::MAX` if there's no skin.
555    pub current_skin_index: u32,
556    /// The material and lightmap indices, packed into 32 bits.
557    ///
558    /// Low 16 bits: index of the material inside the bind group data.
559    /// High 16 bits: index of the lightmap in the binding array.
560    pub material_and_lightmap_bind_group_slot: u32,
561    /// User supplied tag to identify this mesh instance.
562    pub tag: u32,
563    /// The index of the morph descriptor for this mesh instance in the
564    /// `morph_descriptors` table.
565    ///
566    /// If the mesh has no morph targets, this is `u32::MAX`.
567    pub morph_descriptor_index: u32,
568    /// The index of the mesh metadata buffer.
569    pub metadata_index: u32,
570}
571
572/// Information that has to be transferred from CPU to GPU in order to produce
573/// the full [`MeshUniform`].
574///
575/// This is essentially a subset of the fields in [`MeshUniform`] above.
576#[derive(ShaderType, Pod, Zeroable, Clone, Copy, Default, Debug)]
577#[repr(C)]
578pub struct MeshInputUniform {
579    /// Affine 4x3 matrix transposed to 3x4.
580    pub world_from_local: [Vec4; 3],
581    /// Four 16-bit unsigned normalized UV values packed into a `UVec2`:
582    ///
583    /// ```text
584    ///                         <--- MSB                   LSB --->
585    ///                         +---- min v ----+ +---- min u ----+
586    ///     lightmap_uv_rect.x: vvvvvvvv vvvvvvvv uuuuuuuu uuuuuuuu,
587    ///                         +---- max v ----+ +---- max u ----+
588    ///     lightmap_uv_rect.y: VVVVVVVV VVVVVVVV UUUUUUUU UUUUUUUU,
589    ///
590    /// (MSB: most significant bit; LSB: least significant bit.)
591    /// ```
592    pub lightmap_uv_rect: UVec2,
593    /// Various [`MeshFlags`].
594    pub flags: u32,
595    /// The index of this mesh's [`MeshInputUniform`] in the previous frame's
596    /// buffer, if applicable.
597    ///
598    /// This is used for TAA. If not present, this will be `u32::MAX`.
599    pub previous_input_index: u32,
600    /// The index of this mesh's first vertex in the vertex buffer.
601    ///
602    /// Multiple meshes can be packed into a single vertex buffer (see
603    /// [`MeshAllocator`]). This value stores the offset of the first vertex in
604    /// this mesh in that buffer.
605    pub first_vertex_index: u32,
606    /// The index of this mesh's first index in the index buffer, if any.
607    ///
608    /// Multiple meshes can be packed into a single index buffer (see
609    /// [`MeshAllocator`]). This value stores the offset of the first index in
610    /// this mesh in that buffer.
611    ///
612    /// If this mesh isn't indexed, this value is ignored.
613    pub first_index_index: u32,
614    /// For an indexed mesh, the number of indices that make it up; for a
615    /// non-indexed mesh, the number of vertices in it.
616    pub index_count: u32,
617    /// The current skin index, or `u32::MAX` if there's no skin.
618    pub current_skin_index: u32,
619    /// The material and lightmap indices, packed into 32 bits.
620    ///
621    /// Low 16 bits: index of the material inside the bind group data.
622    /// High 16 bits: index of the lightmap in the binding array.
623    pub material_and_lightmap_bind_group_slot: u32,
624    /// The number of the frame on which this [`MeshInputUniform`] was built.
625    ///
626    /// This is used to validate the previous transform and skin. If this
627    /// [`MeshInputUniform`] wasn't updated on this frame, then we know that
628    /// neither this mesh's transform nor that of its joints have been updated
629    /// on this frame, and therefore the transforms of both this mesh and its
630    /// joints must be identical to those for the previous frame.
631    pub timestamp: u32,
632    /// User supplied tag to identify this mesh instance.
633    pub tag: u32,
634    /// The index of the morph descriptor for this mesh instance in the
635    /// `morph_descriptors` table.
636    ///
637    /// If the mesh has no morph targets, this is `u32::MAX`.
638    pub morph_descriptor_index: u32,
639    pub metadata_index: u32,
640    pub pad1: u32,
641    pub pad2: u32,
642    pub pad3: u32,
643}
644
645/// Per-mesh-instance data that we retain from the previous frame.
646#[derive(ShaderType, Pod, Zeroable, Clone, Copy, Default, Debug)]
647#[repr(C)]
648pub struct PreviousMeshInputUniform {
649    /// The model transform, an affine 4×3 matrix transposed to 3×4.
650    pub world_from_local: [Vec4; 3],
651}
652
653impl BufferDataInput for MeshInputUniform {
654    type Previous = PreviousMeshInputUniform;
655}
656
657impl_atomic_pod!(MeshInputUniform, MeshInputUniformBlob);
658
659impl_atomic_pod!(PreviousMeshInputUniform, PreviousMeshInputUniformBlob);
660
661/// Information about each mesh instance needed to cull it on GPU.
662///
663/// This consists of its axis-aligned bounding box (AABB).
664#[derive(ShaderType, Pod, Zeroable, Clone, Copy, Default)]
665#[repr(C)]
666pub struct MeshCullingData {
667    /// The 3D center of the AABB in model space, padded with an extra unused
668    /// float value.
669    pub aabb_center: Vec4,
670    /// The 3D extents of the AABB in model space, divided by two, padded with
671    /// an extra unused float value.
672    pub aabb_half_extents: Vec4,
673}
674
675/// A GPU buffer that holds the information needed to cull meshes on GPU.
676///
677/// At the moment, this simply holds each mesh's AABB.
678///
679/// To avoid wasting CPU time in the CPU culling case, this buffer will be empty
680/// if GPU culling isn't in use.
681#[derive(Resource, Deref, DerefMut)]
682pub struct MeshCullingDataBuffer(AtomicSparseBufferVec<MeshCullingData>);
683
684impl_atomic_pod!(MeshCullingData, MeshCullingDataBlob);
685
686impl MeshUniform {
687    pub fn new(
688        mesh_transforms: &MeshTransforms,
689        first_vertex_index: u32,
690        material_bind_group_slot: MaterialBindGroupSlot,
691        maybe_lightmap: Option<(LightmapSlotIndex, Rect)>,
692        current_skin_index: Option<u32>,
693        morph_descriptor_index: Option<MorphDescriptorIndex>,
694        tag: Option<u32>,
695        metadata_index: Option<u32>,
696    ) -> Self {
697        let (local_from_world_transpose_a, local_from_world_transpose_b) =
698            mesh_transforms.world_from_local.inverse_transpose_3x3();
699        let lightmap_bind_group_slot = match maybe_lightmap {
700            None => u16::MAX,
701            Some((slot_index, _)) => slot_index.into(),
702        };
703
704        let material_slot = u32::from(material_bind_group_slot);
705        debug_assert!(
706            material_slot <= 0xFFFF,
707            "Material bind group slot {material_slot} overflowed"
708        );
709        let material_and_lightmap_bind_group_slot =
710            material_slot | ((lightmap_bind_group_slot as u32) << 16);
711
712        Self {
713            world_from_local: mesh_transforms.world_from_local.to_transpose(),
714            previous_world_from_local: mesh_transforms.previous_world_from_local.to_transpose(),
715            lightmap_uv_rect: pack_lightmap_uv_rect(maybe_lightmap.map(|(_, uv_rect)| uv_rect)),
716            local_from_world_transpose_a,
717            local_from_world_transpose_b,
718            flags: mesh_transforms.flags,
719            first_vertex_index,
720            current_skin_index: current_skin_index.unwrap_or(u32::MAX),
721            material_and_lightmap_bind_group_slot,
722            tag: tag.unwrap_or(0),
723            morph_descriptor_index: match morph_descriptor_index {
724                Some(morph_descriptor_index) => morph_descriptor_index.0,
725                None => u32::MAX,
726            },
727            metadata_index: metadata_index.unwrap_or(0),
728        }
729    }
730}
731
732// NOTE: These must match the bit flags in bevy_pbr/src/render/mesh_types.wesl!
733bitflags::bitflags! {
734    /// Various flags and tightly-packed values on a mesh.
735    ///
736    /// Flags grow from the top bit down; other values grow from the bottom bit
737    /// up.
738    #[repr(transparent)]
739    pub struct MeshFlags: u32 {
740        /// Bitmask for the 16-bit index into the LOD array.
741        ///
742        /// This will be `u16::MAX` if this mesh has no LOD.
743        const LOD_INDEX_MASK              = (1 << 16) - 1;
744        /// Whether visibility ranges use the center of the AABB to compute
745        /// distance from the camera.
746        ///
747        /// If false, this uses distance from the world-space translation of the
748        /// mesh instead.
749        const AABB_BASED_VISIBILITY_RANGE = 1 << 27;
750        /// Disables frustum culling for this mesh.
751        ///
752        /// This corresponds to the
753        /// [`bevy_render::view::visibility::NoFrustumCulling`] component.
754        const NO_FRUSTUM_CULLING          = 1 << 28;
755        const SHADOW_RECEIVER             = 1 << 29;
756        const TRANSMITTED_SHADOW_RECEIVER = 1 << 30;
757        // Indicates the sign of the determinant of the 3x3 model matrix. If the sign is positive,
758        // then the flag should be set, else it should not be set.
759        const SIGN_DETERMINANT_MODEL_3X3  = 1 << 31;
760        const NONE                        = 0;
761        const UNINITIALIZED               = 0xFFFFFFFF;
762    }
763}
764
765impl MeshFlags {
766    fn from_components(
767        transform: &GlobalTransform,
768        lod_index: Option<NonMaxU16>,
769        visibility_range: Option<&VisibilityRange>,
770        no_frustum_culling: bool,
771        not_shadow_receiver: bool,
772        transmitted_receiver: bool,
773    ) -> MeshFlags {
774        let mut mesh_flags = if not_shadow_receiver {
775            MeshFlags::empty()
776        } else {
777            MeshFlags::SHADOW_RECEIVER
778        };
779        if visibility_range.is_some_and(|visibility_range| visibility_range.use_aabb) {
780            mesh_flags |= MeshFlags::AABB_BASED_VISIBILITY_RANGE;
781        }
782        if no_frustum_culling {
783            mesh_flags |= MeshFlags::NO_FRUSTUM_CULLING;
784        }
785        if transmitted_receiver {
786            mesh_flags |= MeshFlags::TRANSMITTED_SHADOW_RECEIVER;
787        }
788        if transform.affine().matrix3.determinant().is_sign_positive() {
789            mesh_flags |= MeshFlags::SIGN_DETERMINANT_MODEL_3X3;
790        }
791
792        let lod_index_bits = match lod_index {
793            None => u16::MAX,
794            Some(lod_index) => u16::from(lod_index),
795        };
796        mesh_flags |=
797            MeshFlags::from_bits_retain((lod_index_bits as u32) << MeshFlags::LOD_INDEX_SHIFT);
798
799        mesh_flags
800    }
801
802    /// The first bit of the LOD index.
803    pub const LOD_INDEX_SHIFT: u32 = 0;
804}
805
806bitflags::bitflags! {
807    /// Various useful flags for [`RenderMeshInstance`]s.
808    #[derive(Clone, Copy, Default, Pod, Zeroable)]
809    #[repr(C)]
810    pub struct RenderMeshInstanceFlags: u32 {
811        /// The mesh casts shadows.
812        const SHADOW_CASTER           = 1 << 0;
813        /// The mesh can participate in automatic batching.
814        const AUTOMATIC_BATCHING      = 1 << 1;
815        /// The mesh had a transform last frame and so is eligible for motion
816        /// vector computation.
817        const HAS_PREVIOUS_TRANSFORM  = 1 << 2;
818        /// The mesh had a skin last frame and so that skin should be taken into
819        /// account for motion vector computation.
820        const HAS_PREVIOUS_SKIN       = 1 << 3;
821        /// The mesh had morph targets last frame and so they should be taken
822        /// into account for motion vector computation.
823        const HAS_PREVIOUS_MORPH      = 1 << 4;
824        /// CPU culling has been disabled because the `NoCpuCulling` component
825        /// is present on the mesh instance.
826        const NO_CPU_CULLING          = 1 << 5;
827    }
828}
829
830/// CPU data that the render world keeps for each entity, when *not* using GPU
831/// mesh uniform building.
832#[derive(Deref, DerefMut)]
833pub struct RenderMeshInstanceCpu {
834    /// Data shared between both the CPU mesh uniform building and the GPU mesh
835    /// uniform building paths.
836    #[deref]
837    pub shared: RenderMeshInstanceSharedFlatBlob,
838    /// The transform of the mesh.
839    ///
840    /// This will be written into the [`MeshUniform`] at the appropriate time.
841    pub transforms: MeshTransforms,
842    /// The set of render layers that this mesh belongs to.
843    pub render_layers: Option<RenderLayers>,
844}
845
846/// CPU data that the render world needs to keep for each entity that contains a
847/// mesh when using GPU mesh uniform building.
848#[derive(Deref)]
849pub struct RenderMeshInstanceGpu {
850    /// Thread-safe shared between both the CPU mesh uniform building and the
851    /// GPU mesh uniform building paths.
852    #[deref]
853    pub shared: RenderMeshInstanceSharedFlatBlob,
854    /// Thread-safe per-mesh-instance data that's specific to the GPU mesh
855    /// uniform building path.
856    pub gpu_specific: RenderMeshInstanceGpuFlatBlob,
857    /// The render layers that this mesh instance belongs to.
858    ///
859    /// This contains a [`smallvec::SmallVec`], so it isn't thread-safe.
860    pub render_layers: Option<RenderLayers>,
861}
862
863/// The thread-safe POD that's stored for each mesh, common to both the CPU and
864/// GPU preprocessing paths.
865///
866/// Fields here are formatted in such a way as to implement [`bytemuck::Pod`]:
867/// i.e. with no vectors and no enums. A corresponding
868/// [`RenderMeshInstanceSharedFlatBlob`] is provided, for in-place update in
869/// shared memory.
870#[derive(Clone, Copy, Default, Pod, Zeroable)]
871#[repr(C)]
872pub struct RenderMeshInstanceSharedFlat {
873    asset_id: MeshAssetIdFlat,
874    material_bindings_index: MaterialBindingId,
875    lightmap_slab_index: LightmapSlabIndexFlat,
876    tag: u32,
877    current_uniform_index: u32,
878    flags: RenderMeshInstanceFlags,
879}
880
881impl_atomic_pod!(
882    RenderMeshInstanceSharedFlat,
883    RenderMeshInstanceSharedFlatBlob,
884    field(asset_id: MeshAssetIdFlat, mesh_asset_id_flat, set_mesh_asset_id_flat),
885    field(
886        material_bindings_index: MaterialBindingId,
887        material_bindings_index,
888        set_material_bindings_index
889    ),
890    field(
891        lightmap_slab_index: LightmapSlabIndexFlat,
892        lightmap_slab_index_flat,
893        set_lightmap_slab_index_flat
894    ),
895    field(tag: u32, tag, set_tag),
896    field(flags: RenderMeshInstanceFlags, flags, set_flags),
897);
898
899impl RenderMeshInstanceSharedFlatBlob {
900    pub fn mesh_asset_id(&self) -> AssetId<Mesh> {
901        self.mesh_asset_id_flat().into()
902    }
903
904    pub fn set_mesh_asset_id(&self, asset_id: AssetId<Mesh>) {
905        self.set_mesh_asset_id_flat(asset_id.into());
906    }
907
908    pub fn lightmap_slab_index(&self) -> Option<LightmapSlabIndex> {
909        self.lightmap_slab_index_flat().into()
910    }
911
912    pub fn set_lightmap_slab_index(&self, lightmap_slab_index: Option<LightmapSlabIndex>) {
913        self.set_lightmap_slab_index_flat(lightmap_slab_index.into());
914    }
915
916    /// Returns true if this entity is eligible to participate in automatic
917    /// batching.
918    #[inline]
919    pub fn should_batch(&self) -> bool {
920        self.flags()
921            .contains(RenderMeshInstanceFlags::AUTOMATIC_BATCHING)
922    }
923}
924
925/// Data in [`RenderMeshInstanceGpu`] that's both specific to the GPU
926/// preprocessing path and POD.
927///
928/// This includes all the data except the `render_layers` list, which isn't POD.
929#[derive(Clone, Copy, Default, Pod, Zeroable)]
930#[repr(C)]
931pub struct RenderMeshInstanceGpuFlat {
932    current_uniform_index: u32,
933}
934
935impl_atomic_pod!(
936    RenderMeshInstanceGpuFlat,
937    RenderMeshInstanceGpuFlatBlob,
938    field(current_uniform_index: u32, current_uniform_index, set_current_uniform_index),
939);
940
941#[derive(Clone, Copy, Default, Pod, Zeroable)]
942#[repr(C)]
943struct MeshAssetIdFlat {
944    mode: u32,
945    words: [u32; 4],
946}
947
948#[derive(Clone, Copy, Default, Pod, Zeroable)]
949#[repr(C)]
950struct LightmapSlabIndexFlat(u32);
951
952const MESH_ASSET_ID_FLAT_MODE_INDEX: u32 = 0;
953const MESH_ASSET_ID_FLAT_MODE_UUID: u32 = 1;
954
955impl From<AssetId<Mesh>> for MeshAssetIdFlat {
956    #[inline]
957    fn from(value: AssetId<Mesh>) -> Self {
958        match value {
959            AssetId::Index { index, .. } => {
960                let bits = index.to_bits();
961                MeshAssetIdFlat {
962                    mode: MESH_ASSET_ID_FLAT_MODE_INDEX,
963                    words: [(bits & 0xffff_ffff) as u32, (bits >> 32) as u32, 0, 0],
964                }
965            }
966            AssetId::Uuid { uuid } => {
967                let (hi, lo) = uuid.as_u64_pair();
968                MeshAssetIdFlat {
969                    mode: MESH_ASSET_ID_FLAT_MODE_UUID,
970                    words: [
971                        (lo & 0xffff_ffff) as u32,
972                        (lo >> 32) as u32,
973                        (hi & 0xffff_ffff) as u32,
974                        (hi >> 32) as u32,
975                    ],
976                }
977            }
978        }
979    }
980}
981
982impl From<MeshAssetIdFlat> for AssetId<Mesh> {
983    #[inline]
984    fn from(value: MeshAssetIdFlat) -> AssetId<Mesh> {
985        if value.mode == MESH_ASSET_ID_FLAT_MODE_INDEX {
986            AssetId::from(AssetIndex::from_bits(
987                (value.words[0] as u64) | ((value.words[1] as u64) << 32),
988            ))
989        } else {
990            let lo = (value.words[0] as u64) | ((value.words[1] as u64) << 32);
991            let hi = (value.words[2] as u64) | ((value.words[3] as u64) << 32);
992            AssetId::Uuid {
993                uuid: Uuid::from_u64_pair(hi, lo),
994            }
995        }
996    }
997}
998
999impl From<Option<LightmapSlabIndex>> for LightmapSlabIndexFlat {
1000    #[inline]
1001    fn from(value: Option<LightmapSlabIndex>) -> Self {
1002        match value {
1003            Some(slab_index) => LightmapSlabIndexFlat((*slab_index).into()),
1004            None => LightmapSlabIndexFlat(!0),
1005        }
1006    }
1007}
1008
1009impl From<LightmapSlabIndexFlat> for Option<LightmapSlabIndex> {
1010    #[inline]
1011    fn from(value: LightmapSlabIndexFlat) -> Self {
1012        NonMaxU32::new(value.0).map(LightmapSlabIndex)
1013    }
1014}
1015
1016/// CPU data that the render world needs to keep about each entity that contains
1017/// a mesh.
1018pub struct RenderMeshInstanceShared {
1019    /// The [`AssetId`] of the mesh.
1020    pub mesh_asset_id: AssetId<Mesh>,
1021    /// A slot for the material bind group index.
1022    pub material_bindings_index: MaterialBindingId,
1023    /// Index of the slab that the lightmap resides in, if a lightmap is
1024    /// present.
1025    pub lightmap_slab_index: Option<LightmapSlabIndex>,
1026    /// A representative position of the mesh instance in local space,
1027    /// derived from its axis-aligned bounding box.
1028    ///
1029    /// This value is typically used as a spatial proxy for operations such as
1030    /// view-dependent sorting (e.g., transparent object ordering).
1031    pub center: Vec3,
1032    /// User supplied tag to identify this mesh instance.
1033    pub tag: u32,
1034    /// Various flags.
1035    pub flags: RenderMeshInstanceFlags,
1036}
1037
1038/// Information that is gathered during the parallel portion of mesh extraction
1039/// when GPU mesh uniform building is enabled.
1040///
1041/// From this, the [`MeshInputUniform`] and [`RenderMeshInstanceGpu`] are
1042/// prepared.
1043pub struct RenderMeshInstanceGpuBuilder {
1044    /// Data that will be placed on the [`RenderMeshInstanceGpu`].
1045    pub shared: RenderMeshInstanceSharedFlat,
1046    /// The current transform.
1047    pub world_from_local: Affine3,
1048    /// Four 16-bit unsigned normalized UV values packed into a [`UVec2`]:
1049    ///
1050    /// ```text
1051    ///                         <--- MSB                   LSB --->
1052    ///                         +---- min v ----+ +---- min u ----+
1053    ///     lightmap_uv_rect.x: vvvvvvvv vvvvvvvv uuuuuuuu uuuuuuuu,
1054    ///                         +---- max v ----+ +---- max u ----+
1055    ///     lightmap_uv_rect.y: VVVVVVVV VVVVVVVV UUUUUUUU UUUUUUUU,
1056    ///
1057    /// (MSB: most significant bit; LSB: least significant bit.)
1058    /// ```
1059    pub lightmap_uv_rect: UVec2,
1060    /// The index of the previous mesh input.
1061    pub previous_input_index: Option<NonMaxU32>,
1062    /// The render layers that this mesh instance belongs to.
1063    pub render_layers: Option<RenderLayers>,
1064    /// Various flags.
1065    pub mesh_flags: MeshFlags,
1066}
1067
1068/// The per-thread queues used during [`extract_meshes_for_gpu_building`].
1069///
1070/// There are two varieties of these: one for when culling happens on CPU and
1071/// one for when culling happens on GPU. Having the two varieties avoids wasting
1072/// space if GPU culling is disabled.
1073#[derive(Default)]
1074pub enum RenderMeshInstanceGpuQueue {
1075    /// The default value.
1076    ///
1077    /// This becomes [`RenderMeshInstanceGpuQueue::CpuCulling`] or
1078    /// [`RenderMeshInstanceGpuQueue::GpuCulling`] once extraction starts.
1079    #[default]
1080    None,
1081    /// The version of [`RenderMeshInstanceGpuQueue`] that omits the
1082    /// [`MeshCullingData`], so that we don't waste space when GPU
1083    /// culling is disabled.
1084    CpuCulling {
1085        /// Stores GPU data for each entity that became visible or changed in
1086        /// such a way that necessitates updating the [`MeshInputUniform`] (e.g.
1087        /// changed transform).
1088        changed: Vec<(MainEntity, RenderMeshInstanceGpuBuilder)>,
1089        /// Stores the IDs of entities that became invisible this frame.
1090        removed: Vec<MainEntity>,
1091    },
1092    /// The version of [`RenderMeshInstanceGpuQueue`] that contains the
1093    /// [`MeshCullingData`], used when any view has GPU culling
1094    /// enabled.
1095    GpuCulling {
1096        /// Stores GPU data for each mesh entity that became visible or changed
1097        /// in such a way as to necessitate updating the [`MeshInputUniform`]
1098        /// (e.g. changed transform).
1099        ///
1100        /// This only stores information for meshes *without* [`NoCpuCulling`].
1101        changed_cpu_culling: Vec<(MainEntity, RenderMeshInstanceGpuBuilder, MeshCullingData)>,
1102        /// Stores GPU data for each mesh entity that changed in such a way as
1103        /// to necessitate updating the [`MeshInputUniform`] (e.g. changed
1104        /// transform).
1105        ///
1106        /// This only stores information for meshes *with* [`NoCpuCulling`].
1107        changed_gpu_culling: Vec<(MainEntity, RenderMeshInstanceGpuBuilder, MeshCullingData)>,
1108        /// Stores the IDs of entities that became invisible this frame.
1109        removed: Vec<MainEntity>,
1110    },
1111}
1112
1113/// The per-thread queues containing mesh instances, populated during the
1114/// extract phase.
1115///
1116/// These are filled in [`extract_meshes_for_gpu_building`] and consumed in
1117/// [`collect_meshes_for_gpu_building`].
1118#[derive(Resource, Default, Deref, DerefMut)]
1119pub struct RenderMeshInstanceGpuQueues(Parallel<RenderMeshInstanceGpuQueue>);
1120
1121/// Holds a list of meshes that couldn't be extracted this frame because their
1122/// materials weren't prepared yet.
1123///
1124/// On subsequent frames, we try to reextract those meshes.
1125#[derive(Resource, Default, Deref, DerefMut)]
1126pub struct MeshesToReextractNextFrame(MainEntityHashSet);
1127
1128impl RenderMeshInstanceSharedFlat {
1129    /// A gpu builder will provide the mesh instance id
1130    /// during [`RenderMeshInstanceGpuPrepared::update`].
1131    fn for_gpu_building(
1132        previous_transform: Option<&PreviousGlobalTransform>,
1133        mesh: &Mesh3d,
1134        tag: Option<&MeshTag>,
1135        not_shadow_caster: bool,
1136        no_automatic_batching: bool,
1137        no_cpu_culling: bool,
1138    ) -> Self {
1139        Self::new(
1140            previous_transform,
1141            mesh,
1142            tag,
1143            default(),
1144            not_shadow_caster,
1145            no_automatic_batching,
1146            no_cpu_culling,
1147        )
1148    }
1149
1150    /// The cpu builder does not have an equivalent [`RenderMeshInstanceGpuBuilder`].
1151    fn for_cpu_building(
1152        previous_transform: Option<&PreviousGlobalTransform>,
1153        mesh: &Mesh3d,
1154        tag: Option<&MeshTag>,
1155        material_bindings_index: MaterialBindingId,
1156        not_shadow_caster: bool,
1157        no_automatic_batching: bool,
1158    ) -> Self {
1159        Self::new(
1160            previous_transform,
1161            mesh,
1162            tag,
1163            material_bindings_index,
1164            not_shadow_caster,
1165            no_automatic_batching,
1166            false,
1167        )
1168    }
1169
1170    fn new(
1171        previous_transform: Option<&PreviousGlobalTransform>,
1172        mesh: &Mesh3d,
1173        tag: Option<&MeshTag>,
1174        material_bindings_index: MaterialBindingId,
1175        not_shadow_caster: bool,
1176        no_automatic_batching: bool,
1177        no_cpu_culling: bool,
1178    ) -> Self {
1179        let mut mesh_instance_flags = RenderMeshInstanceFlags::empty();
1180        mesh_instance_flags.set(RenderMeshInstanceFlags::SHADOW_CASTER, !not_shadow_caster);
1181        mesh_instance_flags.set(
1182            RenderMeshInstanceFlags::AUTOMATIC_BATCHING,
1183            !no_automatic_batching,
1184        );
1185        mesh_instance_flags.set(
1186            RenderMeshInstanceFlags::HAS_PREVIOUS_TRANSFORM,
1187            previous_transform.is_some(),
1188        );
1189        mesh_instance_flags.set(RenderMeshInstanceFlags::NO_CPU_CULLING, no_cpu_culling);
1190
1191        RenderMeshInstanceSharedFlat {
1192            asset_id: mesh.id().into(),
1193            material_bindings_index,
1194            tag: tag.map_or(0, |i| **i),
1195            flags: mesh_instance_flags,
1196            // Filled in later.
1197            lightmap_slab_index: LightmapSlabIndexFlat::default(),
1198            // Filled in later.
1199            current_uniform_index: 0,
1200        }
1201    }
1202}
1203
1204/// Information that the render world keeps about each entity that contains a
1205/// mesh.
1206///
1207/// The set of information needed is different depending on whether CPU or GPU
1208/// [`MeshUniform`] building is in use.
1209#[derive(Resource)]
1210pub enum RenderMeshInstances {
1211    /// Information needed when using CPU mesh instance data building.
1212    CpuBuilding(RenderMeshInstancesCpu),
1213    /// Information needed when using GPU mesh instance data building.
1214    GpuBuilding(RenderMeshInstancesGpu),
1215}
1216
1217/// Information that the render world keeps about each entity that contains a
1218/// mesh, when using CPU mesh instance data building.
1219#[derive(Default, Deref, DerefMut)]
1220pub struct RenderMeshInstancesCpu(MainEntityHashMap<RenderMeshInstanceCpu>);
1221
1222/// Information that the render world keeps about each entity that contains a
1223/// mesh, when using GPU mesh instance data building.
1224#[derive(Default, Deref, DerefMut)]
1225pub struct RenderMeshInstancesGpu(MainEntityHashMap<RenderMeshInstanceGpu>);
1226
1227impl RenderMeshInstances {
1228    /// Creates a new [`RenderMeshInstances`] instance.
1229    fn new(use_gpu_instance_buffer_builder: bool) -> RenderMeshInstances {
1230        if use_gpu_instance_buffer_builder {
1231            RenderMeshInstances::GpuBuilding(RenderMeshInstancesGpu::default())
1232        } else {
1233            RenderMeshInstances::CpuBuilding(RenderMeshInstancesCpu::default())
1234        }
1235    }
1236
1237    /// Returns the ID of the mesh asset attached to the given entity, if any.
1238    pub fn mesh_asset_id(&self, entity: MainEntity) -> Option<AssetId<Mesh>> {
1239        match *self {
1240            RenderMeshInstances::CpuBuilding(ref instances) => instances.mesh_asset_id(entity),
1241            RenderMeshInstances::GpuBuilding(ref instances) => instances.mesh_asset_id(entity),
1242        }
1243    }
1244
1245    /// Constructs [`RenderMeshQueueData`] for the given entity, if it has a
1246    /// mesh attached.
1247    pub fn render_mesh_queue_data(&self, entity: MainEntity) -> Option<RenderMeshQueueData<'_>> {
1248        match *self {
1249            RenderMeshInstances::CpuBuilding(ref instances) => {
1250                instances.render_mesh_queue_data(entity)
1251            }
1252            RenderMeshInstances::GpuBuilding(ref instances) => {
1253                instances.render_mesh_queue_data(entity)
1254            }
1255        }
1256    }
1257
1258    /// Inserts the given flags into the CPU or GPU render mesh instance data
1259    /// for the given mesh as appropriate.
1260    fn insert_mesh_instance_flags(&mut self, entity: MainEntity, flags: RenderMeshInstanceFlags) {
1261        match *self {
1262            RenderMeshInstances::CpuBuilding(ref mut instances) => {
1263                instances.insert_mesh_instance_flags(entity, flags);
1264            }
1265            RenderMeshInstances::GpuBuilding(ref mut instances) => {
1266                instances.insert_mesh_instance_flags(entity, flags);
1267            }
1268        }
1269    }
1270}
1271
1272impl RenderMeshInstancesCpu {
1273    fn mesh_asset_id(&self, entity: MainEntity) -> Option<AssetId<Mesh>> {
1274        self.get(&entity)
1275            .map(|render_mesh_instance| render_mesh_instance.mesh_asset_id())
1276    }
1277
1278    fn render_mesh_queue_data(&self, entity: MainEntity) -> Option<RenderMeshQueueData<'_>> {
1279        self.get(&entity)
1280            .map(|render_mesh_instance| RenderMeshQueueData {
1281                shared: &render_mesh_instance.shared,
1282                render_layers: render_mesh_instance.render_layers.clone(),
1283                current_uniform_index: InputUniformIndex::default(),
1284            })
1285    }
1286
1287    /// Inserts the given flags into the render mesh instance data for the given
1288    /// mesh.
1289    fn insert_mesh_instance_flags(&mut self, entity: MainEntity, flags: RenderMeshInstanceFlags) {
1290        if let Some(instance) = self.get_mut(&entity) {
1291            instance.set_flags(instance.flags() | flags);
1292        }
1293    }
1294}
1295
1296impl RenderMeshInstancesGpu {
1297    fn mesh_asset_id(&self, entity: MainEntity) -> Option<AssetId<Mesh>> {
1298        self.get(&entity)
1299            .map(|render_mesh_instance| render_mesh_instance.mesh_asset_id())
1300    }
1301
1302    fn render_mesh_queue_data(&self, entity: MainEntity) -> Option<RenderMeshQueueData<'_>> {
1303        self.get(&entity)
1304            .map(|render_mesh_instance| RenderMeshQueueData {
1305                shared: &render_mesh_instance.shared,
1306                render_layers: render_mesh_instance.render_layers.clone(),
1307                current_uniform_index: InputUniformIndex(
1308                    render_mesh_instance.gpu_specific.current_uniform_index(),
1309                ),
1310            })
1311    }
1312
1313    /// Inserts the given flags into the render mesh instance data for the given
1314    /// mesh.
1315    fn insert_mesh_instance_flags(&mut self, entity: MainEntity, flags: RenderMeshInstanceFlags) {
1316        if let Some(instance) = self.get_mut(&entity) {
1317            instance.set_flags(instance.flags() | flags);
1318        }
1319    }
1320}
1321
1322impl RenderMeshInstanceGpuQueue {
1323    /// Clears out a [`RenderMeshInstanceGpuQueue`], creating or recreating it
1324    /// as necessary.
1325    ///
1326    /// `any_gpu_culling` should be set to true if any view has GPU culling
1327    /// enabled.
1328    fn init(&mut self, any_gpu_culling: bool) {
1329        match (any_gpu_culling, &mut *self) {
1330            (
1331                true,
1332                RenderMeshInstanceGpuQueue::GpuCulling {
1333                    changed_cpu_culling,
1334                    changed_gpu_culling,
1335                    removed,
1336                },
1337            ) => {
1338                changed_cpu_culling.clear();
1339                changed_gpu_culling.clear();
1340                removed.clear();
1341            }
1342            (true, _) => {
1343                *self = RenderMeshInstanceGpuQueue::GpuCulling {
1344                    changed_cpu_culling: vec![],
1345                    changed_gpu_culling: vec![],
1346                    removed: vec![],
1347                }
1348            }
1349            (false, RenderMeshInstanceGpuQueue::CpuCulling { changed, removed }) => {
1350                changed.clear();
1351                removed.clear();
1352            }
1353            (false, _) => {
1354                *self = RenderMeshInstanceGpuQueue::CpuCulling {
1355                    changed: vec![],
1356                    removed: vec![],
1357                }
1358            }
1359        }
1360    }
1361
1362    /// Adds a new mesh to this queue.
1363    fn push(
1364        &mut self,
1365        entity: MainEntity,
1366        instance_builder: RenderMeshInstanceGpuBuilder,
1367        culling_data_builder: Option<MeshCullingData>,
1368        no_cpu_culling: bool,
1369    ) {
1370        match (&mut *self, culling_data_builder, no_cpu_culling) {
1371            (
1372                &mut RenderMeshInstanceGpuQueue::CpuCulling {
1373                    changed: ref mut queue,
1374                    ..
1375                },
1376                None,
1377                _,
1378            ) => {
1379                queue.push((entity, instance_builder));
1380            }
1381
1382            (
1383                &mut RenderMeshInstanceGpuQueue::GpuCulling {
1384                    changed_cpu_culling: ref mut queue,
1385                    ..
1386                },
1387                Some(culling_data_builder),
1388                false,
1389            )
1390            | (
1391                &mut RenderMeshInstanceGpuQueue::GpuCulling {
1392                    changed_gpu_culling: ref mut queue,
1393                    ..
1394                },
1395                Some(culling_data_builder),
1396                true,
1397            ) => {
1398                queue.push((entity, instance_builder, culling_data_builder));
1399            }
1400
1401            (_, None, _) => {
1402                *self = RenderMeshInstanceGpuQueue::CpuCulling {
1403                    changed: vec![(entity, instance_builder)],
1404                    removed: vec![],
1405                };
1406            }
1407
1408            (_, Some(culling_data_builder), false) => {
1409                *self = RenderMeshInstanceGpuQueue::GpuCulling {
1410                    changed_cpu_culling: vec![(entity, instance_builder, culling_data_builder)],
1411                    changed_gpu_culling: vec![],
1412                    removed: vec![],
1413                };
1414            }
1415            (_, Some(culling_data_builder), true) => {
1416                *self = RenderMeshInstanceGpuQueue::GpuCulling {
1417                    changed_cpu_culling: vec![],
1418                    changed_gpu_culling: vec![(entity, instance_builder, culling_data_builder)],
1419                    removed: vec![],
1420                };
1421            }
1422        }
1423    }
1424
1425    /// Adds the given entity to the `removed` list, queuing it for removal.
1426    ///
1427    /// The `gpu_culling` parameter specifies whether GPU culling is enabled.
1428    fn remove(&mut self, entity: MainEntity, gpu_culling: bool) {
1429        match (&mut *self, gpu_culling) {
1430            (RenderMeshInstanceGpuQueue::None, false) => {
1431                *self = RenderMeshInstanceGpuQueue::CpuCulling {
1432                    changed: vec![],
1433                    removed: vec![entity],
1434                }
1435            }
1436            (RenderMeshInstanceGpuQueue::None, true) => {
1437                *self = RenderMeshInstanceGpuQueue::GpuCulling {
1438                    changed_cpu_culling: vec![],
1439                    changed_gpu_culling: vec![],
1440                    removed: vec![entity],
1441                }
1442            }
1443            (RenderMeshInstanceGpuQueue::CpuCulling { removed, .. }, _)
1444            | (RenderMeshInstanceGpuQueue::GpuCulling { removed, .. }, _) => {
1445                removed.push(entity);
1446            }
1447        }
1448    }
1449}
1450
1451impl RenderMeshInstanceGpuBuilder {
1452    /// Prepares the data needed to update the mesh instance.
1453    ///
1454    /// This is the thread-safe part of the update.
1455    fn prepare(
1456        mut self,
1457        entity: MainEntity,
1458        mesh_allocator: &MeshAllocator,
1459        mesh_material_ids: &RenderMaterialInstances,
1460        render_material_bindings: &RenderMaterialBindings,
1461        render_lightmaps: &RenderLightmaps,
1462        skin_uniforms: &SkinUniforms,
1463        morph_indices: &MorphIndices,
1464        timestamp: FrameCount,
1465    ) -> Option<RenderMeshInstanceGpuPrepared> {
1466        // Look up the material index. If we couldn't fetch the material index,
1467        // then the material hasn't been prepared yet, perhaps because it hasn't
1468        // yet loaded. In that case, we return None so that
1469        // `collect_meshes_for_gpu_building` will add the mesh to
1470        // `meshes_to_reextract_next_frame` and bail.
1471        let mesh_material = mesh_material_ids.mesh_material(entity);
1472        let mesh_material_binding_id = if let Some(mesh_material) = mesh_material {
1473            render_material_bindings.get(&mesh_material).copied()?
1474        } else {
1475            // Use a dummy material binding ID.
1476            MaterialBindingId::default()
1477        };
1478        self.shared.material_bindings_index = mesh_material_binding_id;
1479
1480        let (first_vertex_index, vertex_count) =
1481            match mesh_allocator.mesh_vertex_slice(&self.shared.asset_id.into()) {
1482                Some(mesh_vertex_slice) => (
1483                    mesh_vertex_slice.range.start,
1484                    mesh_vertex_slice.range.end - mesh_vertex_slice.range.start,
1485                ),
1486                None => (0, 0),
1487            };
1488        let (mesh_is_indexed, first_index_index, index_count) =
1489            match mesh_allocator.mesh_index_slice(&self.shared.asset_id.into()) {
1490                Some(mesh_index_slice) => (
1491                    true,
1492                    mesh_index_slice.range.start,
1493                    mesh_index_slice.range.end - mesh_index_slice.range.start,
1494                ),
1495                None => (false, 0, 0),
1496            };
1497        let current_skin_index = match skin_uniforms.skin_byte_offset(entity) {
1498            Some(skin_index) => skin_index.index(),
1499            None => u32::MAX,
1500        };
1501
1502        let lightmap_slot = match render_lightmaps.render_lightmaps.get(&entity) {
1503            Some(render_lightmap) => u16::from(*render_lightmap.slot_index),
1504            None => u16::MAX,
1505        };
1506        let lightmap_slab_index = render_lightmaps
1507            .render_lightmaps
1508            .get(&entity)
1509            .map(|lightmap| lightmap.slab_index);
1510        self.shared.lightmap_slab_index = lightmap_slab_index.into();
1511
1512        let morph_descriptor_index = match morph_indices.morph_descriptor_index(entity) {
1513            Some(morph_descriptor_index) => *morph_descriptor_index,
1514            None => u32::MAX,
1515        };
1516
1517        let metadata_index = mesh_allocator
1518            .mesh_metadata_slice(&self.shared.asset_id.into())
1519            .map(|mesh_metadata_slice| mesh_metadata_slice.range.start)
1520            .unwrap_or(0);
1521
1522        // Create the mesh input uniform.
1523        let material_slot = u32::from(self.shared.material_bindings_index.slot);
1524        debug_assert!(
1525            material_slot <= 0xFFFF,
1526            "Material bind group slot {material_slot} overflowed"
1527        );
1528        let material_and_lightmap_bind_group_slot = material_slot | ((lightmap_slot as u32) << 16);
1529
1530        let mesh_input_uniform = MeshInputUniform {
1531            world_from_local: self.world_from_local.to_transpose(),
1532            lightmap_uv_rect: self.lightmap_uv_rect,
1533            flags: self.mesh_flags.bits(),
1534            previous_input_index: u32::MAX,
1535            timestamp: timestamp.0,
1536            first_vertex_index,
1537            first_index_index,
1538            index_count: if mesh_is_indexed {
1539                index_count
1540            } else {
1541                vertex_count
1542            },
1543            current_skin_index,
1544            material_and_lightmap_bind_group_slot,
1545            tag: self.shared.tag,
1546            morph_descriptor_index,
1547            metadata_index,
1548            ..Default::default()
1549        };
1550
1551        Some(RenderMeshInstanceGpuPrepared {
1552            shared: self.shared,
1553            mesh_input_uniform,
1554            render_layers: self.render_layers,
1555        })
1556    }
1557}
1558
1559/// Data needed to construct the [`RenderMeshInstanceGpu`] for a mesh instance.
1560pub struct RenderMeshInstanceGpuPrepared {
1561    /// Data shared between the CPU and GPU versions of this mesh instance.
1562    shared: RenderMeshInstanceSharedFlat,
1563    /// The data that will be uploaded to the GPU as a [`MeshInputUniform`].
1564    mesh_input_uniform: MeshInputUniform,
1565    /// The render layers that this mesh instance belongs to.
1566    render_layers: Option<RenderLayers>,
1567}
1568
1569impl RenderMeshInstanceGpuPrepared {
1570    /// Flushes this mesh instance to the [`RenderMeshInstanceGpu`] and
1571    /// [`MeshInputUniform`] tables, replacing the existing entry if applicable.
1572    fn update(
1573        mut self,
1574        entity: MainEntity,
1575        render_mesh_instances: &mut MainEntityHashMap<RenderMeshInstanceGpu>,
1576        current_input_buffer: &mut InstanceInputUniformBuffer<MeshInputUniform>,
1577        previous_input_buffer: &PreviousInstanceInputUniformBuffer<PreviousMeshInputUniform>,
1578    ) -> u32 {
1579        // Did the last frame contain this entity as well?
1580        let current_uniform_index;
1581        match render_mesh_instances.entry(entity) {
1582            Entry::Occupied(mut occupied_entry) => {
1583                // Yes, it did. Replace its entry with the new one.
1584
1585                // Reserve a slot.
1586                current_uniform_index = occupied_entry
1587                    .get_mut()
1588                    .gpu_specific
1589                    .current_uniform_index();
1590
1591                // Save the old mesh transform. The mesh preprocessing shader
1592                // will need it to compute motion vectors.
1593                let previous_world_from_local = current_input_buffer
1594                    .get_unchecked(current_uniform_index)
1595                    .world_from_local;
1596                let previous_input_index = previous_input_buffer.push(PreviousMeshInputUniform {
1597                    world_from_local: previous_world_from_local,
1598                });
1599                self.mesh_input_uniform.previous_input_index = previous_input_index;
1600
1601                // Write in the new mesh input uniform.
1602                current_input_buffer.set(current_uniform_index, self.mesh_input_uniform);
1603
1604                // Write the instance.
1605                let existing_instance = occupied_entry.get_mut();
1606                self.shared.write_to_blob(&existing_instance.shared);
1607                existing_instance
1608                    .gpu_specific
1609                    .set_current_uniform_index(current_uniform_index);
1610                existing_instance.render_layers = self.render_layers.clone();
1611            }
1612
1613            Entry::Vacant(vacant_entry) => {
1614                // No, this is a new entity. Push its data on to the buffer.
1615                current_uniform_index = current_input_buffer.add(self.mesh_input_uniform);
1616
1617                let new_instance = vacant_entry.insert(RenderMeshInstanceGpu {
1618                    shared: RenderMeshInstanceSharedFlatBlob::default(),
1619                    gpu_specific: RenderMeshInstanceGpuFlatBlob::default(),
1620                    render_layers: self.render_layers.clone(),
1621                });
1622                self.shared.write_to_blob(&new_instance.shared);
1623                RenderMeshInstanceGpuFlat {
1624                    current_uniform_index,
1625                }
1626                .write_to_blob(&new_instance.gpu_specific);
1627            }
1628        }
1629
1630        current_uniform_index
1631    }
1632}
1633
1634/// Removes a [`MeshInputUniform`] corresponding to an entity that became
1635/// invisible from the buffer.
1636fn remove_mesh_input_uniform(
1637    entity: MainEntity,
1638    render_mesh_instances: &mut MainEntityHashMap<RenderMeshInstanceGpu>,
1639    current_input_buffer: &mut InstanceInputUniformBuffer<MeshInputUniform>,
1640) -> Option<u32> {
1641    // Remove the uniform data.
1642    let removed_render_mesh_instance = render_mesh_instances.remove(&entity)?;
1643
1644    let removed_uniform_index = removed_render_mesh_instance
1645        .gpu_specific
1646        .current_uniform_index();
1647    current_input_buffer.remove(removed_uniform_index);
1648    Some(removed_uniform_index)
1649}
1650
1651impl MeshCullingData {
1652    /// Returns a new [`MeshCullingData`] initialized with the given AABB.
1653    ///
1654    /// If no AABB is provided, an infinitely-large one is conservatively
1655    /// chosen.
1656    fn new(aabb: Option<&Aabb>) -> Self {
1657        match aabb {
1658            Some(aabb) => MeshCullingData {
1659                aabb_center: aabb.center.extend(0.0),
1660                aabb_half_extents: aabb.half_extents.extend(0.0),
1661            },
1662            None => MeshCullingData {
1663                aabb_center: Vec3::ZERO.extend(0.0),
1664                aabb_half_extents: Vec3::INFINITY.extend(0.0),
1665            },
1666        }
1667    }
1668
1669    /// Flushes this mesh instance culling data to the
1670    /// [`MeshCullingDataBuffer`], replacing the existing entry if applicable.
1671    fn update(
1672        &self,
1673        mesh_culling_data_buffer: &mut MeshCullingDataBuffer,
1674        instance_data_index: u32,
1675    ) {
1676        while mesh_culling_data_buffer.len() < instance_data_index + 1 {
1677            mesh_culling_data_buffer.push(MeshCullingData::default());
1678        }
1679        mesh_culling_data_buffer.set(instance_data_index, *self);
1680    }
1681}
1682
1683impl Default for MeshCullingDataBuffer {
1684    #[inline]
1685    fn default() -> Self {
1686        Self(AtomicSparseBufferVec::new(
1687            BufferUsages::STORAGE,
1688            Arc::from("mesh culling data buffer"),
1689        ))
1690    }
1691}
1692
1693/// Data that [`crate::material::queue_material_meshes`] and similar systems
1694/// need in order to place entities that contain meshes in the right batch.
1695#[derive(Deref)]
1696pub struct RenderMeshQueueData<'a> {
1697    /// General information about the mesh instance.
1698    #[deref]
1699    pub shared: &'a RenderMeshInstanceSharedFlatBlob,
1700    /// The render layers that this mesh instance belongs to.
1701    pub render_layers: Option<RenderLayers>,
1702    /// The index of the [`MeshInputUniform`] in the GPU buffer for this mesh
1703    /// instance.
1704    pub current_uniform_index: InputUniformIndex,
1705}
1706
1707/// A [`SystemSet`] that encompasses both [`extract_meshes_for_cpu_building`]
1708/// and [`extract_meshes_for_gpu_building`].
1709#[derive(SystemSet, Clone, PartialEq, Eq, Debug, Hash)]
1710pub struct MeshExtractionSystems;
1711
1712/// A resource, part of the render world, that stores all entities that are
1713/// potentially-visible and have [`NoCpuCulling`] components.
1714///
1715/// Even though this resource exists, individual views still have their own
1716/// lists of all GPU-culled entities, because render layers can alter the set of
1717/// entities visible to each view.
1718#[derive(Resource, Default)]
1719pub struct RenderGpuCulledEntities {
1720    /// A mapping from each potentially-visible entity to the render layers it's
1721    /// part of.
1722    pub entities: MainEntityHashMap<RenderLayers>,
1723
1724    /// A list of all entities with GPU culling (and no CPU culling) that became
1725    /// potentially visible in some view this frame.
1726    ///
1727    /// This also includes entities that changed from CPU culling to GPU
1728    /// culling.
1729    ///
1730    /// Unlike the corresponding field in
1731    /// [`bevy_render::view::visibility::RenderVisibleEntitiesClass`], this list
1732    /// is *not* necessarily sorted.
1733    pub added: Vec<MainEntity>,
1734
1735    /// A list of all entities with GPU culling that were either despawned or
1736    /// otherwise became definitely invisible this frame.
1737    ///
1738    /// This also includes entities that changed from GPU culling to CPU culling.
1739    ///
1740    /// Unlike the corresponding field in
1741    /// [`bevy_render::view::visibility::RenderVisibleEntitiesClass`], this list
1742    /// is *not* necessarily sorted.
1743    pub removed: Vec<MainEntity>,
1744
1745    /// A list of all entities with GPU culling that changed the set of render
1746    /// layers they belong to this frame.
1747    pub changed_layers: Vec<MainEntity>,
1748}
1749
1750impl RenderGpuCulledEntities {
1751    /// Clears out the sets of newly-added entities, newly-removed entities, and
1752    /// entities that newly changed render layers in preparation for a new
1753    /// frame.
1754    pub fn prepare_for_new_frame(&mut self) {
1755        self.added.clear();
1756        self.removed.clear();
1757        self.changed_layers.clear();
1758    }
1759
1760    /// Records that an entity became newly-visible or changed its set of layers
1761    /// this frame.
1762    ///
1763    /// The `render_layers` argument specifies the set of render layers that the
1764    /// entity belongs to.
1765    ///
1766    /// Note that this method is only called for entities that the extraction
1767    /// systems picked up this frame, so the extraction change detection must be
1768    /// configured to catch render layer changes (see
1769    /// `extract_meshes_for_gpu_building`) in order for layer changes on
1770    /// GPU-culled meshes to propagate.
1771    pub fn update(
1772        &mut self,
1773        new_entity: MainEntity,
1774        render_layers: RenderLayers,
1775        no_cpu_culling: bool,
1776    ) {
1777        match self.entities.entry(new_entity) {
1778            Entry::Occupied(mut occupied_entry) => {
1779                if no_cpu_culling {
1780                    if *occupied_entry.get() != render_layers {
1781                        self.changed_layers.push(new_entity);
1782                    }
1783
1784                    occupied_entry.insert(render_layers);
1785                } else {
1786                    occupied_entry.remove();
1787                    self.removed.push(new_entity);
1788                }
1789            }
1790            Entry::Vacant(vacant_entry) => {
1791                if no_cpu_culling {
1792                    vacant_entry.insert(render_layers);
1793                    self.added.push(new_entity);
1794                }
1795            }
1796        }
1797    }
1798
1799    /// Records that an entity became newly-invisible this frame.
1800    pub fn remove(&mut self, old_entity: MainEntity) {
1801        self.removed.push(old_entity);
1802        self.entities.remove(&old_entity);
1803    }
1804}
1805
1806/// Extracts meshes from the main world into the render world, populating the
1807/// [`RenderMeshInstances`].
1808///
1809/// This is the variant of the system that runs when we're *not* using GPU
1810/// [`MeshUniform`] building.
1811pub fn extract_meshes_for_cpu_building(
1812    mut render_mesh_instances: ResMut<RenderMeshInstances>,
1813    mesh_material_ids: Res<RenderMaterialInstances>,
1814    render_material_bindings: Res<RenderMaterialBindings>,
1815    render_visibility_ranges: Res<RenderVisibilityRanges>,
1816    mut render_mesh_instance_queues: Local<Parallel<Vec<(Entity, RenderMeshInstanceCpu)>>>,
1817    meshes_query: Extract<
1818        Query<(
1819            Entity,
1820            &ViewVisibility,
1821            &GlobalTransform,
1822            Option<&PreviousGlobalTransform>,
1823            &Mesh3d,
1824            Option<&MeshTag>,
1825            Has<NoFrustumCulling>,
1826            Has<NotShadowReceiver>,
1827            Has<TransmittedShadowReceiver>,
1828            Has<NotShadowCaster>,
1829            Has<NoAutomaticBatching>,
1830            Option<&VisibilityRange>,
1831            Option<&RenderLayers>,
1832        )>,
1833    >,
1834) {
1835    meshes_query.par_iter().for_each_init(
1836        || render_mesh_instance_queues.borrow_local_mut(),
1837        |queue,
1838         (
1839            entity,
1840            view_visibility,
1841            transform,
1842            previous_transform,
1843            mesh,
1844            tag,
1845            no_frustum_culling,
1846            not_shadow_receiver,
1847            transmitted_receiver,
1848            not_shadow_caster,
1849            no_automatic_batching,
1850            visibility_range,
1851            render_layers,
1852        )| {
1853            if !view_visibility.get() {
1854                return;
1855            }
1856
1857            let mut lod_index = None;
1858            if visibility_range.is_some() {
1859                lod_index = render_visibility_ranges.lod_index_for_entity(entity.into());
1860            }
1861
1862            let mesh_flags = MeshFlags::from_components(
1863                transform,
1864                lod_index,
1865                visibility_range,
1866                no_frustum_culling,
1867                not_shadow_receiver,
1868                transmitted_receiver,
1869            );
1870
1871            let mesh_material = mesh_material_ids.mesh_material(MainEntity::from(entity));
1872
1873            let material_bindings_index = mesh_material
1874                .and_then(|mesh_material| render_material_bindings.get(&mesh_material).copied())
1875                .unwrap_or_default();
1876
1877            let shared = RenderMeshInstanceSharedFlat::for_cpu_building(
1878                previous_transform,
1879                mesh,
1880                tag,
1881                material_bindings_index,
1882                not_shadow_caster,
1883                no_automatic_batching,
1884            );
1885
1886            let world_from_local = transform.affine();
1887            let previous_world_from_local = previous_transform
1888                .map(|previous_transform| previous_transform.0)
1889                .unwrap_or(world_from_local);
1890
1891            queue.push((
1892                entity,
1893                RenderMeshInstanceCpu {
1894                    transforms: MeshTransforms {
1895                        world_from_local: world_from_local.into(),
1896                        previous_world_from_local: previous_world_from_local.into(),
1897                        flags: mesh_flags.bits(),
1898                    },
1899                    shared: (&shared).into(),
1900                    render_layers: render_layers.cloned(),
1901                },
1902            ));
1903        },
1904    );
1905
1906    // Collect the render mesh instances.
1907    let RenderMeshInstances::CpuBuilding(ref mut render_mesh_instances) = *render_mesh_instances
1908    else {
1909        panic!(
1910            "`extract_meshes_for_cpu_building` should only be called if we're using CPU \
1911            `MeshUniform` building"
1912        );
1913    };
1914
1915    render_mesh_instances.clear();
1916    for queue in render_mesh_instance_queues.iter_mut() {
1917        for (entity, render_mesh_instance) in queue.drain(..) {
1918            render_mesh_instances.insert(entity.into(), render_mesh_instance);
1919        }
1920    }
1921}
1922
1923/// All the data that we need from a mesh in the main world.
1924type GpuMeshExtractionQuery = (
1925    Entity,
1926    Read<ViewVisibility>,
1927    Read<GlobalTransform>,
1928    Option<Read<PreviousGlobalTransform>>,
1929    Option<Read<Lightmap>>,
1930    Option<Read<Aabb>>,
1931    Read<Mesh3d>,
1932    Option<Read<MeshTag>>,
1933    (
1934        Has<NoFrustumCulling>,
1935        Has<NotShadowReceiver>,
1936        Has<TransmittedShadowReceiver>,
1937        Has<NotShadowCaster>,
1938        Has<NoAutomaticBatching>,
1939        Has<NoCpuCulling>,
1940    ),
1941    Option<Read<VisibilityRange>>,
1942    Option<Read<RenderLayers>>,
1943);
1944
1945/// Extracts meshes from the main world to thread-local buffers in the render
1946/// world.
1947///
1948/// This is optimized to only look at entities that have changed since the last
1949/// frame.
1950///
1951/// This is the variant of the system that runs when we're using GPU
1952/// [`MeshUniform`] building.
1953pub fn extract_meshes_for_gpu_building(
1954    mut render_mesh_instances: ResMut<RenderMeshInstances>,
1955    render_visibility_ranges: Res<RenderVisibilityRanges>,
1956    mut render_mesh_instance_queues: ResMut<RenderMeshInstanceGpuQueues>,
1957    changed_meshes_query: Extract<
1958        Query<
1959            GpuMeshExtractionQuery,
1960            Or<(
1961                Changed<ViewVisibility>,
1962                Changed<GlobalTransform>,
1963                Changed<PreviousGlobalTransform>,
1964                Changed<Lightmap>,
1965                Changed<Aabb>,
1966                Changed<Mesh3d>,
1967                Changed<MeshTag>,
1968                Or<(
1969                    Changed<NoFrustumCulling>,
1970                    Changed<NotShadowReceiver>,
1971                    Changed<TransmittedShadowReceiver>,
1972                    Changed<NotShadowCaster>,
1973                    Changed<NoAutomaticBatching>,
1974                    Changed<NoCpuCulling>,
1975                )>,
1976                Changed<VisibilityRange>,
1977                Changed<SkinnedMesh>,
1978                Changed<RenderLayers>,
1979            )>,
1980        >,
1981    >,
1982    (
1983        mut removed_previous_global_transform_query,
1984        mut removed_lightmap_query,
1985        mut removed_aabb_query,
1986        mut removed_mesh_tag_query,
1987        mut removed_no_frustum_culling_query,
1988        mut removed_not_shadow_receiver_query,
1989        mut removed_transmitted_receiver_query,
1990        mut removed_not_shadow_caster_query,
1991        mut removed_no_automatic_batching_query,
1992        mut removed_no_cpu_culling_query,
1993        mut removed_visibility_range_query,
1994        mut removed_skinned_mesh_query,
1995        mut removed_render_layers_query,
1996    ): (
1997        Extract<RemovedComponents<PreviousGlobalTransform>>,
1998        Extract<RemovedComponents<Lightmap>>,
1999        Extract<RemovedComponents<Aabb>>,
2000        Extract<RemovedComponents<MeshTag>>,
2001        Extract<RemovedComponents<NoFrustumCulling>>,
2002        Extract<RemovedComponents<NotShadowReceiver>>,
2003        Extract<RemovedComponents<TransmittedShadowReceiver>>,
2004        Extract<RemovedComponents<NotShadowCaster>>,
2005        Extract<RemovedComponents<NoAutomaticBatching>>,
2006        Extract<RemovedComponents<NoCpuCulling>>,
2007        Extract<RemovedComponents<VisibilityRange>>,
2008        Extract<RemovedComponents<SkinnedMesh>>,
2009        Extract<RemovedComponents<RenderLayers>>,
2010    ),
2011    all_meshes_query: Extract<Query<GpuMeshExtractionQuery>>,
2012    mut removed_meshes_query: Extract<RemovedComponents<Mesh3d>>,
2013    gpu_culling_query: Extract<Query<(), (With<Camera>, Without<NoIndirectDrawing>)>>,
2014    meshes_to_reextract_next_frame: ResMut<MeshesToReextractNextFrame>,
2015    mut reextract_entities: Local<EntityHashSet>,
2016    mut potential_reextraction_set: Local<IndexSet<Entity, EntityHash>>,
2017    mut potential_reextraction_bitfield: Local<Vec<AtomicU64>>,
2018) {
2019    reextract_entities.clear();
2020
2021    // Initialize the queues.
2022    let any_gpu_culling = !gpu_culling_query.is_empty();
2023    for render_mesh_instance_queue in render_mesh_instance_queues.iter_mut() {
2024        render_mesh_instance_queue.init(any_gpu_culling);
2025    }
2026
2027    // Process materials that `collect_meshes_for_gpu_building` marked as
2028    // needing to be reextracted. This will happen when we extracted a mesh on
2029    // some previous frame, but its material hadn't been prepared yet, perhaps
2030    // because the material hadn't yet been loaded. We reextract such materials
2031    // on subsequent frames so that `collect_meshes_for_gpu_building` will check
2032    // to see if their materials have been prepared.
2033    potential_reextraction_set.clear();
2034    potential_reextraction_set.extend(
2035        meshes_to_reextract_next_frame
2036            .iter()
2037            .map(|&e| *e)
2038            .chain(removed_previous_global_transform_query.read())
2039            .chain(removed_lightmap_query.read())
2040            .chain(removed_aabb_query.read())
2041            .chain(removed_mesh_tag_query.read())
2042            .chain(removed_no_frustum_culling_query.read())
2043            .chain(removed_not_shadow_receiver_query.read())
2044            .chain(removed_transmitted_receiver_query.read())
2045            .chain(removed_not_shadow_caster_query.read())
2046            .chain(removed_no_automatic_batching_query.read())
2047            .chain(removed_no_cpu_culling_query.read())
2048            .chain(removed_visibility_range_query.read())
2049            .chain(removed_skinned_mesh_query.read())
2050            .chain(removed_render_layers_query.read()),
2051    );
2052
2053    // We have to skip the meshes in the potential reextraction set if we
2054    // encounter them during the `changed_meshes_query` below. But, because
2055    // `changed_meshes_query` is currently a full table scan, we don't want to
2056    // have to query it multiple times. So we instead represent the potential
2057    // reextraction set as a bitfield and set the bit corresponding to an entity
2058    // as we encounter that entity below.
2059    potential_reextraction_bitfield.clear();
2060    potential_reextraction_bitfield.extend(
2061        iter::repeat_with(|| AtomicU64::new(0)).take(potential_reextraction_set.len().div_ceil(64)),
2062    );
2063
2064    // Collect render mesh instances. Build up the uniform buffer.
2065
2066    let RenderMeshInstances::GpuBuilding(ref mut render_mesh_instances) = *render_mesh_instances
2067    else {
2068        panic!(
2069            "`extract_meshes_for_gpu_building` should only be called if we're \
2070            using GPU `MeshUniform` building"
2071        );
2072    };
2073
2074    // Find all meshes that have changed, and record information needed to
2075    // construct the `MeshInputUniform` for them.
2076    changed_meshes_query.par_iter().for_each_init(
2077        || render_mesh_instance_queues.borrow_local_mut(),
2078        |queue, query_row| {
2079            extract_mesh_for_gpu_building(
2080                query_row,
2081                &render_visibility_ranges,
2082                render_mesh_instances,
2083                queue,
2084                any_gpu_culling,
2085            );
2086
2087            // If this entity was in the potential reextraction set, set the
2088            // appropriate bit.
2089            if let Some(bit_index) = potential_reextraction_set.get_index_of(&query_row.0) {
2090                potential_reextraction_bitfield[bit_index / 64]
2091                    .fetch_or(1 << (bit_index % 64), Ordering::Relaxed);
2092            }
2093        },
2094    );
2095
2096    // Add the entities in the potential reextraction set to the
2097    // `reextract_entities` list, unless we saw them in the query above.
2098    //
2099    // Note that this will likely iterate over some spurious zero bits at the
2100    // end, since we rounded the number of elements to potentially reextract up
2101    // to the nearest multiple of 64. But that's OK, because we check to see
2102    // whether the indices exist in the potential reextraction set before adding
2103    // the corresponding entities to the `reextract_entities` list.
2104    for bit in AtomicU64ZeroBitIter::new(&potential_reextraction_bitfield) {
2105        if let Some(entity) = potential_reextraction_set.get_index(bit as usize) {
2106            reextract_entities.insert(*entity);
2107        }
2108    }
2109
2110    // Reextract meshes we marked as needing to be reextracted.
2111    let mut queue = render_mesh_instance_queues.borrow_local_mut();
2112    for entity in &reextract_entities {
2113        if let Ok(query_row) = all_meshes_query.get(*entity) {
2114            extract_mesh_for_gpu_building(
2115                query_row,
2116                &render_visibility_ranges,
2117                render_mesh_instances,
2118                &mut queue,
2119                any_gpu_culling,
2120            );
2121        }
2122    }
2123
2124    // Also record info about each mesh that became invisible.
2125    for entity in removed_meshes_query.read() {
2126        // Only queue a mesh for removal if we didn't pick it up above.
2127        // It's possible that a necessary component was removed and re-added in
2128        // the same frame.
2129        let entity = MainEntity::from(entity);
2130        if !changed_meshes_query.contains(*entity)
2131            && !meshes_to_reextract_next_frame.contains(&entity)
2132        {
2133            queue.remove(entity, any_gpu_culling);
2134        }
2135    }
2136}
2137
2138/// Extracts a single mesh from the main world to a thread-local buffer in the
2139/// render world.
2140fn extract_mesh_for_gpu_building(
2141    (
2142        entity,
2143        view_visibility,
2144        transform,
2145        previous_transform,
2146        lightmap,
2147        aabb,
2148        mesh,
2149        tag,
2150        (
2151            no_frustum_culling,
2152            not_shadow_receiver,
2153            transmitted_receiver,
2154            not_shadow_caster,
2155            no_automatic_batching,
2156            no_cpu_culling,
2157        ),
2158        visibility_range,
2159        render_layers,
2160    ): <GpuMeshExtractionQuery as QueryData>::Item<'_, '_>,
2161    render_visibility_ranges: &RenderVisibilityRanges,
2162    render_mesh_instances: &RenderMeshInstancesGpu,
2163    queue: &mut RenderMeshInstanceGpuQueue,
2164    any_gpu_culling: bool,
2165) {
2166    // If the entity is invisible, remove it.
2167    if !view_visibility.get() {
2168        queue.remove(entity.into(), any_gpu_culling);
2169        return;
2170    }
2171
2172    // If the entity has a visibility range, determine its LOD index.
2173    let mut lod_index = None;
2174    if visibility_range.is_some() {
2175        lod_index = render_visibility_ranges.lod_index_for_entity(entity.into());
2176    }
2177
2178    // Calculate the mesh flags.
2179    let mesh_flags = MeshFlags::from_components(
2180        transform,
2181        lod_index,
2182        visibility_range,
2183        no_frustum_culling,
2184        not_shadow_receiver,
2185        transmitted_receiver,
2186    );
2187
2188    // Calculate shared mesh data.
2189    let shared = RenderMeshInstanceSharedFlat::for_gpu_building(
2190        previous_transform,
2191        mesh,
2192        tag,
2193        not_shadow_caster,
2194        no_automatic_batching,
2195        no_cpu_culling,
2196    );
2197
2198    // Calculate the lightmap UV rect, if applicable.
2199    let lightmap_uv_rect = pack_lightmap_uv_rect(lightmap.map(|lightmap| lightmap.uv_rect));
2200
2201    // Calculate data needed to cull the mesh on GPU.
2202    let gpu_mesh_culling_data = any_gpu_culling.then(|| MeshCullingData::new(aabb));
2203
2204    // Determine where the mesh was in the buffer on the previous frame, if
2205    // applicable. This is used for motion vector computation.
2206    let previous_input_index = if shared
2207        .flags
2208        .contains(RenderMeshInstanceFlags::HAS_PREVIOUS_TRANSFORM)
2209    {
2210        render_mesh_instances
2211            .get(&MainEntity::from(entity))
2212            .and_then(|render_mesh_instance| {
2213                NonMaxU32::new(render_mesh_instance.gpu_specific.current_uniform_index())
2214            })
2215    } else {
2216        None
2217    };
2218
2219    // Gather up all the data needed to update the GPU buffers in
2220    // `collect_meshes_for_gpu_building`.
2221    let gpu_mesh_instance_builder = RenderMeshInstanceGpuBuilder {
2222        shared,
2223        world_from_local: (transform.affine()).into(),
2224        lightmap_uv_rect,
2225        mesh_flags,
2226        previous_input_index,
2227        render_layers: render_layers.cloned(),
2228    };
2229
2230    // Push that data onto the queue.
2231    queue.push(
2232        entity.into(),
2233        gpu_mesh_instance_builder,
2234        gpu_mesh_culling_data,
2235        no_cpu_culling,
2236    );
2237}
2238
2239/// An iterator over the 0 positions in an array of atomic words.
2240struct AtomicU64ZeroBitIter<'a> {
2241    /// The slice of atomic words.
2242    bits: &'a [AtomicU64],
2243    /// The current word.
2244    ///
2245    /// We change bits from 0 to 1 as we encounter them.
2246    current_word: u64,
2247    /// The index of the word after [`Self::current_word`].
2248    next_index: usize,
2249}
2250
2251impl<'a> AtomicU64ZeroBitIter<'a> {
2252    /// Creates a new [`AtomicU64ZeroBitIter`] ready to iterate over the given
2253    /// bits.
2254    fn new(bits: &'a [AtomicU64]) -> AtomicU64ZeroBitIter<'a> {
2255        AtomicU64ZeroBitIter {
2256            bits,
2257            current_word: !0,
2258            next_index: 0,
2259        }
2260    }
2261}
2262
2263impl<'a> Iterator for AtomicU64ZeroBitIter<'a> {
2264    type Item = u32;
2265
2266    fn next(&mut self) -> Option<Self::Item> {
2267        // Repeatedly load the next word if we're out of zero bits in this one.
2268        while self.current_word == !0 {
2269            self.current_word = self.bits.get(self.next_index)?.load(Ordering::Relaxed);
2270            self.next_index += 1;
2271        }
2272
2273        // Find the next zero bit index.
2274        let bit_index = self.current_word.trailing_ones();
2275        self.current_word |= 1 << bit_index;
2276        let word_index = ((self.next_index - 1) * 64) as u32;
2277        Some(word_index + bit_index)
2278    }
2279}
2280
2281/// Transfers entities from [`RenderGpuCulledEntities`] to the
2282/// [`RenderVisibleEntities`] and [`RenderShadowMapVisibleEntities`] components
2283/// on each view.
2284///
2285/// Each view must maintain a separate list of GPU-culled entities because the
2286/// views and entities might belong to different render layers.
2287pub fn collect_gpu_culled_meshes(
2288    mut cameras: Query<(Option<&RenderLayers>, &mut RenderVisibleEntities), With<ExtractedView>>,
2289    mut lights: Query<(Option<&RenderLayers>, &mut RenderShadowMapVisibleEntities)>,
2290    render_gpu_culled_entities: Res<RenderGpuCulledEntities>,
2291) {
2292    let default_render_layers = RenderLayers::default();
2293
2294    // Collect cameras.
2295    for (maybe_render_layers, mut render_visible_entities) in &mut cameras {
2296        let just_added_render_visible_entities = render_visible_entities.is_added();
2297        collect_gpu_culled_meshes_for_subview(
2298            maybe_render_layers.unwrap_or(&default_render_layers),
2299            &mut render_visible_entities,
2300            just_added_render_visible_entities,
2301            &render_gpu_culled_entities,
2302        );
2303    }
2304
2305    // Collect shadow maps.
2306    for (maybe_render_layers, mut render_shadow_map_visible_entities) in &mut lights {
2307        let last_run = render_shadow_map_visible_entities.last_run();
2308        let this_run = render_shadow_map_visible_entities.this_run();
2309
2310        for (render_visible_entities_added_tick, render_visible_entities) in
2311            render_shadow_map_visible_entities.subviews.values_mut()
2312        {
2313            collect_gpu_culled_meshes_for_subview(
2314                maybe_render_layers.unwrap_or(&default_render_layers),
2315                render_visible_entities,
2316                render_visible_entities_added_tick.is_newer_than(last_run, this_run),
2317                &render_gpu_culled_entities,
2318            );
2319        }
2320    }
2321}
2322
2323/// Transfers entities from [`RenderGpuCulledEntities`] to the
2324/// [`RenderVisibleEntities`] object for each view or subview.
2325///
2326/// This only processes meshes that have [`NoCpuCulling`] components. The
2327/// corresponding function for entities that are culled on CPU is
2328/// `collect_visible_cpu_culled_entities_for_subview`.
2329fn collect_gpu_culled_meshes_for_subview(
2330    view_render_layers: &RenderLayers,
2331    render_visible_entities: &mut RenderVisibleEntities,
2332    just_added_render_visible_entities: bool,
2333    render_mesh_instance_gpu_queues: &RenderGpuCulledEntities,
2334) {
2335    let is_entity_relevant =
2336        |render_layers: &RenderLayers| -> bool { view_render_layers.intersects(render_layers) };
2337
2338    // Only 3D meshes can be culled on GPU at the moment.
2339    let render_view_visible_mesh_entities = render_visible_entities
2340        .classes
2341        .entry(TypeId::of::<Mesh3d>())
2342        .or_default();
2343
2344    // `RenderGpuCulledEntities` is a global resource that only cares about this frame changed renderables, so when the camera is spawned later, this per frame information is gone.
2345    // So we do a full flush on the `RenderVisibleEntities` whenever it just got added
2346    if just_added_render_visible_entities {
2347        // We assume `RenderVisibleEntities` is completely fresh so there will only be new entities
2348        for (main_entity, render_layers) in render_mesh_instance_gpu_queues.entities.iter() {
2349            if is_entity_relevant(render_layers) {
2350                // Update the tables. 3D meshes have no render entity, so it's
2351                // appropriate to use `Entity::PLACEHOLDER` here.
2352                render_view_visible_mesh_entities
2353                    .entities_gpu_culling
2354                    .insert(*main_entity, Entity::PLACEHOLDER);
2355                render_view_visible_mesh_entities
2356                    .added_entities
2357                    .push((Entity::PLACEHOLDER, *main_entity));
2358            }
2359        }
2360
2361        render_view_visible_mesh_entities.sort_added_entities();
2362    } else {
2363        // Update the list with entities that were removed.
2364        for main_entity in &render_mesh_instance_gpu_queues.removed {
2365            if render_view_visible_mesh_entities
2366                .entities_gpu_culling
2367                .remove(main_entity)
2368                .is_some()
2369            {
2370                render_view_visible_mesh_entities
2371                    .removed_entities
2372                    .push((Entity::PLACEHOLDER, *main_entity));
2373            }
2374        }
2375
2376        // Update the list with entities that became newly visible.
2377        let mut any_added = false;
2378        for main_entity in &render_mesh_instance_gpu_queues.added {
2379            // Make sure the entity belongs to our set of render layers.
2380            let maybe_render_layers = render_mesh_instance_gpu_queues.entities.get(main_entity);
2381            if maybe_render_layers.is_none_or(is_entity_relevant) {
2382                // Update the tables. 3D meshes have no render entity, so it's
2383                // appropriate to use `Entity::PLACEHOLDER` here.
2384                render_view_visible_mesh_entities
2385                    .entities_gpu_culling
2386                    .insert(*main_entity, Entity::PLACEHOLDER);
2387                render_view_visible_mesh_entities
2388                    .added_entities
2389                    .push((Entity::PLACEHOLDER, *main_entity));
2390                any_added = true;
2391            }
2392        }
2393
2394        // Process entities that changed layers.
2395        for main_entity in &render_mesh_instance_gpu_queues.changed_layers {
2396            let Some(render_layers) = render_mesh_instance_gpu_queues.entities.get(main_entity)
2397            else {
2398                continue;
2399            };
2400
2401            // This is either treated as no change, as an addition, or as a removal.
2402            let entity_was_relevant = render_view_visible_mesh_entities
2403                .entities_gpu_culling
2404                .contains_key(main_entity);
2405            let entity_is_relevant = is_entity_relevant(render_layers);
2406            match (entity_was_relevant, entity_is_relevant) {
2407                (false, false) | (true, true) => {
2408                    // No change; do nothing.
2409                }
2410                (false, true) => {
2411                    // The entity became visible. This is an addition.
2412                    render_view_visible_mesh_entities
2413                        .entities_gpu_culling
2414                        .insert(*main_entity, Entity::PLACEHOLDER);
2415                    render_view_visible_mesh_entities
2416                        .added_entities
2417                        .push((Entity::PLACEHOLDER, *main_entity));
2418                    any_added = true;
2419                }
2420                (true, false) => {
2421                    // The entity became invisible. This is a removal.
2422                    render_view_visible_mesh_entities
2423                        .entities_gpu_culling
2424                        .remove(main_entity);
2425                    render_view_visible_mesh_entities
2426                        .removed_entities
2427                        .push((Entity::PLACEHOLDER, *main_entity));
2428                }
2429            }
2430        }
2431
2432        // Make sure the `added_entities` list is sorted, as the
2433        // `DirtySpecializations` iterator will binary search it.
2434        if any_added {
2435            render_view_visible_mesh_entities.sort_added_entities();
2436        }
2437    }
2438}
2439
2440/// A system that sets the [`RenderMeshInstanceFlags`] for each mesh based on
2441/// whether the previous frame had skins and/or morph targets.
2442///
2443/// Ordinarily, [`RenderMeshInstanceFlags`] are set during the extraction phase.
2444/// However, we can't do that for the flags related to skins and morph targets
2445/// because the previous frame's skin and morph targets are the responsibility
2446/// of [`extract_skins`] and [`extract_morphs`] respectively. We want to run
2447/// those systems in parallel with mesh extraction for performance, so we need
2448/// to defer setting of these mesh instance flags to after extraction, which
2449/// this system does. An alternative to having skin- and morph-target-related
2450/// data in [`RenderMeshInstanceFlags`] would be to have
2451/// [`crate::material::queue_material_meshes`] check the skin and morph target
2452/// tables for each mesh, but that would be too slow in the hot mesh queuing
2453/// loop.
2454pub fn set_mesh_motion_vector_flags(
2455    mut render_mesh_instances: ResMut<RenderMeshInstances>,
2456    skin_uniforms: Res<SkinUniforms>,
2457    morph_indices: Res<MorphIndices>,
2458) {
2459    // Set `HAS_PREVIOUS_SKIN` if the mesh has skin weights from the previous
2460    // frame.
2461    for &entity in skin_uniforms.all_skins() {
2462        render_mesh_instances
2463            .insert_mesh_instance_flags(entity, RenderMeshInstanceFlags::HAS_PREVIOUS_SKIN);
2464    }
2465
2466    // Set `HAS_PREVIOUS_MORPH` if the mesh has morph targets from the previous
2467    // frame.
2468    match *morph_indices {
2469        MorphIndices::Uniform { ref prev, .. } => {
2470            for &entity in prev.keys() {
2471                render_mesh_instances.insert_mesh_instance_flags(
2472                    entity,
2473                    RenderMeshInstanceFlags::HAS_PREVIOUS_MORPH,
2474                );
2475            }
2476        }
2477        MorphIndices::Storage {
2478            morph_weights_info: ref morph_target_info,
2479            ..
2480        } => {
2481            for (entity, morph_target_info) in morph_target_info {
2482                if morph_target_info.prev_weight_offset.is_some() {
2483                    render_mesh_instances.insert_mesh_instance_flags(
2484                        *entity,
2485                        RenderMeshInstanceFlags::HAS_PREVIOUS_MORPH,
2486                    );
2487                }
2488            }
2489        }
2490    }
2491}
2492
2493/// Creates the [`RenderMeshInstanceGpu`]s and [`MeshInputUniform`]s when GPU
2494/// preprocessing is in use.
2495pub fn collect_meshes_for_gpu_building(
2496    render_mesh_instances: ResMut<RenderMeshInstances>,
2497    batched_instance_buffers: ResMut<
2498        gpu_preprocessing::BatchedInstanceBuffers<MeshUniform, MeshInputUniform>,
2499    >,
2500    mut mesh_culling_data_buffer: ResMut<MeshCullingDataBuffer>,
2501    mut render_mesh_instance_queues: ResMut<RenderMeshInstanceGpuQueues>,
2502    mut render_gpu_culled_entities: ResMut<RenderGpuCulledEntities>,
2503    mesh_allocator: Res<MeshAllocator>,
2504    mesh_material_ids: Res<RenderMaterialInstances>,
2505    render_material_bindings: Res<RenderMaterialBindings>,
2506    render_lightmaps: Res<RenderLightmaps>,
2507    skin_uniforms: Res<SkinUniforms>,
2508    morph_indices: Res<MorphIndices>,
2509    frame_count: Res<FrameCount>,
2510    mut meshes_to_reextract_next_frame: ResMut<MeshesToReextractNextFrame>,
2511) {
2512    let RenderMeshInstances::GpuBuilding(render_mesh_instances) =
2513        render_mesh_instances.into_inner()
2514    else {
2515        return;
2516    };
2517
2518    // We're going to rebuild `meshes_to_reextract_next_frame`.
2519    meshes_to_reextract_next_frame.clear();
2520
2521    // Collect render mesh instances. Build up the uniform buffer.
2522    let gpu_preprocessing::BatchedInstanceBuffers {
2523        current_input_buffer,
2524        previous_input_buffer,
2525        ..
2526    } = batched_instance_buffers.into_inner();
2527
2528    // Make sure the mesh culling data buffer has enough space.
2529    if !current_input_buffer.is_empty() {
2530        mesh_culling_data_buffer.grow(current_input_buffer.len() as u32);
2531    }
2532
2533    // Pre-allocate the previous input buffer for concurrent pushes.
2534    previous_input_buffer.reserve(current_input_buffer.len() as u32);
2535
2536    // We're going to build up the added, removed, and layers-changed lists on
2537    // `RenderGpuCulledEntities`, so clear them out.
2538    render_gpu_culled_entities.prepare_for_new_frame();
2539
2540    // Channels used by parallel workers to send data to the single consumer.
2541    let (prepared_tx, prepared_rx) = mpsc::channel();
2542    let (reextract_tx, reextract_rx) = mpsc::channel();
2543    let (removed_tx, removed_rx) = mpsc::channel();
2544
2545    {
2546        // Reference data shared between tasks
2547        let mesh_allocator = &mesh_allocator;
2548        let mesh_material_ids = &mesh_material_ids;
2549        let render_material_bindings = &render_material_bindings;
2550        let render_lightmaps = &render_lightmaps;
2551        let skin_uniforms = &skin_uniforms;
2552        let frame_count = *frame_count;
2553        let render_mesh_instances = &*render_mesh_instances;
2554        let current_input_buffer = &*current_input_buffer;
2555        let previous_input_buffer = &*previous_input_buffer;
2556        let mesh_culling_data_buffer = &*mesh_culling_data_buffer;
2557        let morph_indices = &*morph_indices;
2558
2559        // Spawn workers on the taskpool to prepare and update meshes in parallel.
2560        ComputeTaskPool::get().scope(|scope| {
2561            // Iterate through each queue, spawning a task for each queue. This loop completes quickly
2562            // as it does very little work, it is just spawning and moving data into tasks in a loop.
2563            for queue in render_mesh_instance_queues.iter_mut() {
2564                match *queue {
2565                    RenderMeshInstanceGpuQueue::None => {
2566                        // This can only happen if the queue is empty.
2567                    }
2568
2569                    RenderMeshInstanceGpuQueue::CpuCulling {
2570                        ref mut changed,
2571                        ref mut removed,
2572                    } => {
2573                        let prepared_tx = prepared_tx.clone();
2574                        let reextract_tx = reextract_tx.clone();
2575                        let removed_tx = removed_tx.clone();
2576                        scope.spawn(async move {
2577                            #[cfg(feature = "trace")]
2578                            let _span = info_span!("prepared_mesh_producer").entered();
2579                            changed
2580                                .drain(..)
2581                                .for_each(|(entity, mesh_instance_builder)| {
2582                                    match mesh_instance_builder.prepare(
2583                                        entity,
2584                                        mesh_allocator,
2585                                        mesh_material_ids,
2586                                        render_material_bindings,
2587                                        render_lightmaps,
2588                                        skin_uniforms,
2589                                        morph_indices,
2590                                        frame_count,
2591                                    ) {
2592                                        Some(prepared) => {
2593                                            prepared_tx.send((entity, prepared, None)).ok();
2594                                        }
2595                                        None => {
2596                                            reextract_tx.send(entity).ok();
2597                                        }
2598                                    }
2599                                });
2600
2601                            for entity in removed.drain(..) {
2602                                removed_tx.send(entity).unwrap();
2603                            }
2604                        });
2605                    }
2606
2607                    RenderMeshInstanceGpuQueue::GpuCulling {
2608                        ref mut changed_cpu_culling,
2609                        ref mut changed_gpu_culling,
2610                        ref mut removed,
2611                    } => {
2612                        let prepared_tx = prepared_tx.clone();
2613                        let reextract_tx = reextract_tx.clone();
2614                        let removed_tx = removed_tx.clone();
2615                        scope.spawn(async move {
2616                            #[cfg(feature = "trace")]
2617                            let _span = info_span!("prepared_mesh_producer").entered();
2618                            for (entity, mesh_instance_builder, mesh_culling_builder) in
2619                                changed_cpu_culling
2620                                    .drain(..)
2621                                    .chain(changed_gpu_culling.drain(..))
2622                            {
2623                                let Some(mut prepared) = mesh_instance_builder.prepare(
2624                                    entity,
2625                                    mesh_allocator,
2626                                    mesh_material_ids,
2627                                    render_material_bindings,
2628                                    render_lightmaps,
2629                                    skin_uniforms,
2630                                    morph_indices,
2631                                    frame_count,
2632                                ) else {
2633                                    reextract_tx.send(entity).ok();
2634                                    continue;
2635                                };
2636
2637                                let Some(render_mesh_instance) = render_mesh_instances.get(&entity)
2638                                else {
2639                                    // We must take the slow path because we
2640                                    // haven't seen the mesh instance yet. Send
2641                                    // the mesh instance to the collection sink.
2642                                    let _ = prepared_tx.send((
2643                                        entity,
2644                                        prepared,
2645                                        Some(mesh_culling_builder),
2646                                    ));
2647                                    continue;
2648                                };
2649
2650                                if prepared.render_layers != render_mesh_instance.render_layers
2651                                    || prepared
2652                                        .shared
2653                                        .flags
2654                                        .contains(RenderMeshInstanceFlags::NO_CPU_CULLING)
2655                                        != render_mesh_instance
2656                                            .shared
2657                                            .flags()
2658                                            .contains(RenderMeshInstanceFlags::NO_CPU_CULLING)
2659                                {
2660                                    // We must take the slow path because the
2661                                    // instance either changed render layers or
2662                                    // CPU/GPU culling mode. Send the mesh
2663                                    // instance to the collection sink.
2664                                    let _ = prepared_tx.send((
2665                                        entity,
2666                                        prepared,
2667                                        Some(mesh_culling_builder),
2668                                    ));
2669                                    continue;
2670                                }
2671
2672                                // If we got here, we can take a fast path and
2673                                // write directly to shared memory, since the
2674                                // only fields that changed are POD fields.
2675
2676                                prepared.shared.write_to_blob(&render_mesh_instance.shared);
2677
2678                                let current_uniform_index =
2679                                    render_mesh_instance.gpu_specific.current_uniform_index();
2680
2681                                let previous_world_from_local = current_input_buffer
2682                                    .get_unchecked(current_uniform_index)
2683                                    .world_from_local;
2684                                let previous_input_index =
2685                                    previous_input_buffer.push(PreviousMeshInputUniform {
2686                                        world_from_local: previous_world_from_local,
2687                                    });
2688                                prepared.mesh_input_uniform.previous_input_index =
2689                                    previous_input_index;
2690
2691                                current_input_buffer
2692                                    .set(current_uniform_index, prepared.mesh_input_uniform);
2693                                mesh_culling_data_buffer
2694                                    .set(current_uniform_index, mesh_culling_builder);
2695                            }
2696
2697                            for entity in removed.drain(..) {
2698                                removed_tx.send(entity).unwrap();
2699                            }
2700                        });
2701                    }
2702                }
2703            }
2704
2705            // Drop the senders owned by the scope, so the only senders left are those captured by the
2706            // spawned tasks. When the tasks are complete, the channels will close, and the consumer
2707            // will finish. Without this, the scope would deadlock on the blocked consumer.
2708            drop(prepared_tx);
2709            drop(reextract_tx);
2710            drop(removed_tx);
2711        });
2712    }
2713
2714    while let Ok(batch) = prepared_rx.recv() {
2715        let (entity, prepared, mesh_culling_builder) = batch;
2716        let instance_data_index = prepared.update(
2717            entity,
2718            &mut *render_mesh_instances,
2719            current_input_buffer,
2720            previous_input_buffer,
2721        );
2722        if let Some(mesh_culling_data) = mesh_culling_builder {
2723            mesh_culling_data.update(&mut mesh_culling_data_buffer, instance_data_index);
2724        }
2725        // If the instance is already visible, just update the layers.
2726        // Otherwise, mark it as newly-added.
2727        let (render_layers, no_cpu_culling) = match render_mesh_instances.get(&entity) {
2728            None => (RenderLayers::default(), false),
2729            Some(render_mesh_instance) => (
2730                render_mesh_instance
2731                    .render_layers
2732                    .clone()
2733                    .unwrap_or_default(),
2734                render_mesh_instance
2735                    .shared
2736                    .flags()
2737                    .contains(RenderMeshInstanceFlags::NO_CPU_CULLING),
2738            ),
2739        };
2740        render_gpu_culled_entities.update(entity, render_layers, no_cpu_culling);
2741    }
2742    while let Ok(batch) = removed_rx.recv() {
2743        let entity = batch;
2744        remove_mesh_input_uniform(entity, &mut *render_mesh_instances, current_input_buffer);
2745        render_gpu_culled_entities.remove(entity);
2746    }
2747    while let Ok(batch) = reextract_rx.recv() {
2748        let entity = batch;
2749        meshes_to_reextract_next_frame.insert(entity);
2750    }
2751    // Buffers can't be empty. Make sure there's something in the previous input buffer.
2752    previous_input_buffer.ensure_nonempty();
2753}
2754
2755/// All data needed to construct a pipeline for rendering 3D meshes.
2756#[derive(Resource, Clone)]
2757pub struct MeshPipeline {
2758    /// A reference to all the mesh pipeline view layouts.
2759    pub view_layouts: MeshPipelineViewLayouts,
2760    pub clustered_forward_buffer_binding_type: BufferBindingType,
2761    pub mesh_layouts: MeshLayouts,
2762    /// The shader asset handle.
2763    pub shader: Handle<Shader>,
2764    /// `MeshUniform`s are stored in arrays in buffers. If storage buffers are available, they
2765    /// are used and this will be `None`, otherwise uniform buffers will be used with batches
2766    /// of this many `MeshUniform`s, stored at dynamic offsets within the uniform buffer.
2767    /// Use code like this in custom shaders:
2768    /// ```wesl
2769    /// @if(PER_OBJECT_BUFFER_BATCH_SIZE)
2770    /// @group(1) @binding(0) var<uniform> mesh: array<Mesh, u32(constants::PER_OBJECT_BUFFER_BATCH_SIZE)>;
2771    /// @else
2772    /// @group(1) @binding(0) var<storage> mesh: array<Mesh>;
2773    /// ```
2774    pub per_object_buffer_batch_size: Option<u32>,
2775
2776    /// Whether binding arrays (a.k.a. bindless textures) are usable on the
2777    /// current render device.
2778    ///
2779    /// This affects whether reflection probes can be used.
2780    pub binding_arrays_are_usable: bool,
2781
2782    /// Whether clustered decals are usable on the current render device.
2783    pub clustered_decals_are_usable: bool,
2784
2785    /// Whether skins will use uniform buffers on account of storage buffers
2786    /// being unavailable on this platform.
2787    pub skins_use_uniform_buffers: bool,
2788
2789    /// Whether mesh metadata will use uniform buffers on account of storage buffers
2790    /// being unavailable on this platform.
2791    pub metadata_use_uniform_buffers: bool,
2792}
2793
2794fn init_mesh_pipeline(
2795    mut commands: Commands,
2796    render_device: Res<RenderDevice>,
2797    render_adapter: Res<RenderAdapter>,
2798    view_layouts: Res<MeshPipelineViewLayouts>,
2799    asset_server: Res<AssetServer>,
2800) {
2801    let shader = load_embedded_asset!(asset_server.as_ref(), "mesh.wesl");
2802
2803    let clustered_forward_buffer_binding_type =
2804        render_device.get_supported_read_only_binding_type(CLUSTERED_FORWARD_STORAGE_BUFFER_COUNT);
2805
2806    let res = MeshPipeline {
2807        view_layouts: view_layouts.clone(),
2808        clustered_forward_buffer_binding_type,
2809        mesh_layouts: MeshLayouts::new(&render_device, &render_adapter),
2810        shader,
2811        per_object_buffer_batch_size: GpuArrayBuffer::<MeshUniform>::batch_size(
2812            &render_device.limits(),
2813        ),
2814        binding_arrays_are_usable: binding_arrays_are_usable(&render_device, &render_adapter),
2815        clustered_decals_are_usable: decal::clustered::clustered_decals_are_usable(
2816            &render_device,
2817            &render_adapter,
2818        ),
2819        skins_use_uniform_buffers: skins_use_uniform_buffers(&render_device.limits()),
2820        metadata_use_uniform_buffers: bevy_render::storage_buffers_are_unsupported(
2821            &render_device.limits(),
2822        ),
2823    };
2824
2825    commands.insert_resource(res);
2826}
2827
2828impl MeshPipeline {
2829    pub fn get_view_layout(&self, layout_key: MeshPipelineViewLayoutKey) -> MeshPipelineViewLayout {
2830        self.view_layouts.get_view_layout(layout_key)
2831    }
2832}
2833
2834/// A 1x1x1 'all 1.0' texture to use as a dummy texture in place of optional [`crate::pbr_material::StandardMaterial`] textures
2835pub fn build_dummy_white_gpu_image(
2836    render_device: Res<RenderDevice>,
2837    default_sampler: Res<DefaultImageSampler>,
2838    render_queue: Res<RenderQueue>,
2839) -> GpuImage {
2840    let image = Image::default();
2841    let texture = render_device.create_texture(&image.texture_descriptor);
2842    // The default image always uses the default sampler.
2843    let sampler = (**default_sampler).clone();
2844
2845    if let Ok(format_size) = image.texture_descriptor.format.pixel_size() {
2846        render_queue.write_texture(
2847            texture.as_image_copy(),
2848            image.data.as_ref().expect("Image was created without data"),
2849            TexelCopyBufferLayout {
2850                offset: 0,
2851                bytes_per_row: Some(image.width() * format_size as u32),
2852                rows_per_image: None,
2853            },
2854            image.texture_descriptor.size,
2855        );
2856    }
2857
2858    let texture_view = texture.create_view(&TextureViewDescriptor::default());
2859    GpuImage {
2860        texture,
2861        texture_view,
2862        sampler,
2863        texture_descriptor: image.texture_descriptor,
2864        texture_view_descriptor: image.texture_view_descriptor,
2865        had_data: true,
2866    }
2867}
2868
2869pub fn get_image_texture<'a>(
2870    dummy_white_gpu_image: &'a GpuImage,
2871    gpu_images: &'a RenderAssets<GpuImage>,
2872    handle_option: &Option<Handle<Image>>,
2873) -> Option<(&'a TextureView, &'a Sampler)> {
2874    if let Some(handle) = handle_option {
2875        let gpu_image = gpu_images.get(handle)?;
2876        Some((&gpu_image.texture_view, &gpu_image.sampler))
2877    } else {
2878        Some((
2879            &dummy_white_gpu_image.texture_view,
2880            &dummy_white_gpu_image.sampler,
2881        ))
2882    }
2883}
2884
2885/// Data that must be identical for meshes to be multi-drawn together.
2886#[derive(Clone, Copy, PartialEq)]
2887pub struct MeshBatchSetCompareData {
2888    /// The bind group for the material.
2889    material_bind_group_index: MaterialBindGroupIndex,
2890    /// The slabs that the mesh data is stored in.
2891    mesh_slabs: MeshSlabs,
2892    /// The bindless slab that stores the lightmap for this mesh, if applicable.
2893    lightmap_slab: Option<NonMaxU32>,
2894}
2895
2896impl GetBatchData for MeshPipeline {
2897    type Param = (
2898        SRes<RenderMeshInstances>,
2899        SRes<RenderLightmaps>,
2900        SRes<MeshAllocator>,
2901        SRes<SkinUniforms>,
2902        SRes<MorphIndices>,
2903    );
2904    type BatchSetCompareData = MeshBatchSetCompareData;
2905    type BatchCompareData = AssetId<Mesh>;
2906
2907    type BufferData = MeshUniform;
2908
2909    fn get_batch_data(
2910        (mesh_instances, lightmaps, mesh_allocator, skin_uniforms, morph_indices): &SystemParamItem<
2911            Self::Param,
2912        >,
2913        (_entity, main_entity): (Entity, MainEntity),
2914    ) -> Option<(
2915        Self::BufferData,
2916        Option<(Self::BatchSetCompareData, Self::BatchCompareData)>,
2917    )> {
2918        let RenderMeshInstances::CpuBuilding(ref mesh_instances) = **mesh_instances else {
2919            error!(
2920                "`get_batch_data` should never be called in GPU mesh uniform \
2921                building mode"
2922            );
2923            return None;
2924        };
2925        let mesh_instance = mesh_instances.get(&main_entity)?;
2926        let mesh_asset_id = mesh_instance.mesh_asset_id();
2927        let first_vertex_index = match mesh_allocator.mesh_vertex_slice(&mesh_asset_id) {
2928            Some(mesh_vertex_slice) => mesh_vertex_slice.range.start,
2929            None => 0,
2930        };
2931        let mesh_slabs = mesh_allocator.mesh_slabs(&mesh_asset_id)?;
2932        let maybe_lightmap = lightmaps.render_lightmaps.get(&main_entity);
2933
2934        let current_skin_index = skin_uniforms.skin_index(main_entity);
2935        let morph_descriptor_index = morph_indices.morph_descriptor_index(main_entity);
2936        let material_bind_group_index = mesh_instance.material_bindings_index();
2937
2938        let metadata_index = mesh_allocator
2939            .mesh_metadata_slice(&mesh_asset_id)
2940            .map(|mesh_metadata_slice| mesh_metadata_slice.range.start);
2941
2942        Some((
2943            MeshUniform::new(
2944                &mesh_instance.transforms,
2945                first_vertex_index,
2946                material_bind_group_index.slot,
2947                maybe_lightmap.map(|lightmap| (lightmap.slot_index, lightmap.uv_rect)),
2948                current_skin_index,
2949                morph_descriptor_index,
2950                Some(mesh_instance.tag()),
2951                metadata_index,
2952            ),
2953            mesh_instance.should_batch().then_some((
2954                MeshBatchSetCompareData {
2955                    material_bind_group_index: material_bind_group_index.group,
2956                    mesh_slabs,
2957                    lightmap_slab: maybe_lightmap.map(|lightmap| lightmap.slab_index.0),
2958                },
2959                mesh_instance.mesh_asset_id(),
2960            )),
2961        ))
2962    }
2963}
2964
2965impl GetFullBatchData for MeshPipeline {
2966    type BufferInputData = MeshInputUniform;
2967
2968    fn get_index_and_compare_data(
2969        (mesh_instances, lightmaps, mesh_allocator, _, _): &SystemParamItem<Self::Param>,
2970        main_entity: MainEntity,
2971    ) -> Option<(
2972        NonMaxU32,
2973        Option<(Self::BatchSetCompareData, Self::BatchCompareData)>,
2974    )> {
2975        // This should only be called during GPU building.
2976        let RenderMeshInstances::GpuBuilding(ref mesh_instances) = **mesh_instances else {
2977            error!(
2978                "`get_index_and_compare_data` should never be called in CPU mesh uniform building \
2979                mode"
2980            );
2981            return None;
2982        };
2983
2984        let mesh_instance = mesh_instances.get(&main_entity)?;
2985        let mesh_slabs = mesh_allocator.mesh_slabs(&mesh_instance.mesh_asset_id())?;
2986        let maybe_lightmap = lightmaps.render_lightmaps.get(&main_entity);
2987        let material_bind_group_index = mesh_instance.material_bindings_index();
2988
2989        Some((
2990            NonMaxU32::new(mesh_instance.gpu_specific.current_uniform_index())?,
2991            mesh_instance.should_batch().then_some((
2992                MeshBatchSetCompareData {
2993                    material_bind_group_index: material_bind_group_index.group,
2994                    mesh_slabs,
2995                    lightmap_slab: maybe_lightmap.map(|lightmap| lightmap.slab_index.0),
2996                },
2997                mesh_instance.mesh_asset_id(),
2998            )),
2999        ))
3000    }
3001
3002    fn get_binned_batch_data(
3003        (mesh_instances, lightmaps, mesh_allocator, skin_uniforms, morph_indices): &SystemParamItem<
3004            Self::Param,
3005        >,
3006        main_entity: MainEntity,
3007    ) -> Option<Self::BufferData> {
3008        let RenderMeshInstances::CpuBuilding(ref mesh_instances) = **mesh_instances else {
3009            error!(
3010                "`get_binned_batch_data` should never be called in GPU mesh uniform building mode"
3011            );
3012            return None;
3013        };
3014        let mesh_instance = mesh_instances.get(&main_entity)?;
3015        let mesh_asset_id = mesh_instance.mesh_asset_id();
3016        let first_vertex_index = match mesh_allocator.mesh_vertex_slice(&mesh_asset_id) {
3017            Some(mesh_vertex_slice) => mesh_vertex_slice.range.start,
3018            None => 0,
3019        };
3020        let maybe_lightmap = lightmaps.render_lightmaps.get(&main_entity);
3021
3022        let current_skin_index = skin_uniforms.skin_index(main_entity);
3023        let morph_descriptor_index = morph_indices.morph_descriptor_index(main_entity);
3024
3025        let metadata_index = mesh_allocator
3026            .mesh_metadata_slice(&mesh_asset_id)
3027            .map(|mesh_metadata_slice| mesh_metadata_slice.range.start);
3028
3029        Some(MeshUniform::new(
3030            &mesh_instance.transforms,
3031            first_vertex_index,
3032            mesh_instance.material_bindings_index().slot,
3033            maybe_lightmap.map(|lightmap| (lightmap.slot_index, lightmap.uv_rect)),
3034            current_skin_index,
3035            morph_descriptor_index,
3036            Some(mesh_instance.tag()),
3037            metadata_index,
3038        ))
3039    }
3040
3041    fn get_binned_index(
3042        (mesh_instances, _, _, _, _): &SystemParamItem<Self::Param>,
3043        main_entity: MainEntity,
3044    ) -> Option<NonMaxU32> {
3045        // This should only be called during GPU building.
3046        let RenderMeshInstances::GpuBuilding(ref mesh_instances) = **mesh_instances else {
3047            error!(
3048                "`get_binned_index` should never be called in CPU mesh uniform \
3049                building mode"
3050            );
3051            return None;
3052        };
3053
3054        mesh_instances
3055            .get(&main_entity)
3056            .and_then(|entity| NonMaxU32::new(entity.gpu_specific.current_uniform_index()))
3057    }
3058
3059    fn write_batch_indirect_parameters_metadata(
3060        indexed: bool,
3061        base_output_index: u32,
3062        batch_set_index: Option<NonMaxU32>,
3063        phase_indirect_parameters_buffers: &mut UntypedPhaseIndirectParametersBuffers,
3064        indirect_parameters_offset: u32,
3065    ) {
3066        let indirect_parameters = IndirectParametersMetadata {
3067            base_output_index,
3068            batch_set_index: match batch_set_index {
3069                Some(batch_set_index) => u32::from(batch_set_index),
3070                None => !0,
3071            },
3072            // These fields are filled in by the GPU:
3073            mesh_index: 0,
3074            early_instance_count: 0,
3075            late_instance_count: 0,
3076        };
3077
3078        if indexed {
3079            phase_indirect_parameters_buffers
3080                .indexed
3081                .set(indirect_parameters_offset, indirect_parameters);
3082        } else {
3083            phase_indirect_parameters_buffers
3084                .non_indexed
3085                .set(indirect_parameters_offset, indirect_parameters);
3086        }
3087    }
3088}
3089
3090bitflags::bitflags! {
3091    #[derive(Default, Clone, Copy, Debug, PartialEq, Eq, Hash)]
3092    #[repr(transparent)]
3093    // NOTE: Apparently quadro drivers support up to 64x MSAA.
3094    // MSAA uses the highest 3 bits for the MSAA log2(sample count) to support up to 128x MSAA.
3095    pub struct MeshPipelineKey: u64 {
3096        // Nothing
3097        const NONE                              = 0;
3098
3099        // Inherited bits
3100        const MORPH_TARGETS                     = BaseMeshPipelineKey::MORPH_TARGETS.bits();
3101
3102        // Flag bits
3103        const TONEMAP_IN_SHADER                 = 1 << 0;
3104        const DEBAND_DITHER                     = 1 << 1;
3105        const DEPTH_PREPASS                     = 1 << 2;
3106        const NORMAL_PREPASS                    = 1 << 3;
3107        const DEFERRED_PREPASS                  = 1 << 4;
3108        const MOTION_VECTOR_PREPASS             = 1 << 5;
3109        const MAY_DISCARD                       = 1 << 6; // Guards shader codepaths that may discard, allowing early depth tests in most cases
3110                                                            // See: https://www.khronos.org/opengl/wiki/Early_Fragment_Test
3111        const ENVIRONMENT_MAP                   = 1 << 7;
3112        const SCREEN_SPACE_AMBIENT_OCCLUSION    = 1 << 8;
3113        const UNCLIPPED_DEPTH_ORTHO             = 1 << 9; // Disables depth clipping for use with directional light shadow views
3114                                                            // Emulated via fragment shader depth on hardware that doesn't support it natively
3115                                                            // See: https://www.w3.org/TR/webgpu/#depth-clipping and https://therealmjp.github.io/posts/shadow-maps/#disabling-z-clipping
3116        const TEMPORAL_JITTER                   = 1 << 10;
3117        const VIEW_TRANSMISSION_TEXTURE         = 1 << 11;
3118        const LIGHTMAPPED                       = 1 << 12;
3119        const LIGHTMAP_BICUBIC_SAMPLING         = 1 << 13;
3120        const IRRADIANCE_VOLUME                 = 1 << 14;
3121        const VISIBILITY_RANGE_DITHER           = 1 << 15;
3122        const SCREEN_SPACE_REFLECTIONS          = 1 << 16;
3123        const HAS_PREVIOUS_SKIN                 = 1 << 17;
3124        const HAS_PREVIOUS_MORPH                = 1 << 18;
3125        const OIT_ENABLED                       = 1 << 19;
3126        const DISTANCE_FOG                      = 1 << 20;
3127        const ATMOSPHERE                        = 1 << 21;
3128        const INVERT_CULLING                    = 1 << 22;
3129        const PREPASS_READS_MATERIAL            = 1 << 23;
3130        const CONTACT_SHADOWS                   = 1 << 24;
3131        const LAST_FLAG                         = Self::CONTACT_SHADOWS.bits();
3132
3133        const ALL_PREPASS_BITS                  = Self::DEPTH_PREPASS.bits()
3134                                                | Self::NORMAL_PREPASS.bits()
3135                                                | Self::DEFERRED_PREPASS.bits()
3136                                                | Self::MOTION_VECTOR_PREPASS.bits()
3137                                                | Self::MAY_DISCARD.bits()
3138                                                | Self::PREPASS_READS_MATERIAL.bits();
3139
3140        // Bitfields
3141        const MSAA_RESERVED_BITS                = Self::MSAA_MASK_BITS << Self::MSAA_SHIFT_BITS;
3142        const BLEND_RESERVED_BITS               = Self::BLEND_MASK_BITS << Self::BLEND_SHIFT_BITS; // ← Bitmask reserving bits for the blend state
3143        const BLEND_OPAQUE                      = 0 << Self::BLEND_SHIFT_BITS;                     // ← Values are just sequential within the mask
3144        const BLEND_PREMULTIPLIED_ALPHA         = 1 << Self::BLEND_SHIFT_BITS;                     // ← As blend states is on 3 bits, it can range from 0 to 7
3145        const BLEND_MULTIPLY                    = 2 << Self::BLEND_SHIFT_BITS;                     // ← See `BLEND_MASK_BITS` for the number of bits available
3146        const BLEND_ALPHA                       = 3 << Self::BLEND_SHIFT_BITS;                     //
3147        const BLEND_ALPHA_TO_COVERAGE           = 4 << Self::BLEND_SHIFT_BITS;                     // ← We still have room for three more values without adding more bits
3148        const TONEMAP_METHOD_RESERVED_BITS      = Self::TONEMAP_METHOD_MASK_BITS << Self::TONEMAP_METHOD_SHIFT_BITS;
3149        const TONEMAP_METHOD_LINEAR             = 0 << Self::TONEMAP_METHOD_SHIFT_BITS;
3150        const TONEMAP_METHOD_REINHARD           = 1 << Self::TONEMAP_METHOD_SHIFT_BITS;
3151        const TONEMAP_METHOD_REINHARD_LUMINANCE = 2 << Self::TONEMAP_METHOD_SHIFT_BITS;
3152        const TONEMAP_METHOD_ACES_FITTED        = 3 << Self::TONEMAP_METHOD_SHIFT_BITS;
3153        const TONEMAP_METHOD_AGX                = 4 << Self::TONEMAP_METHOD_SHIFT_BITS;
3154        const TONEMAP_METHOD_SOMEWHAT_BORING_DISPLAY_TRANSFORM = 5 << Self::TONEMAP_METHOD_SHIFT_BITS;
3155        const TONEMAP_METHOD_TONY_MC_MAPFACE    = 6 << Self::TONEMAP_METHOD_SHIFT_BITS;
3156        const TONEMAP_METHOD_BLENDER_FILMIC     = 7 << Self::TONEMAP_METHOD_SHIFT_BITS;
3157        const TONEMAP_METHOD_PBR_NEUTRAL        = 8 << Self::TONEMAP_METHOD_SHIFT_BITS;
3158        const SHADOW_FILTER_METHOD_RESERVED_BITS = Self::SHADOW_FILTER_METHOD_MASK_BITS << Self::SHADOW_FILTER_METHOD_SHIFT_BITS;
3159        const SHADOW_FILTER_METHOD_HARDWARE_2X2  = 0 << Self::SHADOW_FILTER_METHOD_SHIFT_BITS;
3160        const SHADOW_FILTER_METHOD_GAUSSIAN      = 1 << Self::SHADOW_FILTER_METHOD_SHIFT_BITS;
3161        const SHADOW_FILTER_METHOD_TEMPORAL      = 2 << Self::SHADOW_FILTER_METHOD_SHIFT_BITS;
3162        const VIEW_PROJECTION_RESERVED_BITS     = Self::VIEW_PROJECTION_MASK_BITS << Self::VIEW_PROJECTION_SHIFT_BITS;
3163        const VIEW_PROJECTION_NONSTANDARD       = 0 << Self::VIEW_PROJECTION_SHIFT_BITS;
3164        const VIEW_PROJECTION_PERSPECTIVE       = 1 << Self::VIEW_PROJECTION_SHIFT_BITS;
3165        const VIEW_PROJECTION_ORTHOGRAPHIC      = 2 << Self::VIEW_PROJECTION_SHIFT_BITS;
3166        const VIEW_PROJECTION_RESERVED          = 3 << Self::VIEW_PROJECTION_SHIFT_BITS;
3167        const SCREEN_SPACE_SPECULAR_TRANSMISSION_RESERVED_BITS = Self::SCREEN_SPACE_SPECULAR_TRANSMISSION_MASK_BITS << Self::SCREEN_SPACE_SPECULAR_TRANSMISSION_SHIFT_BITS;
3168        const SCREEN_SPACE_SPECULAR_TRANSMISSION_LOW    = 0 << Self::SCREEN_SPACE_SPECULAR_TRANSMISSION_SHIFT_BITS;
3169        const SCREEN_SPACE_SPECULAR_TRANSMISSION_MEDIUM = 1 << Self::SCREEN_SPACE_SPECULAR_TRANSMISSION_SHIFT_BITS;
3170        const SCREEN_SPACE_SPECULAR_TRANSMISSION_HIGH   = 2 << Self::SCREEN_SPACE_SPECULAR_TRANSMISSION_SHIFT_BITS;
3171        const SCREEN_SPACE_SPECULAR_TRANSMISSION_ULTRA  = 3 << Self::SCREEN_SPACE_SPECULAR_TRANSMISSION_SHIFT_BITS;
3172        const COLOR_TARGET_FORMAT_RESERVED_BITS = Self::COLOR_TARGET_FORMAT_MASK_BITS
3173            << Self::COLOR_TARGET_FORMAT_SHIFT_BITS;
3174        const ALL_RESERVED_BITS =
3175            Self::BLEND_RESERVED_BITS.bits() |
3176            Self::MSAA_RESERVED_BITS.bits() |
3177            Self::TONEMAP_METHOD_RESERVED_BITS.bits() |
3178            Self::SHADOW_FILTER_METHOD_RESERVED_BITS.bits() |
3179            Self::VIEW_PROJECTION_RESERVED_BITS.bits() |
3180            Self::SCREEN_SPACE_SPECULAR_TRANSMISSION_RESERVED_BITS.bits() |
3181            Self::COLOR_TARGET_FORMAT_RESERVED_BITS.bits();
3182    }
3183}
3184
3185impl MeshPipelineKey {
3186    const MSAA_MASK_BITS: u64 = 0b111;
3187    const MSAA_SHIFT_BITS: u64 = Self::LAST_FLAG.bits().trailing_zeros() as u64 + 1;
3188
3189    const BLEND_MASK_BITS: u64 = 0b111;
3190    const BLEND_SHIFT_BITS: u64 = Self::MSAA_MASK_BITS.count_ones() as u64 + Self::MSAA_SHIFT_BITS;
3191
3192    const TONEMAP_METHOD_MASK_BITS: u64 = 0b1111;
3193    const TONEMAP_METHOD_SHIFT_BITS: u64 =
3194        Self::BLEND_MASK_BITS.count_ones() as u64 + Self::BLEND_SHIFT_BITS;
3195
3196    const SHADOW_FILTER_METHOD_MASK_BITS: u64 = 0b11;
3197    const SHADOW_FILTER_METHOD_SHIFT_BITS: u64 =
3198        Self::TONEMAP_METHOD_MASK_BITS.count_ones() as u64 + Self::TONEMAP_METHOD_SHIFT_BITS;
3199
3200    const VIEW_PROJECTION_MASK_BITS: u64 = 0b11;
3201    const VIEW_PROJECTION_SHIFT_BITS: u64 = Self::SHADOW_FILTER_METHOD_MASK_BITS.count_ones()
3202        as u64
3203        + Self::SHADOW_FILTER_METHOD_SHIFT_BITS;
3204
3205    const SCREEN_SPACE_SPECULAR_TRANSMISSION_MASK_BITS: u64 = 0b11;
3206    const SCREEN_SPACE_SPECULAR_TRANSMISSION_SHIFT_BITS: u64 =
3207        Self::VIEW_PROJECTION_MASK_BITS.count_ones() as u64 + Self::VIEW_PROJECTION_SHIFT_BITS;
3208
3209    const COLOR_TARGET_FORMAT_MASK_BITS: u64 = view::COLOR_TARGET_FORMAT_MASK_BITS as u64;
3210    const COLOR_TARGET_FORMAT_SHIFT_BITS: u64 = Self::SCREEN_SPACE_SPECULAR_TRANSMISSION_MASK_BITS
3211        .count_ones() as u64
3212        + Self::SCREEN_SPACE_SPECULAR_TRANSMISSION_SHIFT_BITS;
3213
3214    pub fn from_msaa_samples(msaa_samples: u32) -> Self {
3215        let msaa_bits =
3216            (msaa_samples.trailing_zeros() as u64 & Self::MSAA_MASK_BITS) << Self::MSAA_SHIFT_BITS;
3217        Self::from_bits_retain(msaa_bits)
3218    }
3219
3220    /// Create a pipeline key from the view's color target format.
3221    #[inline]
3222    pub fn from_target_format(format: TextureFormat) -> Self {
3223        let code = texture_format_to_code(format)
3224            .expect("Texture format is not supported by the pipeline") as u64;
3225        Self::from_bits_retain(
3226            (code & Self::COLOR_TARGET_FORMAT_MASK_BITS) << Self::COLOR_TARGET_FORMAT_SHIFT_BITS,
3227        )
3228    }
3229
3230    /// Color target format of the main pass for this pipeline key.
3231    #[inline]
3232    pub fn target_format(&self) -> TextureFormat {
3233        let code = ((self.bits() >> Self::COLOR_TARGET_FORMAT_SHIFT_BITS)
3234            & Self::COLOR_TARGET_FORMAT_MASK_BITS) as u8;
3235        texture_format_from_code(code)
3236            .expect("Unknown bits in `COLOR_TARGET_FORMAT_MASK_BITS` of the pipeline key")
3237    }
3238
3239    pub fn msaa_samples(&self) -> u32 {
3240        1 << ((self.bits() >> Self::MSAA_SHIFT_BITS) & Self::MSAA_MASK_BITS)
3241    }
3242
3243    /// Create a [`BaseMeshPipelineKey`] from mesh primitive topology and index format.
3244    ///
3245    /// For non-strip topologies, [`BaseMeshPipelineKey::STRIP_INDEX_FORMAT_NONE`] is set regardless of the `strip_index_format` argument.
3246    pub fn from_primitive_topology_and_strip_index(
3247        primitive_topology: PrimitiveTopology,
3248        strip_index_format: Option<IndexFormat>,
3249    ) -> Self {
3250        let index_bits = if primitive_topology.is_strip() {
3251            match strip_index_format {
3252                None => BaseMeshPipelineKey::STRIP_INDEX_FORMAT_NONE,
3253                Some(indices) => match indices {
3254                    IndexFormat::Uint16 => BaseMeshPipelineKey::STRIP_INDEX_FORMAT_U16,
3255                    IndexFormat::Uint32 => BaseMeshPipelineKey::STRIP_INDEX_FORMAT_U32,
3256                },
3257            }
3258        } else {
3259            BaseMeshPipelineKey::STRIP_INDEX_FORMAT_NONE
3260        }
3261        .bits();
3262        let primitive_topology_bits = ((primitive_topology as u64)
3263            & BaseMeshPipelineKey::PRIMITIVE_TOPOLOGY_MASK_BITS)
3264            << BaseMeshPipelineKey::PRIMITIVE_TOPOLOGY_SHIFT_BITS;
3265        Self::from_bits_retain(primitive_topology_bits | index_bits)
3266    }
3267
3268    pub fn primitive_topology(&self) -> PrimitiveTopology {
3269        let primitive_topology_bits = (self.bits()
3270            >> BaseMeshPipelineKey::PRIMITIVE_TOPOLOGY_SHIFT_BITS)
3271            & BaseMeshPipelineKey::PRIMITIVE_TOPOLOGY_MASK_BITS;
3272        match primitive_topology_bits {
3273            x if x == PrimitiveTopology::PointList as u64 => PrimitiveTopology::PointList,
3274            x if x == PrimitiveTopology::LineList as u64 => PrimitiveTopology::LineList,
3275            x if x == PrimitiveTopology::LineStrip as u64 => PrimitiveTopology::LineStrip,
3276            x if x == PrimitiveTopology::TriangleList as u64 => PrimitiveTopology::TriangleList,
3277            x if x == PrimitiveTopology::TriangleStrip as u64 => PrimitiveTopology::TriangleStrip,
3278            _ => PrimitiveTopology::default(),
3279        }
3280    }
3281
3282    pub fn strip_index_format(&self) -> Option<IndexFormat> {
3283        let index_bits = self.bits() & BaseMeshPipelineKey::STRIP_INDEX_FORMAT_RESERVED_BITS.bits();
3284        match index_bits {
3285            x if x == BaseMeshPipelineKey::STRIP_INDEX_FORMAT_U16.bits() => {
3286                Some(IndexFormat::Uint16)
3287            }
3288            x if x == BaseMeshPipelineKey::STRIP_INDEX_FORMAT_U32.bits() => {
3289                Some(IndexFormat::Uint32)
3290            }
3291            x if x == BaseMeshPipelineKey::STRIP_INDEX_FORMAT_NONE.bits() => None,
3292            _ => unreachable!(),
3293        }
3294    }
3295}
3296
3297impl From<u64> for MeshPipelineKey {
3298    fn from(value: u64) -> Self {
3299        MeshPipelineKey::from_bits_retain(value)
3300    }
3301}
3302
3303impl From<MeshPipelineKey> for u64 {
3304    fn from(value: MeshPipelineKey) -> Self {
3305        value.bits()
3306    }
3307}
3308
3309// Ensure that we didn't overflow the number of bits available in `MeshPipelineKey`.
3310const_assert_eq!(
3311    (((MeshPipelineKey::LAST_FLAG.bits() << 1) - 1) | MeshPipelineKey::ALL_RESERVED_BITS.bits())
3312        & BaseMeshPipelineKey::all().bits(),
3313    0
3314);
3315
3316// Ensure that the bits of `BaseMeshPipelineKey` don't overlap with the bits of `MeshPipelineKey`
3317// except the inherited bits.
3318const_assert_eq!(
3319    BaseMeshPipelineKey::all().bits() & MeshPipelineKey::all().bits(),
3320    MeshPipelineKey::MORPH_TARGETS.bits()
3321);
3322
3323fn is_skinned(layout: &MeshVertexBufferLayoutRef) -> bool {
3324    layout.0.contains(Mesh::ATTRIBUTE_JOINT_INDEX)
3325        && layout.0.contains(Mesh::ATTRIBUTE_JOINT_WEIGHT)
3326}
3327pub fn setup_morph_and_skinning_defs(
3328    mesh_layouts: &MeshLayouts,
3329    layout: &MeshVertexBufferLayoutRef,
3330    offset: u32,
3331    key: &MeshPipelineKey,
3332    shader_defs: &mut Vec<ShaderDefVal>,
3333    vertex_attributes: &mut Vec<VertexAttributeDescriptor>,
3334    skins_use_uniform_buffers: bool,
3335) -> BindGroupLayoutDescriptor {
3336    let is_morphed = key.intersects(MeshPipelineKey::MORPH_TARGETS);
3337    let is_lightmapped = key.intersects(MeshPipelineKey::LIGHTMAPPED);
3338    let motion_vector_prepass = key.intersects(MeshPipelineKey::MOTION_VECTOR_PREPASS);
3339
3340    if skins_use_uniform_buffers {
3341        shader_defs.push("SKINS_USE_UNIFORM_BUFFERS".into());
3342    }
3343
3344    let mut add_skin_data = || {
3345        shader_defs.push("SKINNED".into());
3346        vertex_attributes.push(Mesh::ATTRIBUTE_JOINT_INDEX.at_shader_location(offset));
3347        vertex_attributes.push(Mesh::ATTRIBUTE_JOINT_WEIGHT.at_shader_location(offset + 1));
3348    };
3349
3350    match (
3351        is_skinned(layout),
3352        is_morphed,
3353        is_lightmapped,
3354        motion_vector_prepass,
3355    ) {
3356        (true, false, _, true) => {
3357            add_skin_data();
3358            mesh_layouts.skinned_motion.clone()
3359        }
3360        (true, false, _, false) => {
3361            add_skin_data();
3362            mesh_layouts.skinned.clone()
3363        }
3364        (true, true, _, true) => {
3365            add_skin_data();
3366            shader_defs.push("MORPH_TARGETS".into());
3367            mesh_layouts.morphed_skinned_motion.clone()
3368        }
3369        (true, true, _, false) => {
3370            add_skin_data();
3371            shader_defs.push("MORPH_TARGETS".into());
3372            mesh_layouts.morphed_skinned.clone()
3373        }
3374        (false, true, _, true) => {
3375            shader_defs.push("MORPH_TARGETS".into());
3376            mesh_layouts.morphed_motion.clone()
3377        }
3378        (false, true, _, false) => {
3379            shader_defs.push("MORPH_TARGETS".into());
3380            mesh_layouts.morphed.clone()
3381        }
3382        (false, false, true, _) => mesh_layouts.lightmapped.clone(),
3383        (false, false, false, _) => mesh_layouts.model_only.clone(),
3384    }
3385}
3386
3387impl SpecializedMeshPipeline for MeshPipeline {
3388    type Key = MeshPipelineKey;
3389
3390    fn specialize(
3391        &self,
3392        key: Self::Key,
3393        layout: &MeshVertexBufferLayoutRef,
3394    ) -> Result<RenderPipelineDescriptor, SpecializedMeshPipelineError> {
3395        let mut shader_defs = Vec::new();
3396        let mut vertex_attributes = Vec::new();
3397
3398        // Let the shader code know that it's running in a mesh pipeline.
3399        shader_defs.push("MESH_PIPELINE".into());
3400
3401        shader_defs.push("VERTEX_OUTPUT_INSTANCE_INDEX".into());
3402
3403        if layout.0.contains(Mesh::ATTRIBUTE_POSITION) {
3404            shader_defs.push("VERTEX_POSITIONS".into());
3405            if layout
3406                .0
3407                .get_attribute_compression()
3408                .contains(MeshAttributeCompressionFlags::COMPRESS_POSITION)
3409            {
3410                shader_defs.push("VERTEX_POSITIONS_COMPRESSED".into());
3411            }
3412            vertex_attributes.push(Mesh::ATTRIBUTE_POSITION.at_shader_location(0));
3413        }
3414
3415        if layout.0.contains(Mesh::ATTRIBUTE_NORMAL) {
3416            shader_defs.push("VERTEX_NORMALS".into());
3417            if layout
3418                .0
3419                .get_attribute_compression()
3420                .contains(MeshAttributeCompressionFlags::COMPRESS_NORMAL)
3421            {
3422                shader_defs.push("VERTEX_NORMALS_COMPRESSED".into());
3423            }
3424            vertex_attributes.push(Mesh::ATTRIBUTE_NORMAL.at_shader_location(1));
3425        }
3426
3427        if layout.0.contains(Mesh::ATTRIBUTE_UV_0) {
3428            shader_defs.push("VERTEX_UVS".into());
3429            shader_defs.push("VERTEX_UVS_A".into());
3430            if layout
3431                .0
3432                .get_attribute_compression()
3433                .contains(MeshAttributeCompressionFlags::COMPRESS_UV0)
3434            {
3435                shader_defs.push("VERTEX_UVS_A_COMPRESSED".into());
3436            }
3437            vertex_attributes.push(Mesh::ATTRIBUTE_UV_0.at_shader_location(2));
3438        }
3439
3440        if layout.0.contains(Mesh::ATTRIBUTE_UV_1) {
3441            shader_defs.push("VERTEX_UVS".into());
3442            shader_defs.push("VERTEX_UVS_B".into());
3443            if layout
3444                .0
3445                .get_attribute_compression()
3446                .contains(MeshAttributeCompressionFlags::COMPRESS_UV1)
3447            {
3448                shader_defs.push("VERTEX_UVS_B_COMPRESSED".into());
3449            }
3450            vertex_attributes.push(Mesh::ATTRIBUTE_UV_1.at_shader_location(3));
3451        }
3452
3453        if layout.0.contains(Mesh::ATTRIBUTE_TANGENT) {
3454            shader_defs.push("VERTEX_TANGENTS".into());
3455            if layout
3456                .0
3457                .get_attribute_compression()
3458                .contains(MeshAttributeCompressionFlags::COMPRESS_TANGENT)
3459            {
3460                shader_defs.push("VERTEX_TANGENTS_COMPRESSED".into());
3461            }
3462            vertex_attributes.push(Mesh::ATTRIBUTE_TANGENT.at_shader_location(4));
3463        }
3464
3465        if layout.0.contains(Mesh::ATTRIBUTE_COLOR) {
3466            shader_defs.push("VERTEX_COLORS".into());
3467            vertex_attributes.push(Mesh::ATTRIBUTE_COLOR.at_shader_location(5));
3468        }
3469
3470        if cfg!(feature = "pbr_transmission_textures") {
3471            shader_defs.push("PBR_TRANSMISSION_TEXTURES_SUPPORTED".into());
3472        }
3473        if cfg!(feature = "pbr_multi_layer_material_textures") {
3474            shader_defs.push("PBR_MULTI_LAYER_MATERIAL_TEXTURES_SUPPORTED".into());
3475        }
3476        if cfg!(feature = "pbr_anisotropy_texture") {
3477            shader_defs.push("PBR_ANISOTROPY_TEXTURE_SUPPORTED".into());
3478        }
3479        if cfg!(feature = "pbr_specular_textures") {
3480            shader_defs.push("PBR_SPECULAR_TEXTURES_SUPPORTED".into());
3481        }
3482        if cfg!(feature = "bluenoise_texture") {
3483            shader_defs.push("BLUE_NOISE_TEXTURE".into());
3484        }
3485        if cfg!(feature = "dfg_lut") {
3486            shader_defs.push("DFG_LUT".into());
3487        }
3488        if cfg!(feature = "area_light_luts") {
3489            shader_defs.push("AREA_LIGHT_LUTS".into());
3490        }
3491
3492        let bind_group_layout = self.get_view_layout(key.into());
3493        let mut bind_group_layout = vec![
3494            bind_group_layout.main_layout.clone(),
3495            bind_group_layout.binding_array_layout.clone(),
3496        ];
3497
3498        if key.msaa_samples() > 1 {
3499            shader_defs.push("MULTISAMPLED".into());
3500        };
3501
3502        if self.metadata_use_uniform_buffers {
3503            shader_defs.push("METADATA_USE_UNIFORM_BUFFERS".into());
3504        }
3505
3506        bind_group_layout.push(setup_morph_and_skinning_defs(
3507            &self.mesh_layouts,
3508            layout,
3509            6,
3510            &key,
3511            &mut shader_defs,
3512            &mut vertex_attributes,
3513            self.skins_use_uniform_buffers,
3514        ));
3515
3516        if key.contains(MeshPipelineKey::CONTACT_SHADOWS) {
3517            shader_defs.push("CONTACT_SHADOWS".into());
3518        }
3519
3520        if key.contains(MeshPipelineKey::OIT_ENABLED) {
3521            shader_defs.push("OIT_ENABLED".into());
3522        }
3523
3524        let vertex_buffer_layout = layout.0.get_layout(&vertex_attributes)?;
3525
3526        let (label, blend, depth_write_enabled);
3527        let pass = key.intersection(MeshPipelineKey::BLEND_RESERVED_BITS);
3528        let mut alpha_to_coverage_enabled = false;
3529        if pass == MeshPipelineKey::BLEND_ALPHA {
3530            label = "alpha_blend_mesh_pipeline".into();
3531            blend = Some(BlendState::ALPHA_BLENDING);
3532            // For the transparent pass, fragments that are closer will be alpha blended
3533            // but their depth is not written to the depth buffer
3534            depth_write_enabled = false;
3535        } else if pass == MeshPipelineKey::BLEND_PREMULTIPLIED_ALPHA {
3536            label = "premultiplied_alpha_mesh_pipeline".into();
3537            blend = Some(BlendState::PREMULTIPLIED_ALPHA_BLENDING);
3538            shader_defs.push("PREMULTIPLY_ALPHA".into());
3539            shader_defs.push("BLEND_PREMULTIPLIED_ALPHA".into());
3540            // For the transparent pass, fragments that are closer will be alpha blended
3541            // but their depth is not written to the depth buffer
3542            depth_write_enabled = false;
3543        } else if pass == MeshPipelineKey::BLEND_MULTIPLY {
3544            label = "multiply_mesh_pipeline".into();
3545            blend = Some(BlendState {
3546                color: BlendComponent {
3547                    src_factor: BlendFactor::Dst,
3548                    dst_factor: BlendFactor::OneMinusSrcAlpha,
3549                    operation: BlendOperation::Add,
3550                },
3551                alpha: BlendComponent::OVER,
3552            });
3553            shader_defs.push("PREMULTIPLY_ALPHA".into());
3554            shader_defs.push("BLEND_MULTIPLY".into());
3555            // For the multiply pass, fragments that are closer will be alpha blended
3556            // but their depth is not written to the depth buffer
3557            depth_write_enabled = false;
3558        } else if pass == MeshPipelineKey::BLEND_ALPHA_TO_COVERAGE {
3559            label = "alpha_to_coverage_mesh_pipeline".into();
3560            // BlendState::REPLACE is not needed here, and None will be potentially much faster in some cases
3561            blend = None;
3562            // For the opaque and alpha mask passes, fragments that are closer will replace
3563            // the current fragment value in the output and the depth is written to the
3564            // depth buffer
3565            depth_write_enabled = true;
3566            alpha_to_coverage_enabled = true;
3567            shader_defs.push("ALPHA_TO_COVERAGE".into());
3568        } else {
3569            label = "opaque_mesh_pipeline".into();
3570            // BlendState::REPLACE is not needed here, and None will be potentially much faster in some cases
3571            blend = None;
3572            // For the opaque and alpha mask passes, fragments that are closer will replace
3573            // the current fragment value in the output and the depth is written to the
3574            // depth buffer
3575            depth_write_enabled = true;
3576        }
3577
3578        if key.contains(MeshPipelineKey::NORMAL_PREPASS) {
3579            shader_defs.push("NORMAL_PREPASS".into());
3580        }
3581
3582        if key.contains(MeshPipelineKey::DEPTH_PREPASS) {
3583            shader_defs.push("DEPTH_PREPASS".into());
3584        }
3585
3586        // Transparent meshes don't contribute to the depth prepass, so SSAO should not be applied.
3587        if key.contains(MeshPipelineKey::SCREEN_SPACE_AMBIENT_OCCLUSION) && depth_write_enabled {
3588            shader_defs.push("SCREEN_SPACE_AMBIENT_OCCLUSION".into());
3589        }
3590
3591        if key.contains(MeshPipelineKey::MOTION_VECTOR_PREPASS) {
3592            shader_defs.push("MOTION_VECTOR_PREPASS".into());
3593        }
3594
3595        if key.contains(MeshPipelineKey::HAS_PREVIOUS_SKIN) {
3596            shader_defs.push("HAS_PREVIOUS_SKIN".into());
3597        }
3598
3599        if key.contains(MeshPipelineKey::HAS_PREVIOUS_MORPH) {
3600            shader_defs.push("HAS_PREVIOUS_MORPH".into());
3601        }
3602
3603        if key.contains(MeshPipelineKey::DEFERRED_PREPASS) {
3604            shader_defs.push("DEFERRED_PREPASS".into());
3605        }
3606
3607        if key.contains(MeshPipelineKey::NORMAL_PREPASS) && key.msaa_samples() == 1 {
3608            shader_defs.push("LOAD_PREPASS_NORMALS".into());
3609        }
3610
3611        let view_projection = key.intersection(MeshPipelineKey::VIEW_PROJECTION_RESERVED_BITS);
3612        if view_projection == MeshPipelineKey::VIEW_PROJECTION_NONSTANDARD {
3613            shader_defs.push("VIEW_PROJECTION_NONSTANDARD".into());
3614        } else if view_projection == MeshPipelineKey::VIEW_PROJECTION_PERSPECTIVE {
3615            shader_defs.push("VIEW_PROJECTION_PERSPECTIVE".into());
3616        } else if view_projection == MeshPipelineKey::VIEW_PROJECTION_ORTHOGRAPHIC {
3617            shader_defs.push("VIEW_PROJECTION_ORTHOGRAPHIC".into());
3618        }
3619
3620        #[cfg(all(feature = "webgl", target_arch = "wasm32", not(feature = "webgpu")))]
3621        shader_defs.push("WEBGL2".into());
3622
3623        #[cfg(feature = "experimental_pbr_pcss")]
3624        shader_defs.push("PCSS_SAMPLERS_AVAILABLE".into());
3625
3626        if key.contains(MeshPipelineKey::TONEMAP_IN_SHADER) {
3627            shader_defs.push("TONEMAP_IN_SHADER".into());
3628            shader_defs.push(ShaderDefVal::UInt(
3629                "TONEMAPPING_LUT_TEXTURE_BINDING_INDEX".into(),
3630                TONEMAPPING_LUT_TEXTURE_BINDING_INDEX,
3631            ));
3632            shader_defs.push(ShaderDefVal::UInt(
3633                "TONEMAPPING_LUT_SAMPLER_BINDING_INDEX".into(),
3634                TONEMAPPING_LUT_SAMPLER_BINDING_INDEX,
3635            ));
3636
3637            let method = key.intersection(MeshPipelineKey::TONEMAP_METHOD_RESERVED_BITS);
3638
3639            if method == MeshPipelineKey::TONEMAP_METHOD_LINEAR {
3640                shader_defs.push("TONEMAP_METHOD_LINEAR".into());
3641            } else if method == MeshPipelineKey::TONEMAP_METHOD_REINHARD {
3642                shader_defs.push("TONEMAP_METHOD_REINHARD".into());
3643            } else if method == MeshPipelineKey::TONEMAP_METHOD_REINHARD_LUMINANCE {
3644                shader_defs.push("TONEMAP_METHOD_REINHARD_LUMINANCE".into());
3645            } else if method == MeshPipelineKey::TONEMAP_METHOD_ACES_FITTED {
3646                shader_defs.push("TONEMAP_METHOD_ACES_FITTED".into());
3647            } else if method == MeshPipelineKey::TONEMAP_METHOD_AGX {
3648                shader_defs.push("TONEMAP_METHOD_AGX".into());
3649            } else if method == MeshPipelineKey::TONEMAP_METHOD_SOMEWHAT_BORING_DISPLAY_TRANSFORM {
3650                shader_defs.push("TONEMAP_METHOD_SOMEWHAT_BORING_DISPLAY_TRANSFORM".into());
3651            } else if method == MeshPipelineKey::TONEMAP_METHOD_BLENDER_FILMIC {
3652                shader_defs.push("TONEMAP_METHOD_BLENDER_FILMIC".into());
3653            } else if method == MeshPipelineKey::TONEMAP_METHOD_TONY_MC_MAPFACE {
3654                shader_defs.push("TONEMAP_METHOD_TONY_MC_MAPFACE".into());
3655            } else if method == MeshPipelineKey::TONEMAP_METHOD_PBR_NEUTRAL {
3656                shader_defs.push("TONEMAP_METHOD_PBR_NEUTRAL".into());
3657            }
3658
3659            // Debanding is tied to tonemapping in the shader, cannot run without it.
3660            if key.contains(MeshPipelineKey::DEBAND_DITHER) {
3661                shader_defs.push("DEBAND_DITHER".into());
3662            }
3663        }
3664
3665        if key.contains(MeshPipelineKey::MAY_DISCARD) {
3666            shader_defs.push("MAY_DISCARD".into());
3667        }
3668
3669        if key.contains(MeshPipelineKey::ENVIRONMENT_MAP) {
3670            shader_defs.push("ENVIRONMENT_MAP".into());
3671        }
3672
3673        if key.contains(MeshPipelineKey::IRRADIANCE_VOLUME) && IRRADIANCE_VOLUMES_ARE_USABLE {
3674            shader_defs.push("IRRADIANCE_VOLUME".into());
3675        }
3676
3677        if key.contains(MeshPipelineKey::LIGHTMAPPED) {
3678            shader_defs.push("LIGHTMAP".into());
3679        }
3680        if key.contains(MeshPipelineKey::LIGHTMAP_BICUBIC_SAMPLING) {
3681            shader_defs.push("LIGHTMAP_BICUBIC_SAMPLING".into());
3682        }
3683
3684        if key.contains(MeshPipelineKey::TEMPORAL_JITTER) {
3685            shader_defs.push("TEMPORAL_JITTER".into());
3686        }
3687
3688        let shadow_filter_method =
3689            key.intersection(MeshPipelineKey::SHADOW_FILTER_METHOD_RESERVED_BITS);
3690        if shadow_filter_method == MeshPipelineKey::SHADOW_FILTER_METHOD_HARDWARE_2X2 {
3691            shader_defs.push("SHADOW_FILTER_METHOD_HARDWARE_2X2".into());
3692        } else if shadow_filter_method == MeshPipelineKey::SHADOW_FILTER_METHOD_GAUSSIAN {
3693            shader_defs.push("SHADOW_FILTER_METHOD_GAUSSIAN".into());
3694        } else if shadow_filter_method == MeshPipelineKey::SHADOW_FILTER_METHOD_TEMPORAL {
3695            shader_defs.push("SHADOW_FILTER_METHOD_TEMPORAL".into());
3696        }
3697
3698        if key.contains(MeshPipelineKey::VIEW_TRANSMISSION_TEXTURE) {
3699            shader_defs.push("VIEW_TRANSMISSION_TEXTURE".into());
3700        }
3701
3702        let blur_quality =
3703            key.intersection(MeshPipelineKey::SCREEN_SPACE_SPECULAR_TRANSMISSION_RESERVED_BITS);
3704
3705        shader_defs.push(ShaderDefVal::Int(
3706            "SCREEN_SPACE_SPECULAR_TRANSMISSION_BLUR_TAPS".into(),
3707            match blur_quality {
3708                MeshPipelineKey::SCREEN_SPACE_SPECULAR_TRANSMISSION_LOW => 4,
3709                MeshPipelineKey::SCREEN_SPACE_SPECULAR_TRANSMISSION_MEDIUM => 8,
3710                MeshPipelineKey::SCREEN_SPACE_SPECULAR_TRANSMISSION_HIGH => 16,
3711                MeshPipelineKey::SCREEN_SPACE_SPECULAR_TRANSMISSION_ULTRA => 32,
3712                _ => unreachable!(), // Not possible, since the mask is 2 bits, and we've covered all 4 cases
3713            },
3714        ));
3715
3716        if key.contains(MeshPipelineKey::VISIBILITY_RANGE_DITHER) {
3717            shader_defs.push("VISIBILITY_RANGE_DITHER".into());
3718        }
3719
3720        if key.contains(MeshPipelineKey::DISTANCE_FOG) {
3721            shader_defs.push("DISTANCE_FOG".into());
3722        }
3723
3724        if key.contains(MeshPipelineKey::ATMOSPHERE) {
3725            shader_defs.push("ATMOSPHERE".into());
3726        }
3727
3728        if self.binding_arrays_are_usable {
3729            shader_defs.push("MULTIPLE_LIGHT_PROBES_IN_ARRAY".into());
3730            shader_defs.push("MULTIPLE_LIGHTMAPS_IN_ARRAY".into());
3731        }
3732
3733        if IRRADIANCE_VOLUMES_ARE_USABLE {
3734            shader_defs.push("IRRADIANCE_VOLUMES_ARE_USABLE".into());
3735        }
3736
3737        if self.clustered_decals_are_usable {
3738            shader_defs.push("CLUSTERED_DECALS_ARE_USABLE".into());
3739            if cfg!(feature = "pbr_light_textures") {
3740                shader_defs.push("LIGHT_TEXTURES".into());
3741            }
3742        }
3743
3744        let format = key.target_format();
3745
3746        // This is defined here so that custom shaders that use something other than
3747        // the mesh binding from bevy_pbr::render::mesh_bindings can easily make use of this
3748        // in their own shaders.
3749        if let Some(per_object_buffer_batch_size) = self.per_object_buffer_batch_size {
3750            shader_defs.push(ShaderDefVal::UInt(
3751                "PER_OBJECT_BUFFER_BATCH_SIZE".into(),
3752                per_object_buffer_batch_size,
3753            ));
3754        }
3755
3756        Ok(RenderPipelineDescriptor {
3757            vertex: VertexState {
3758                shader: self.shader.clone(),
3759                shader_defs: shader_defs.clone(),
3760                buffers: vec![vertex_buffer_layout],
3761                ..default()
3762            },
3763            fragment: Some(FragmentState {
3764                shader: self.shader.clone(),
3765                shader_defs,
3766                targets: vec![Some(ColorTargetState {
3767                    format,
3768                    blend,
3769                    write_mask: ColorWrites::ALL,
3770                })],
3771                ..default()
3772            }),
3773            layout: bind_group_layout,
3774            primitive: PrimitiveState {
3775                cull_mode: Some(Face::Back),
3776                unclipped_depth: false,
3777                topology: key.primitive_topology(),
3778                strip_index_format: key.strip_index_format(),
3779                ..default()
3780            },
3781            depth_stencil: Some(DepthStencilState {
3782                format: CORE_3D_DEPTH_FORMAT,
3783                depth_write_enabled: Some(depth_write_enabled),
3784                depth_compare: Some(CompareFunction::GreaterEqual),
3785                stencil: StencilState {
3786                    front: StencilFaceState::IGNORE,
3787                    back: StencilFaceState::IGNORE,
3788                    read_mask: 0,
3789                    write_mask: 0,
3790                },
3791                bias: DepthBiasState {
3792                    constant: 0,
3793                    slope_scale: 0.0,
3794                    clamp: 0.0,
3795                },
3796            }),
3797            multisample: MultisampleState {
3798                count: key.msaa_samples(),
3799                mask: !0,
3800                alpha_to_coverage_enabled,
3801            },
3802            label: Some(label),
3803            ..default()
3804        })
3805    }
3806}
3807
3808/// The bind groups for meshes currently loaded.
3809///
3810/// If GPU mesh preprocessing isn't in use, these are global to the scene. If
3811/// GPU mesh preprocessing is in use, these are specific to a single phase.
3812pub struct MeshPhaseBindGroups {
3813    /// Map metadata slab id to model-only bind group.
3814    model_only: HashMap<MeshSlabId, BindGroup>,
3815    /// Map metadata slab id to skinned bind group.
3816    skinned: HashMap<MeshSlabId, MeshBindGroupPair>,
3817    /// Bind groups for meshes with morph targets.
3818    morph_targets: MeshMorphTargetBindGroups,
3819    lightmaps: HashMap<(MeshSlabId, LightmapSlabIndex), BindGroup>,
3820}
3821
3822/// Stores bind groups for each mesh with morph targets.
3823///
3824/// If storage buffers aren't available on this platform, we use a single bind
3825/// group per mesh. If they are available, however, we use a single bind group
3826/// per metadata slab ID and per morph target slab ID (managed by the mesh allocator).
3827pub enum MeshMorphTargetBindGroups {
3828    /// Maps a mesh asset ID to the bind group for that mesh.
3829    ///
3830    /// We use morph target images on platforms without storage buffers, and as
3831    /// such platforms don't support bindless textures either, we must use a
3832    /// single bind group per morphable mesh.
3833    Uniform(HashMap<AssetId<Mesh>, MeshBindGroupPair>),
3834
3835    /// Maps a metadata slab ID + morph target slab ID pair that the mesh allocator manages to the bind
3836    /// groups for morph displacements in that slab.
3837    Storage(HashMap<(MeshSlabId, MeshSlabId), MeshMorphTargetStorageBindGroups>),
3838}
3839
3840/// The bind groups associated with a single morph displacements slab.
3841///
3842/// Because a single morph displacement slab might contain morph displacements
3843/// for both meshes with skins and meshes without skins, we need two separate
3844/// bind groups here.
3845pub struct MeshMorphTargetStorageBindGroups {
3846    /// The bind group used for meshes with skins.
3847    skinned: Option<MeshBindGroupPair>,
3848    /// The bind group used for meshes without skins.
3849    unskinned: Option<MeshBindGroupPair>,
3850}
3851
3852impl MeshMorphTargetBindGroups {
3853    /// Clears out all morph target bind groups.
3854    fn clear(&mut self) {
3855        match *self {
3856            MeshMorphTargetBindGroups::Uniform(ref mut mesh_to_bind_group_pair) => {
3857                mesh_to_bind_group_pair.clear();
3858            }
3859            MeshMorphTargetBindGroups::Storage(ref mut slab_id_to_bind_groups) => {
3860                slab_id_to_bind_groups.clear();
3861            }
3862        }
3863    }
3864}
3865
3866pub struct MeshBindGroupPair {
3867    motion_vectors: BindGroup,
3868    no_motion_vectors: BindGroup,
3869}
3870
3871/// All bind groups for meshes currently loaded.
3872#[derive(Resource)]
3873pub enum MeshBindGroups {
3874    /// The bind groups for the meshes for the entire scene, if GPU mesh
3875    /// preprocessing isn't in use.
3876    CpuPreprocessing(MeshPhaseBindGroups),
3877    /// A mapping from the type ID of a phase (e.g. [`Opaque3d`]) to the mesh
3878    /// bind groups for that phase.
3879    GpuPreprocessing(TypeIdHashMap<MeshPhaseBindGroups>),
3880}
3881
3882impl MeshPhaseBindGroups {
3883    /// Creates a new, blank, set of bind groups for this phase.
3884    ///
3885    /// Bind groups must be added to the resulting [`MeshPhaseBindGroups`]
3886    /// explicitly.
3887    pub fn new(render_device: &RenderDevice) -> MeshPhaseBindGroups {
3888        MeshPhaseBindGroups {
3889            model_only: HashMap::default(),
3890            skinned: HashMap::default(),
3891            morph_targets: if skins_use_uniform_buffers(&render_device.limits()) {
3892                MeshMorphTargetBindGroups::Uniform(HashMap::default())
3893            } else {
3894                MeshMorphTargetBindGroups::Storage(HashMap::default())
3895            },
3896            lightmaps: HashMap::default(),
3897        }
3898    }
3899
3900    pub fn reset(&mut self) {
3901        self.model_only.clear();
3902        self.skinned.clear();
3903        self.morph_targets.clear();
3904        self.lightmaps.clear();
3905    }
3906
3907    /// Get the appropriate `BindGroup` for `RenderMesh` with the given keys.
3908    pub fn get(
3909        &self,
3910        metadata_slab_id: MeshSlabId,
3911        lightmap: Option<LightmapSlabIndex>,
3912        is_skinned: bool,
3913        morph: MeshMorphBindGroupKey,
3914        motion_vectors: bool,
3915    ) -> Option<&BindGroup> {
3916        match (is_skinned, morph, lightmap) {
3917            (_, MeshMorphBindGroupKey::Uniform(asset_id), _) => match self.morph_targets {
3918                MeshMorphTargetBindGroups::Uniform(ref morph_targets) => morph_targets
3919                    .get(&asset_id)
3920                    .map(|bind_group_pair| bind_group_pair.get(motion_vectors)),
3921                MeshMorphTargetBindGroups::Storage(..) => {
3922                    error!(
3923                        "Tried to look up a mesh morph target bind group using a mesh ID, but \
3924                        we're using storage buffers. Look it up using the slab ID instead."
3925                    );
3926                    None
3927                }
3928            },
3929            (_, MeshMorphBindGroupKey::Storage(metadata_and_morph_slab_ids), _) => match &self
3930                .morph_targets
3931            {
3932                MeshMorphTargetBindGroups::Uniform(..) => {
3933                    error!(
3934                        "Tried to look up a mesh morph target bind group using a slab ID, but \
3935                        we're using uniform buffers. Look it up using the mesh ID instead."
3936                    );
3937                    None
3938                }
3939                MeshMorphTargetBindGroups::Storage(slab_to_bind_group) => {
3940                    let slab_bind_group = slab_to_bind_group.get(&metadata_and_morph_slab_ids)?;
3941                    if is_skinned {
3942                        slab_bind_group
3943                            .skinned
3944                            .as_ref()
3945                            .map(|bind_group_pair| bind_group_pair.get(motion_vectors))
3946                    } else {
3947                        slab_bind_group
3948                            .unskinned
3949                            .as_ref()
3950                            .map(|bind_group_pair| bind_group_pair.get(motion_vectors))
3951                    }
3952                }
3953            },
3954            (true, MeshMorphBindGroupKey::NoMorphTargets, _) => self
3955                .skinned
3956                .get(&metadata_slab_id)
3957                .map(|bind_group_pair| bind_group_pair.get(motion_vectors)),
3958            (false, MeshMorphBindGroupKey::NoMorphTargets, Some(lightmap_slab)) => {
3959                self.lightmaps.get(&(metadata_slab_id, lightmap_slab))
3960            }
3961            (false, MeshMorphBindGroupKey::NoMorphTargets, None) => {
3962                self.model_only.get(&metadata_slab_id)
3963            }
3964        }
3965    }
3966}
3967
3968impl MeshBindGroupPair {
3969    fn get(&self, motion_vectors: bool) -> &BindGroup {
3970        if motion_vectors {
3971            &self.motion_vectors
3972        } else {
3973            &self.no_motion_vectors
3974        }
3975    }
3976}
3977
3978/// Data related to morph targets that we need in order to look up the bind
3979/// group for a mesh.
3980#[derive(Clone, Copy)]
3981pub enum MeshMorphBindGroupKey {
3982    /// The mesh has no morph targets.
3983    NoMorphTargets,
3984    /// The mesh has morph targets, and the current platform doesn't support
3985    /// storage buffers.
3986    ///
3987    /// In this case, there's a single bind group per mesh.
3988    Uniform(AssetId<Mesh>),
3989    /// The mesh has morph targets, and the current platform does support
3990    /// storage buffers.
3991    ///
3992    /// In this case, there's a bind group per metadata slab and per morph target slab (managed
3993    /// by the mesh allocator).
3994    Storage((MeshSlabId, MeshSlabId)),
3995}
3996
3997/// Creates the per-mesh bind groups for each type of mesh and each phase.
3998pub fn prepare_mesh_bind_groups(
3999    mut commands: Commands,
4000    meshes: Res<RenderAssets<RenderMesh>>,
4001    mesh_pipeline: Res<MeshPipeline>,
4002    render_device: Res<RenderDevice>,
4003    pipeline_cache: Res<PipelineCache>,
4004    cpu_batched_instance_buffer: Option<
4005        Res<no_gpu_preprocessing::BatchedInstanceBuffer<MeshUniform>>,
4006    >,
4007    gpu_batched_instance_buffers: Option<
4008        Res<gpu_preprocessing::BatchedInstanceBuffers<MeshUniform, MeshInputUniform>>,
4009    >,
4010    skins_uniform: Res<SkinUniforms>,
4011    weights_uniform: Res<MorphUniforms>,
4012    mesh_allocator: Res<MeshAllocator>,
4013    render_morph_target_allocator: Res<RenderMorphTargetAllocator>,
4014    render_lightmaps: Res<RenderLightmaps>,
4015    metadata_fallback_buffer: Res<MeshMetadataFallbackBuffer>,
4016    mut mesh_bind_groups: Option<ResMut<MeshBindGroups>>,
4017) {
4018    // CPU mesh preprocessing path.
4019    if let Some(cpu_batched_instance_buffer) = cpu_batched_instance_buffer
4020        && let Some(instance_data_binding) = cpu_batched_instance_buffer
4021            .into_inner()
4022            .instance_data_binding()
4023    {
4024        // Reuse allocations
4025        let mut cpu_preprocessing_mesh_bind_groups = match mesh_bind_groups.as_deref_mut() {
4026            None | Some(MeshBindGroups::GpuPreprocessing(_)) => {
4027                MeshPhaseBindGroups::new(&render_device)
4028            }
4029            Some(MeshBindGroups::CpuPreprocessing(cpu_preprocessing_mesh_bind_groups)) => {
4030                core::mem::replace(
4031                    cpu_preprocessing_mesh_bind_groups,
4032                    MeshPhaseBindGroups::new(&render_device),
4033                )
4034            }
4035        };
4036        cpu_preprocessing_mesh_bind_groups.reset();
4037
4038        // In this path, we only have a single set of bind groups for all phases.
4039        prepare_mesh_bind_groups_for_phase(
4040            &mut cpu_preprocessing_mesh_bind_groups,
4041            instance_data_binding,
4042            &meshes,
4043            &mesh_pipeline,
4044            &render_device,
4045            &pipeline_cache,
4046            &skins_uniform,
4047            &weights_uniform,
4048            &mesh_allocator,
4049            &render_morph_target_allocator,
4050            &render_lightmaps,
4051            &metadata_fallback_buffer,
4052        );
4053
4054        commands.insert_resource(MeshBindGroups::CpuPreprocessing(
4055            cpu_preprocessing_mesh_bind_groups,
4056        ));
4057        return;
4058    }
4059
4060    // GPU mesh preprocessing path.
4061    if let Some(gpu_batched_instance_buffers) = gpu_batched_instance_buffers {
4062        // Reuse allocations
4063        let mut gpu_preprocessing_mesh_bind_groups = match mesh_bind_groups.as_deref_mut() {
4064            None | Some(MeshBindGroups::CpuPreprocessing(_)) => TypeIdHashMap::default(),
4065            Some(MeshBindGroups::GpuPreprocessing(gpu_preprocessing_mesh_bind_groups)) => {
4066                core::mem::take(gpu_preprocessing_mesh_bind_groups)
4067            }
4068        };
4069
4070        // Loop over each phase.
4071        for (phase_type_id, batched_phase_instance_buffers) in
4072            &gpu_batched_instance_buffers.phase_instance_buffers
4073        {
4074            let Some(instance_data_binding) =
4075                batched_phase_instance_buffers.instance_data_binding()
4076            else {
4077                continue;
4078            };
4079            let groups = gpu_preprocessing_mesh_bind_groups
4080                .entry(*phase_type_id)
4081                .or_insert(MeshPhaseBindGroups::new(&render_device));
4082            groups.reset();
4083
4084            prepare_mesh_bind_groups_for_phase(
4085                groups,
4086                instance_data_binding,
4087                &meshes,
4088                &mesh_pipeline,
4089                &render_device,
4090                &pipeline_cache,
4091                &skins_uniform,
4092                &weights_uniform,
4093                &mesh_allocator,
4094                &render_morph_target_allocator,
4095                &render_lightmaps,
4096                &metadata_fallback_buffer,
4097            );
4098        }
4099
4100        commands.insert_resource(MeshBindGroups::GpuPreprocessing(
4101            gpu_preprocessing_mesh_bind_groups,
4102        ));
4103    }
4104}
4105
4106/// Creates the per-mesh bind groups for each type of mesh, for a single phase.
4107fn prepare_mesh_bind_groups_for_phase(
4108    groups: &mut MeshPhaseBindGroups,
4109    model: BindingResource,
4110    meshes: &RenderAssets<RenderMesh>,
4111    mesh_pipeline: &MeshPipeline,
4112    render_device: &RenderDevice,
4113    pipeline_cache: &PipelineCache,
4114    skins_uniform: &SkinUniforms,
4115    weights_uniform: &MorphUniforms,
4116    mesh_allocator: &MeshAllocator,
4117    render_morph_target_allocator: &RenderMorphTargetAllocator,
4118    render_lightmaps: &RenderLightmaps,
4119    metadata_fallback_buffer: &MeshMetadataFallbackBuffer,
4120) {
4121    let layouts = &mesh_pipeline.mesh_layouts;
4122
4123    for metadata_slab_id in mesh_allocator.metadata_slabs() {
4124        let metadata_buffer = mesh_allocator
4125            .buffer_for_slab(metadata_slab_id)
4126            .unwrap_or(&metadata_fallback_buffer.buffer);
4127        groups.model_only.insert(
4128            metadata_slab_id,
4129            layouts.model_only(render_device, pipeline_cache, &model, metadata_buffer),
4130        );
4131
4132        // Create the skinned mesh bind group with the current and previous buffers
4133        // (the latter being for motion vector computation).
4134        let (skin, prev_skin) = (&skins_uniform.current_buffer, &skins_uniform.prev_buffer);
4135        groups.skinned.insert(
4136            metadata_slab_id,
4137            MeshBindGroupPair {
4138                motion_vectors: layouts.skinned_motion(
4139                    render_device,
4140                    pipeline_cache,
4141                    &model,
4142                    metadata_buffer,
4143                    skin,
4144                    prev_skin,
4145                ),
4146                no_motion_vectors: layouts.skinned(
4147                    render_device,
4148                    pipeline_cache,
4149                    &model,
4150                    metadata_buffer,
4151                    skin,
4152                ),
4153            },
4154        );
4155
4156        // Create the morphed bind groups with storage buffers.
4157        if weights_uniform.current_buffer.buffer().is_some() {
4158            match (render_morph_target_allocator, &mut groups.morph_targets) {
4159                (
4160                    RenderMorphTargetAllocator::Image {
4161                        mesh_id_to_image: _,
4162                    },
4163                    &mut MeshMorphTargetBindGroups::Uniform(ref mut _morph_targets),
4164                ) => {
4165                    // We will create it later in `prepare_mesh_morph_target_bind_groups_for_phase_using_uniforms`,
4166                    // since the `MeshMorphTargetBindGroups::Uniform` is per-mesh instead of per-slab.
4167                }
4168
4169                (
4170                    &RenderMorphTargetAllocator::Storage,
4171                    &mut MeshMorphTargetBindGroups::Storage(
4172                        ref mut morph_target_storage_bind_groups,
4173                    ),
4174                ) => {
4175                    prepare_mesh_morph_target_bind_groups_for_phase_using_storage(
4176                        &model,
4177                        layouts,
4178                        render_device,
4179                        pipeline_cache,
4180                        skins_uniform,
4181                        weights_uniform,
4182                        mesh_allocator,
4183                        morph_target_storage_bind_groups,
4184                        (metadata_slab_id, metadata_buffer),
4185                    );
4186                }
4187
4188                _ => {
4189                    error!(
4190                    "Mismatched render morph target allocator and mesh morph target bind groups"
4191                );
4192                }
4193            }
4194        }
4195
4196        // Create lightmap bindgroups. There will be one bindgroup for each slab.
4197        let bindless_supported = render_lightmaps.bindless_supported;
4198        for (lightmap_slab_id, lightmap_slab) in render_lightmaps.slabs.iter().enumerate() {
4199            groups.lightmaps.insert(
4200                (
4201                    metadata_slab_id,
4202                    LightmapSlabIndex(NonMaxU32::new(lightmap_slab_id as u32).unwrap()),
4203                ),
4204                layouts.lightmapped(
4205                    render_device,
4206                    pipeline_cache,
4207                    &model,
4208                    metadata_buffer,
4209                    lightmap_slab,
4210                    bindless_supported,
4211                ),
4212            );
4213        }
4214    }
4215
4216    // Create the morphed bind groups with uniforms.
4217    if weights_uniform.current_buffer.buffer().is_some() {
4218        match (render_morph_target_allocator, &mut groups.morph_targets) {
4219            (
4220                RenderMorphTargetAllocator::Image { mesh_id_to_image },
4221                &mut MeshMorphTargetBindGroups::Uniform(ref mut morph_targets),
4222            ) => {
4223                prepare_mesh_morph_target_bind_groups_for_phase_using_uniforms(
4224                    &model,
4225                    meshes,
4226                    layouts,
4227                    render_device,
4228                    pipeline_cache,
4229                    skins_uniform,
4230                    weights_uniform,
4231                    mesh_id_to_image,
4232                    morph_targets,
4233                    mesh_allocator,
4234                    metadata_fallback_buffer,
4235                );
4236            }
4237
4238            (
4239                &RenderMorphTargetAllocator::Storage,
4240                &mut MeshMorphTargetBindGroups::Storage(ref mut _morph_target_storage_bind_groups),
4241            ) => {
4242                // We already filled it above in the loop.
4243            }
4244
4245            _ => {
4246                error!(
4247                    "Mismatched render morph target allocator and mesh morph target bind groups"
4248                );
4249            }
4250        }
4251    }
4252}
4253
4254/// Creates per-mesh morph target bind groups for a single phase.
4255///
4256/// This function is only used when the platform doesn't support storage
4257/// buffers.
4258fn prepare_mesh_morph_target_bind_groups_for_phase_using_uniforms(
4259    model: &BindingResource,
4260    meshes: &RenderAssets<RenderMesh>,
4261    layouts: &MeshLayouts,
4262    render_device: &RenderDevice,
4263    pipeline_cache: &PipelineCache,
4264    skins_uniform: &SkinUniforms,
4265    weights_uniform: &MorphUniforms,
4266    mesh_id_to_image: &HashMap<AssetId<Mesh>, MorphTargetImage>,
4267    morph_targets: &mut HashMap<AssetId<Mesh>, MeshBindGroupPair>,
4268    mesh_allocator: &MeshAllocator,
4269    metadata_fallback_buffer: &MeshMetadataFallbackBuffer,
4270) {
4271    let (skin, prev_skin) = (&skins_uniform.current_buffer, &skins_uniform.prev_buffer);
4272    let weights = weights_uniform
4273        .current_buffer
4274        .buffer()
4275        .expect("Should have a weights buffer by now");
4276    let prev_weights = weights_uniform.prev_buffer.buffer().unwrap_or(weights);
4277    let maybe_morph_descriptors = weights_uniform
4278        .descriptors_buffer
4279        .as_ref()
4280        .and_then(|descriptors_buffer| descriptors_buffer.buffer());
4281
4282    for (id, gpu_mesh) in meshes.iter() {
4283        if !gpu_mesh.has_morph_targets() {
4284            continue;
4285        }
4286        let Some(morph_targets_image) = mesh_id_to_image.get(&id) else {
4287            continue;
4288        };
4289        let metadata_buffer = mesh_allocator
4290            .mesh_metadata_slice(&id)
4291            .map(|slice| slice.buffer)
4292            .unwrap_or(&metadata_fallback_buffer.buffer);
4293        let targets = MorphTargetsResource::Texture(&morph_targets_image.texture_view);
4294        let bind_group_pair = if is_skinned(&gpu_mesh.layout) {
4295            MeshBindGroupPair {
4296                motion_vectors: layouts.morphed_skinned_motion(
4297                    render_device,
4298                    pipeline_cache,
4299                    model,
4300                    metadata_buffer,
4301                    skin,
4302                    weights,
4303                    targets,
4304                    prev_skin,
4305                    prev_weights,
4306                    maybe_morph_descriptors,
4307                ),
4308                no_motion_vectors: layouts.morphed_skinned(
4309                    render_device,
4310                    pipeline_cache,
4311                    model,
4312                    metadata_buffer,
4313                    skin,
4314                    weights,
4315                    targets,
4316                    maybe_morph_descriptors,
4317                ),
4318            }
4319        } else {
4320            MeshBindGroupPair {
4321                motion_vectors: layouts.morphed_motion(
4322                    render_device,
4323                    pipeline_cache,
4324                    model,
4325                    metadata_buffer,
4326                    weights,
4327                    prev_weights,
4328                    targets,
4329                    maybe_morph_descriptors,
4330                ),
4331                no_motion_vectors: layouts.morphed(
4332                    render_device,
4333                    pipeline_cache,
4334                    model,
4335                    metadata_buffer,
4336                    weights,
4337                    targets,
4338                    maybe_morph_descriptors,
4339                ),
4340            }
4341        };
4342        morph_targets.insert(id, bind_group_pair);
4343    }
4344}
4345
4346/// Creates per-slab morph target bind groups for a single phase.
4347///
4348/// This function is only used when the platform supports storage buffers.
4349fn prepare_mesh_morph_target_bind_groups_for_phase_using_storage(
4350    model: &BindingResource,
4351    layouts: &MeshLayouts,
4352    render_device: &RenderDevice,
4353    pipeline_cache: &PipelineCache,
4354    skins_uniform: &SkinUniforms,
4355    weights_uniform: &MorphUniforms,
4356    mesh_allocator: &MeshAllocator,
4357    morph_target_storage_bind_groups: &mut HashMap<
4358        (MeshSlabId, MeshSlabId),
4359        MeshMorphTargetStorageBindGroups,
4360    >,
4361    (metadata_slab_id, metadata_buffer): (MeshSlabId, &Buffer),
4362) {
4363    let (skin, prev_skin) = (&skins_uniform.current_buffer, &skins_uniform.prev_buffer);
4364    let weights = weights_uniform
4365        .current_buffer
4366        .buffer()
4367        .expect("Should have a weights buffer by now");
4368    let prev_weights = weights_uniform.prev_buffer.buffer().unwrap_or(weights);
4369    let maybe_morph_descriptors = weights_uniform
4370        .descriptors_buffer
4371        .as_ref()
4372        .and_then(|descriptors_buffer| descriptors_buffer.buffer());
4373
4374    for morph_target_slab_id in mesh_allocator.morph_target_slabs() {
4375        let Some(buffer) = mesh_allocator.buffer_for_slab(morph_target_slab_id) else {
4376            continue;
4377        };
4378        let targets = MorphTargetsResource::Storage(buffer);
4379        morph_target_storage_bind_groups.insert(
4380            (metadata_slab_id, morph_target_slab_id),
4381            MeshMorphTargetStorageBindGroups {
4382                skinned: Some(MeshBindGroupPair {
4383                    motion_vectors: layouts.morphed_skinned_motion(
4384                        render_device,
4385                        pipeline_cache,
4386                        model,
4387                        metadata_buffer,
4388                        skin,
4389                        weights,
4390                        targets,
4391                        prev_skin,
4392                        prev_weights,
4393                        maybe_morph_descriptors,
4394                    ),
4395                    no_motion_vectors: layouts.morphed_skinned(
4396                        render_device,
4397                        pipeline_cache,
4398                        model,
4399                        metadata_buffer,
4400                        skin,
4401                        weights,
4402                        targets,
4403                        maybe_morph_descriptors,
4404                    ),
4405                }),
4406                unskinned: Some(MeshBindGroupPair {
4407                    motion_vectors: layouts.morphed_motion(
4408                        render_device,
4409                        pipeline_cache,
4410                        model,
4411                        metadata_buffer,
4412                        weights,
4413                        prev_weights,
4414                        targets,
4415                        maybe_morph_descriptors,
4416                    ),
4417                    no_motion_vectors: layouts.morphed(
4418                        render_device,
4419                        pipeline_cache,
4420                        model,
4421                        metadata_buffer,
4422                        weights,
4423                        targets,
4424                        maybe_morph_descriptors,
4425                    ),
4426                }),
4427            },
4428        );
4429    }
4430}
4431
4432pub struct SetMeshViewBindGroup<const I: usize>;
4433impl<P: PhaseItem, const I: usize> RenderCommand<P> for SetMeshViewBindGroup<I> {
4434    type Param = ();
4435    type ViewQuery = (Read<MeshViewBindGroup>,);
4436    type ItemQuery = ();
4437
4438    #[inline]
4439    fn render<'w>(
4440        _item: &P,
4441        (mesh_view_bind_group,): ROQueryItem<'w, '_, Self::ViewQuery>,
4442        _entity: Option<()>,
4443        _: SystemParamItem<'w, '_, Self::Param>,
4444        pass: &mut TrackedRenderPass<'w>,
4445    ) -> RenderCommandResult {
4446        pass.set_bind_group(
4447            I,
4448            &mesh_view_bind_group.main,
4449            &mesh_view_bind_group.main_offsets,
4450        );
4451
4452        RenderCommandResult::Success
4453    }
4454}
4455
4456pub struct SetMeshViewBindingArrayBindGroup<const I: usize>;
4457impl<P: PhaseItem, const I: usize> RenderCommand<P> for SetMeshViewBindingArrayBindGroup<I> {
4458    type Param = ();
4459    type ViewQuery = (Read<MeshViewBindGroup>,);
4460    type ItemQuery = ();
4461
4462    #[inline]
4463    fn render<'w>(
4464        _item: &P,
4465        (mesh_view_bind_group,): ROQueryItem<'w, '_, Self::ViewQuery>,
4466        _entity: Option<()>,
4467        _: SystemParamItem<'w, '_, Self::Param>,
4468        pass: &mut TrackedRenderPass<'w>,
4469    ) -> RenderCommandResult {
4470        pass.set_bind_group(I, &mesh_view_bind_group.binding_array, &[]);
4471
4472        RenderCommandResult::Success
4473    }
4474}
4475
4476pub struct SetMeshViewEmptyBindGroup<const I: usize>;
4477impl<P: PhaseItem, const I: usize> RenderCommand<P> for SetMeshViewEmptyBindGroup<I> {
4478    type Param = ();
4479    type ViewQuery = (Read<MeshViewBindGroup>,);
4480    type ItemQuery = ();
4481
4482    #[inline]
4483    fn render<'w>(
4484        _item: &P,
4485        (mesh_view_bind_group,): ROQueryItem<'w, '_, Self::ViewQuery>,
4486        _entity: Option<()>,
4487        _: SystemParamItem<'w, '_, Self::Param>,
4488        pass: &mut TrackedRenderPass<'w>,
4489    ) -> RenderCommandResult {
4490        pass.set_bind_group(I, &mesh_view_bind_group.empty, &[]);
4491
4492        RenderCommandResult::Success
4493    }
4494}
4495
4496pub struct SetMeshBindGroup<const I: usize>;
4497impl<P: PhaseItem, const I: usize> RenderCommand<P> for SetMeshBindGroup<I> {
4498    type Param = (
4499        SRes<RenderDevice>,
4500        SRes<MeshBindGroups>,
4501        SRes<RenderMeshInstances>,
4502        SRes<SkinUniforms>,
4503        SRes<MorphIndices>,
4504        SRes<MeshAllocator>,
4505        SRes<RenderLightmaps>,
4506        SRes<MeshMetadataFallbackBuffer>,
4507    );
4508    type ViewQuery = Has<MotionVectorPrepass>;
4509    type ItemQuery = ();
4510
4511    #[inline]
4512    fn render<'w>(
4513        item: &P,
4514        has_motion_vector_prepass: bool,
4515        _item_query: Option<()>,
4516        (
4517            render_device,
4518            bind_groups,
4519            mesh_instances,
4520            skin_uniforms,
4521            morph_indices,
4522            mesh_allocator,
4523            lightmaps,
4524            metadata_fallback_buffer,
4525        ): SystemParamItem<'w, '_, Self::Param>,
4526        pass: &mut TrackedRenderPass<'w>,
4527    ) -> RenderCommandResult {
4528        let bind_groups = bind_groups.into_inner();
4529        let mesh_instances = mesh_instances.into_inner();
4530        let skin_uniforms = skin_uniforms.into_inner();
4531        let morph_indices = morph_indices.into_inner();
4532
4533        let entity = &item.main_entity();
4534
4535        let Some(mesh_asset_id) = mesh_instances.mesh_asset_id(*entity) else {
4536            return RenderCommandResult::Success;
4537        };
4538
4539        let mesh_slabs = mesh_allocator.mesh_slabs(&mesh_asset_id);
4540        let metadata_slab_id = mesh_slabs
4541            .and_then(|slabs| slabs.metadata_slab_id)
4542            .unwrap_or(metadata_fallback_buffer.slab_id);
4543        let skins_use_uniform_buffers = skins_use_uniform_buffers(&render_device.limits());
4544
4545        let current_skin_byte_offset = skin_uniforms.skin_byte_offset(*entity);
4546
4547        // Determine which morph bind group key we need, if any. If the platform
4548        // doesn't support storage buffers, there's a separate bind group per
4549        // mesh. Otherwise, if the platform does support storage buffers,
4550        // there's one bind group per metadata slab and per morph target slab (managed by
4551        // the mesh allocator).
4552        let (current_morph_index, prev_morph_index, morph_bind_group_key);
4553        match *morph_indices {
4554            MorphIndices::Uniform {
4555                ref current,
4556                ref prev,
4557            } => {
4558                current_morph_index = current.get(entity);
4559                prev_morph_index = prev.get(entity);
4560                morph_bind_group_key = if current_morph_index.is_some() {
4561                    MeshMorphBindGroupKey::Uniform(mesh_asset_id)
4562                } else {
4563                    MeshMorphBindGroupKey::NoMorphTargets
4564                };
4565            }
4566            MorphIndices::Storage { .. } => {
4567                current_morph_index = None;
4568                prev_morph_index = None;
4569                morph_bind_group_key =
4570                    match mesh_slabs.and_then(|mesh_slabs| mesh_slabs.morph_target_slab_id) {
4571                        Some(morph_target_slab_id) => {
4572                            MeshMorphBindGroupKey::Storage((metadata_slab_id, morph_target_slab_id))
4573                        }
4574                        None => MeshMorphBindGroupKey::NoMorphTargets,
4575                    };
4576            }
4577        };
4578
4579        let is_skinned = current_skin_byte_offset.is_some();
4580
4581        let lightmap_slab_index = lightmaps
4582            .render_lightmaps
4583            .get(entity)
4584            .map(|render_lightmap| render_lightmap.slab_index);
4585
4586        let Some(mesh_phase_bind_groups) = (match *bind_groups {
4587            MeshBindGroups::CpuPreprocessing(ref mesh_phase_bind_groups) => {
4588                Some(mesh_phase_bind_groups)
4589            }
4590            MeshBindGroups::GpuPreprocessing(ref mesh_phase_bind_groups) => {
4591                mesh_phase_bind_groups.get(&TypeId::of::<P>())
4592            }
4593        }) else {
4594            // This is harmless if e.g. we're rendering the `Shadow` phase and
4595            // there weren't any shadows.
4596            return RenderCommandResult::Success;
4597        };
4598
4599        let Some(bind_group) = mesh_phase_bind_groups.get(
4600            metadata_slab_id,
4601            lightmap_slab_index,
4602            is_skinned,
4603            morph_bind_group_key,
4604            has_motion_vector_prepass,
4605        ) else {
4606            return RenderCommandResult::Failure(
4607                "The MeshBindGroups resource wasn't set in the render phase. \
4608                It should be set by the prepare_mesh_bind_group system.\n\
4609                This is a bevy bug! Please open an issue.",
4610            );
4611        };
4612
4613        let mut dynamic_offsets: [u32; 5] = Default::default();
4614        let mut offset_count = 0;
4615        if let PhaseItemExtraIndex::DynamicOffset(dynamic_offset) = item.extra_index() {
4616            dynamic_offsets[offset_count] = dynamic_offset;
4617            offset_count += 1;
4618        }
4619        if skins_use_uniform_buffers {
4620            if let Some(current_skin_index) = current_skin_byte_offset {
4621                dynamic_offsets[offset_count] = current_skin_index.byte_offset;
4622                offset_count += 1;
4623            }
4624            if let Some(current_morph_index) = current_morph_index {
4625                dynamic_offsets[offset_count] = current_morph_index.index;
4626                offset_count += 1;
4627            }
4628        }
4629
4630        // Attach motion vectors if needed.
4631        if skins_use_uniform_buffers && has_motion_vector_prepass {
4632            // Attach the previous skin index for motion vector computation.
4633            if let Some(current_skin_byte_offset) = current_skin_byte_offset {
4634                dynamic_offsets[offset_count] = current_skin_byte_offset.byte_offset;
4635                offset_count += 1;
4636            }
4637
4638            // Attach the previous morph index for motion vector computation. If
4639            // there isn't one, just use zero as the shader will ignore it.
4640            if current_morph_index.is_some() {
4641                match prev_morph_index {
4642                    Some(prev_morph_index) => {
4643                        dynamic_offsets[offset_count] = prev_morph_index.index;
4644                    }
4645                    None => dynamic_offsets[offset_count] = 0,
4646                }
4647                offset_count += 1;
4648            }
4649        }
4650
4651        pass.set_bind_group(I, bind_group, &dynamic_offsets[0..offset_count]);
4652
4653        RenderCommandResult::Success
4654    }
4655}
4656
4657pub struct DrawMesh;
4658impl<P: PhaseItem> RenderCommand<P> for DrawMesh {
4659    type Param = (
4660        SRes<RenderAssets<RenderMesh>>,
4661        SRes<RenderMeshInstances>,
4662        SRes<IndirectParametersBuffers>,
4663        SRes<PipelineCache>,
4664        SRes<MeshAllocator>,
4665        Option<SRes<PreprocessPipelines>>,
4666        SRes<GpuPreprocessingSupport>,
4667    );
4668    type ViewQuery = Has<PreprocessBindGroups>;
4669    type ItemQuery = ();
4670    #[inline]
4671    fn render<'w>(
4672        item: &P,
4673        has_preprocess_bind_group: ROQueryItem<Self::ViewQuery>,
4674        _item_query: Option<()>,
4675        (
4676            meshes,
4677            mesh_instances,
4678            indirect_parameters_buffer,
4679            pipeline_cache,
4680            mesh_allocator,
4681            preprocess_pipelines,
4682            preprocessing_support,
4683        ): SystemParamItem<'w, '_, Self::Param>,
4684        pass: &mut TrackedRenderPass<'w>,
4685    ) -> RenderCommandResult {
4686        // If we're using GPU preprocessing, then we're dependent on that
4687        // compute shader having been run, which of course can only happen if
4688        // it's compiled. Otherwise, our mesh instance data won't be present.
4689        if let Some(preprocess_pipelines) = preprocess_pipelines
4690            && (!has_preprocess_bind_group
4691                || !preprocess_pipelines
4692                    .pipelines_are_loaded(&pipeline_cache, &preprocessing_support))
4693        {
4694            return RenderCommandResult::Skip;
4695        }
4696
4697        let meshes = meshes.into_inner();
4698        let mesh_instances = mesh_instances.into_inner();
4699        let indirect_parameters_buffer = indirect_parameters_buffer.into_inner();
4700        let mesh_allocator = mesh_allocator.into_inner();
4701
4702        let Some(mesh_asset_id) = mesh_instances.mesh_asset_id(item.main_entity()) else {
4703            return RenderCommandResult::Skip;
4704        };
4705        let Some(gpu_mesh) = meshes.get(mesh_asset_id) else {
4706            return RenderCommandResult::Skip;
4707        };
4708        let Some(vertex_buffer_slice) = mesh_allocator.mesh_vertex_slice(&mesh_asset_id) else {
4709            return RenderCommandResult::Skip;
4710        };
4711
4712        pass.set_vertex_buffer(0, vertex_buffer_slice.buffer.slice(..));
4713
4714        let batch_range = item.batch_range();
4715
4716        // Draw either directly or indirectly, as appropriate. If we're in
4717        // indirect mode, we can additionally multi-draw. (We can't multi-draw
4718        // in direct mode because `wgpu` doesn't expose that functionality.)
4719        match &gpu_mesh.buffer_info {
4720            RenderMeshBufferInfo::Indexed {
4721                index_format,
4722                count,
4723            } => {
4724                let Some(index_buffer_slice) = mesh_allocator.mesh_index_slice(&mesh_asset_id)
4725                else {
4726                    return RenderCommandResult::Skip;
4727                };
4728
4729                pass.set_index_buffer(index_buffer_slice.buffer.slice(..), *index_format);
4730
4731                match item.extra_index() {
4732                    PhaseItemExtraIndex::None | PhaseItemExtraIndex::DynamicOffset(_) => {
4733                        pass.draw_indexed(
4734                            index_buffer_slice.range.start
4735                                ..(index_buffer_slice.range.start + *count),
4736                            vertex_buffer_slice.range.start as i32,
4737                            batch_range.clone(),
4738                        );
4739                    }
4740                    PhaseItemExtraIndex::IndirectParametersIndex {
4741                        range: indirect_parameters_range,
4742                        batch_set_index,
4743                    } => {
4744                        // Look up the indirect parameters buffer, as well as
4745                        // the buffer we're going to use for
4746                        // `multi_draw_indexed_indirect_count` (if available).
4747                        let Some(phase_indirect_parameters_buffers) =
4748                            indirect_parameters_buffer.get(&TypeId::of::<P>())
4749                        else {
4750                            warn!(
4751                                "Not rendering mesh because indexed indirect parameters buffer \
4752                                 wasn't present for this phase",
4753                            );
4754                            return RenderCommandResult::Skip;
4755                        };
4756                        let (Some(indirect_parameters_buffer), Some(batch_sets_buffer)) = (
4757                            phase_indirect_parameters_buffers.indexed.data_buffer(),
4758                            phase_indirect_parameters_buffers
4759                                .indexed
4760                                .batch_sets_buffer(),
4761                        ) else {
4762                            warn!(
4763                                "Not rendering mesh because indexed indirect parameters buffer \
4764                                 wasn't present",
4765                            );
4766                            return RenderCommandResult::Skip;
4767                        };
4768
4769                        // Calculate the location of the indirect parameters
4770                        // within the buffer.
4771                        let indirect_parameters_offset = indirect_parameters_range.start as u64
4772                            * size_of::<IndirectParametersIndexed>() as u64;
4773                        let indirect_parameters_count =
4774                            indirect_parameters_range.end - indirect_parameters_range.start;
4775
4776                        // If we're using `multi_draw_indirect_count`, take the
4777                        // number of batches from the appropriate position in
4778                        // the batch sets buffer. Otherwise, supply the size of
4779                        // the batch set.
4780                        match batch_set_index {
4781                            Some(batch_set_index) => {
4782                                let count_offset = u32::from(batch_set_index)
4783                                    * (size_of::<IndirectBatchSet>() as u32);
4784                                pass.multi_draw_indexed_indirect_count(
4785                                    indirect_parameters_buffer,
4786                                    indirect_parameters_offset,
4787                                    batch_sets_buffer,
4788                                    count_offset as u64,
4789                                    indirect_parameters_count,
4790                                );
4791                            }
4792                            None => {
4793                                pass.multi_draw_indexed_indirect(
4794                                    indirect_parameters_buffer,
4795                                    indirect_parameters_offset,
4796                                    indirect_parameters_count,
4797                                );
4798                            }
4799                        }
4800                    }
4801                }
4802            }
4803
4804            RenderMeshBufferInfo::NonIndexed => match item.extra_index() {
4805                PhaseItemExtraIndex::None | PhaseItemExtraIndex::DynamicOffset(_) => {
4806                    pass.draw(vertex_buffer_slice.range, batch_range.clone());
4807                }
4808                PhaseItemExtraIndex::IndirectParametersIndex {
4809                    range: indirect_parameters_range,
4810                    batch_set_index,
4811                } => {
4812                    // Look up the indirect parameters buffer, as well as the
4813                    // buffer we're going to use for
4814                    // `multi_draw_indirect_count` (if available).
4815                    let Some(phase_indirect_parameters_buffers) =
4816                        indirect_parameters_buffer.get(&TypeId::of::<P>())
4817                    else {
4818                        warn!(
4819                            "Not rendering mesh because non-indexed indirect parameters buffer \
4820                                 wasn't present for this phase",
4821                        );
4822                        return RenderCommandResult::Skip;
4823                    };
4824                    let (Some(indirect_parameters_buffer), Some(batch_sets_buffer)) = (
4825                        phase_indirect_parameters_buffers.non_indexed.data_buffer(),
4826                        phase_indirect_parameters_buffers
4827                            .non_indexed
4828                            .batch_sets_buffer(),
4829                    ) else {
4830                        warn!(
4831                            "Not rendering mesh because non-indexed indirect parameters buffer \
4832                             wasn't present"
4833                        );
4834                        return RenderCommandResult::Skip;
4835                    };
4836
4837                    // Calculate the location of the indirect parameters within
4838                    // the buffer.
4839                    let indirect_parameters_offset = indirect_parameters_range.start as u64
4840                        * size_of::<IndirectParametersNonIndexed>() as u64;
4841                    let indirect_parameters_count =
4842                        indirect_parameters_range.end - indirect_parameters_range.start;
4843
4844                    // If we're using `multi_draw_indirect_count`, take the
4845                    // number of batches from the appropriate position in the
4846                    // batch sets buffer. Otherwise, supply the size of the
4847                    // batch set.
4848                    match batch_set_index {
4849                        Some(batch_set_index) => {
4850                            let count_offset =
4851                                u32::from(batch_set_index) * (size_of::<IndirectBatchSet>() as u32);
4852                            pass.multi_draw_indirect_count(
4853                                indirect_parameters_buffer,
4854                                indirect_parameters_offset,
4855                                batch_sets_buffer,
4856                                count_offset as u64,
4857                                indirect_parameters_count,
4858                            );
4859                        }
4860                        None => {
4861                            pass.multi_draw_indirect(
4862                                indirect_parameters_buffer,
4863                                indirect_parameters_offset,
4864                                indirect_parameters_count,
4865                            );
4866                        }
4867                    }
4868                }
4869            },
4870        }
4871        RenderCommandResult::Success
4872    }
4873}
4874
4875#[cfg(test)]
4876mod tests {
4877    use core::sync::atomic::{AtomicU64, Ordering};
4878
4879    use super::{AtomicU64ZeroBitIter, MeshPipelineKey};
4880
4881    #[test]
4882    fn mesh_key_msaa_samples() {
4883        for i in [1, 2, 4, 8, 16, 32, 64, 128] {
4884            assert_eq!(MeshPipelineKey::from_msaa_samples(i).msaa_samples(), i);
4885        }
4886    }
4887
4888    /// Tests that the `AtomicU64ZeroBitIter` works.
4889    #[test]
4890    fn atomic_u64_zero_bit_iter() {
4891        // Randomly-generated test data.
4892        // We use separate constants for this because the Rust compiler
4893        // complains if you make a static array of slices containing atomics.
4894        static TEST_DATA_0: [AtomicU64; 1] = [AtomicU64::new(0x7b52f5ca63498b6a)];
4895        static TEST_DATA_1: [AtomicU64; 2] = [
4896            AtomicU64::new(0x5705b33451b95827),
4897            AtomicU64::new(0x1939ee614074abad),
4898        ];
4899        static TEST_DATA_2: [AtomicU64; 3] = [
4900            AtomicU64::new(0xf33c508d14d145c),
4901            AtomicU64::new(0x2a4749823594ea),
4902            AtomicU64::new(0x5e68df04196a3818),
4903        ];
4904        static TEST_DATA_3: [AtomicU64; 6] = [
4905            AtomicU64::new(0x2336dbda2bd74d09),
4906            AtomicU64::new(0x10b7da1dacf22d33),
4907            AtomicU64::new(0x6eaaf908d957923a),
4908            AtomicU64::new(0x7ec7ffb64cb9c4a6),
4909            AtomicU64::new(0x6dd027da8ad22fa0),
4910            AtomicU64::new(0x13278c5caa74f73d),
4911        ];
4912        static TEST_DATA_4: [AtomicU64; 4] = [
4913            AtomicU64::new(0x32c66f0334bb09e9),
4914            AtomicU64::new(0x60815770d307bdcd),
4915            AtomicU64::new(0x6270a1e972fb8469),
4916            AtomicU64::new(0x610e995c042d6df4),
4917        ];
4918        static TEST_DATA_5: [AtomicU64; 3] = [
4919            AtomicU64::new(0x7fe756fc690097eb),
4920            AtomicU64::new(0x15d87ce6679b1bd8),
4921            AtomicU64::new(0x1985ea515135b255),
4922        ];
4923        static TEST_DATA_6: [AtomicU64; 4] = [
4924            AtomicU64::new(0x1afb9d361c135827),
4925            AtomicU64::new(0x4a79ad582628a854),
4926            AtomicU64::new(0x57a802160315c974),
4927            AtomicU64::new(0x1c0aef068db1f6fb),
4928        ];
4929        static TEST_DATA_7: [AtomicU64; 3] = [
4930            AtomicU64::new(0x53d10eb77230c696),
4931            AtomicU64::new(0x2ca2d709994855fb),
4932            AtomicU64::new(0x26536a13f647f2f7),
4933        ];
4934        static TEST_DATA_8: [AtomicU64; 2] = [
4935            AtomicU64::new(0x6ed95eb903155e00),
4936            AtomicU64::new(0x5e5d58eec92cba0),
4937        ];
4938        static TEST_DATA_9: [AtomicU64; 1] = [AtomicU64::new(0x2caa4b77512b1664)];
4939
4940        let test_data = [
4941            &TEST_DATA_0[..],
4942            &TEST_DATA_1[..],
4943            &TEST_DATA_2[..],
4944            &TEST_DATA_3[..],
4945            &TEST_DATA_4[..],
4946            &TEST_DATA_5[..],
4947            &TEST_DATA_6[..],
4948            &TEST_DATA_7[..],
4949            &TEST_DATA_8[..],
4950            &TEST_DATA_9[..],
4951        ];
4952
4953        for bits in &test_data {
4954            // Compute the zero positions naively.
4955            let mut reference_zero_positions = vec![];
4956            for (word_index, word) in (*bits).iter().enumerate() {
4957                let word = word.load(Ordering::Relaxed);
4958                for bit_index in 0..64 {
4959                    if ((word >> bit_index) & 1) == 0 {
4960                        reference_zero_positions.push((word_index * 64 + bit_index) as u32);
4961                    }
4962                }
4963            }
4964
4965            // Compute the zero positions using the iterator.
4966            let test_zero_positions: Vec<_> = AtomicU64ZeroBitIter::new(bits).collect();
4967
4968            // Check for equality.
4969            assert_eq!(test_zero_positions, reference_zero_positions);
4970        }
4971    }
4972}