Skip to main content

bevy_pbr/render/
mesh.rs

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