bevy_pbr/render/
mesh.rs

1use crate::material_bind_groups::{MaterialBindGroupIndex, MaterialBindGroupSlot};
2use allocator::MeshAllocator;
3use bevy_asset::{load_internal_asset, AssetId};
4use bevy_core_pipeline::{
5    core_3d::{AlphaMask3d, Opaque3d, Transmissive3d, Transparent3d, CORE_3D_DEPTH_FORMAT},
6    deferred::{AlphaMask3dDeferred, Opaque3dDeferred},
7    oit::{prepare_oit_buffers, OrderIndependentTransparencySettingsOffset},
8    prepass::MotionVectorPrepass,
9};
10use bevy_derive::{Deref, DerefMut};
11use bevy_diagnostic::FrameCount;
12use bevy_ecs::{
13    prelude::*,
14    query::{QueryData, ROQueryItem},
15    system::{lifetimeless::*, SystemParamItem, SystemState},
16};
17use bevy_image::{BevyDefault, ImageSampler, TextureFormatPixelInfo};
18use bevy_math::{Affine3, Rect, UVec2, Vec3, Vec4};
19use bevy_platform::collections::{hash_map::Entry, HashMap};
20use bevy_render::{
21    batching::{
22        gpu_preprocessing::{
23            self, GpuPreprocessingSupport, IndirectBatchSet, IndirectParametersBuffers,
24            IndirectParametersCpuMetadata, IndirectParametersIndexed, IndirectParametersNonIndexed,
25            InstanceInputUniformBuffer, UntypedPhaseIndirectParametersBuffers,
26        },
27        no_gpu_preprocessing, GetBatchData, GetFullBatchData, NoAutomaticBatching,
28    },
29    camera::Camera,
30    mesh::{skinning::SkinnedMesh, *},
31    primitives::Aabb,
32    render_asset::RenderAssets,
33    render_phase::{
34        BinnedRenderPhasePlugin, InputUniformIndex, PhaseItem, PhaseItemExtraIndex, RenderCommand,
35        RenderCommandResult, SortedRenderPhasePlugin, TrackedRenderPass,
36    },
37    render_resource::*,
38    renderer::{RenderAdapter, RenderDevice, RenderQueue},
39    sync_world::MainEntityHashSet,
40    texture::{DefaultImageSampler, GpuImage},
41    view::{
42        self, NoFrustumCulling, NoIndirectDrawing, RenderVisibilityRanges, RetainedViewEntity,
43        ViewTarget, ViewUniformOffset, ViewVisibility, VisibilityRange,
44    },
45    Extract,
46};
47use bevy_transform::components::GlobalTransform;
48use bevy_utils::{default, Parallel, TypeIdMap};
49use core::any::TypeId;
50use core::mem::size_of;
51use material_bind_groups::MaterialBindingId;
52use tracing::{error, warn};
53
54use self::irradiance_volume::IRRADIANCE_VOLUMES_ARE_USABLE;
55use crate::environment_map::EnvironmentMapLight;
56use crate::irradiance_volume::IrradianceVolume;
57use crate::{
58    render::{
59        morph::{
60            extract_morphs, no_automatic_morph_batching, prepare_morphs, MorphIndices,
61            MorphUniforms,
62        },
63        skin::no_automatic_skin_batching,
64    },
65    *,
66};
67use bevy_core_pipeline::core_3d::Camera3d;
68use bevy_core_pipeline::oit::OrderIndependentTransparencySettings;
69use bevy_core_pipeline::prepass::{DeferredPrepass, DepthPrepass, NormalPrepass};
70use bevy_core_pipeline::tonemapping::{DebandDither, Tonemapping};
71use bevy_ecs::component::Tick;
72use bevy_ecs::system::SystemChangeTick;
73use bevy_render::camera::TemporalJitter;
74use bevy_render::prelude::Msaa;
75use bevy_render::sync_world::{MainEntity, MainEntityHashMap};
76use bevy_render::view::ExtractedView;
77use bevy_render::RenderSet::PrepareAssets;
78use bytemuck::{Pod, Zeroable};
79use nonmax::{NonMaxU16, NonMaxU32};
80use smallvec::{smallvec, SmallVec};
81use static_assertions::const_assert_eq;
82
83/// Provides support for rendering 3D meshes.
84pub struct MeshRenderPlugin {
85    /// Whether we're building [`MeshUniform`]s on GPU.
86    ///
87    /// This requires compute shader support and so will be forcibly disabled if
88    /// the platform doesn't support those.
89    pub use_gpu_instance_buffer_builder: bool,
90    /// Debugging flags that can optionally be set when constructing the renderer.
91    pub debug_flags: RenderDebugFlags,
92}
93
94impl MeshRenderPlugin {
95    /// Creates a new [`MeshRenderPlugin`] with the given debug flags.
96    pub fn new(debug_flags: RenderDebugFlags) -> MeshRenderPlugin {
97        MeshRenderPlugin {
98            use_gpu_instance_buffer_builder: false,
99            debug_flags,
100        }
101    }
102}
103
104pub const FORWARD_IO_HANDLE: Handle<Shader> = weak_handle!("38111de1-6e35-4dbb-877b-7b6f9334baf6");
105pub const MESH_VIEW_TYPES_HANDLE: Handle<Shader> =
106    weak_handle!("979493db-4ae1-4003-b5c6-fcbb88b152a2");
107pub const MESH_VIEW_BINDINGS_HANDLE: Handle<Shader> =
108    weak_handle!("c6fe674b-4c21-4d4b-867a-352848da5337");
109pub const MESH_TYPES_HANDLE: Handle<Shader> = weak_handle!("a4a3fc2e-a57e-4083-a8ab-2840176927f2");
110pub const MESH_BINDINGS_HANDLE: Handle<Shader> =
111    weak_handle!("84e7f9e6-e566-4a61-914e-c568f5dabf49");
112pub const MESH_FUNCTIONS_HANDLE: Handle<Shader> =
113    weak_handle!("c46aa0f0-6c0c-4b3a-80bf-d8213c771f12");
114pub const MESH_SHADER_HANDLE: Handle<Shader> = weak_handle!("1a7bbae8-4b4f-48a7-b53b-e6822e56f321");
115pub const SKINNING_HANDLE: Handle<Shader> = weak_handle!("7474e812-2506-4cbf-9de3-fe07e5c6ff24");
116pub const MORPH_HANDLE: Handle<Shader> = weak_handle!("da30aac7-34cc-431d-a07f-15b1a783008c");
117pub const OCCLUSION_CULLING_HANDLE: Handle<Shader> =
118    weak_handle!("eaea07d9-7516-482c-aa42-6f8e9927e1f0");
119
120/// How many textures are allowed in the view bind group layout (`@group(0)`) before
121/// broader compatibility with WebGL and WebGPU is at risk, due to the minimum guaranteed
122/// values for `MAX_TEXTURE_IMAGE_UNITS` (in WebGL) and `maxSampledTexturesPerShaderStage` (in WebGPU),
123/// currently both at 16.
124///
125/// We use 10 here because it still leaves us, in a worst case scenario, with 6 textures for the other bind groups.
126///
127/// See: <https://gpuweb.github.io/gpuweb/#limits>
128#[cfg(debug_assertions)]
129pub const MESH_PIPELINE_VIEW_LAYOUT_SAFE_MAX_TEXTURES: usize = 10;
130
131impl Plugin for MeshRenderPlugin {
132    fn build(&self, app: &mut App) {
133        load_internal_asset!(app, FORWARD_IO_HANDLE, "forward_io.wgsl", Shader::from_wgsl);
134        load_internal_asset!(
135            app,
136            MESH_VIEW_TYPES_HANDLE,
137            "mesh_view_types.wgsl",
138            Shader::from_wgsl_with_defs,
139            vec![
140                ShaderDefVal::UInt(
141                    "MAX_DIRECTIONAL_LIGHTS".into(),
142                    MAX_DIRECTIONAL_LIGHTS as u32
143                ),
144                ShaderDefVal::UInt(
145                    "MAX_CASCADES_PER_LIGHT".into(),
146                    MAX_CASCADES_PER_LIGHT as u32,
147                )
148            ]
149        );
150        load_internal_asset!(
151            app,
152            MESH_VIEW_BINDINGS_HANDLE,
153            "mesh_view_bindings.wgsl",
154            Shader::from_wgsl
155        );
156        load_internal_asset!(app, MESH_TYPES_HANDLE, "mesh_types.wgsl", Shader::from_wgsl);
157        load_internal_asset!(
158            app,
159            MESH_FUNCTIONS_HANDLE,
160            "mesh_functions.wgsl",
161            Shader::from_wgsl
162        );
163        load_internal_asset!(app, MESH_SHADER_HANDLE, "mesh.wgsl", Shader::from_wgsl);
164        load_internal_asset!(app, SKINNING_HANDLE, "skinning.wgsl", Shader::from_wgsl);
165        load_internal_asset!(app, MORPH_HANDLE, "morph.wgsl", Shader::from_wgsl);
166        load_internal_asset!(
167            app,
168            OCCLUSION_CULLING_HANDLE,
169            "occlusion_culling.wgsl",
170            Shader::from_wgsl
171        );
172
173        if app.get_sub_app(RenderApp).is_none() {
174            return;
175        }
176
177        app.add_systems(
178            PostUpdate,
179            (no_automatic_skin_batching, no_automatic_morph_batching),
180        )
181        .add_plugins((
182            BinnedRenderPhasePlugin::<Opaque3d, MeshPipeline>::new(self.debug_flags),
183            BinnedRenderPhasePlugin::<AlphaMask3d, MeshPipeline>::new(self.debug_flags),
184            BinnedRenderPhasePlugin::<Shadow, MeshPipeline>::new(self.debug_flags),
185            BinnedRenderPhasePlugin::<Opaque3dDeferred, MeshPipeline>::new(self.debug_flags),
186            BinnedRenderPhasePlugin::<AlphaMask3dDeferred, MeshPipeline>::new(self.debug_flags),
187            SortedRenderPhasePlugin::<Transmissive3d, MeshPipeline>::new(self.debug_flags),
188            SortedRenderPhasePlugin::<Transparent3d, MeshPipeline>::new(self.debug_flags),
189        ));
190
191        if let Some(render_app) = app.get_sub_app_mut(RenderApp) {
192            render_app
193                .init_resource::<MorphUniforms>()
194                .init_resource::<MorphIndices>()
195                .init_resource::<MeshCullingDataBuffer>()
196                .init_resource::<RenderMaterialInstances>()
197                .configure_sets(
198                    ExtractSchedule,
199                    ExtractMeshesSet
200                        .after(view::extract_visibility_ranges)
201                        .after(late_sweep_material_instances),
202                )
203                .add_systems(
204                    ExtractSchedule,
205                    (
206                        extract_skins,
207                        extract_morphs,
208                        gpu_preprocessing::clear_batched_gpu_instance_buffers::<MeshPipeline>
209                            .before(ExtractMeshesSet),
210                    ),
211                )
212                .add_systems(
213                    Render,
214                    (
215                        set_mesh_motion_vector_flags.in_set(RenderSet::PrepareMeshes),
216                        prepare_skins.in_set(RenderSet::PrepareResources),
217                        prepare_morphs.in_set(RenderSet::PrepareResources),
218                        prepare_mesh_bind_groups.in_set(RenderSet::PrepareBindGroups),
219                        prepare_mesh_view_bind_groups
220                            .in_set(RenderSet::PrepareBindGroups)
221                            .after(prepare_oit_buffers),
222                        no_gpu_preprocessing::clear_batched_cpu_instance_buffers::<MeshPipeline>
223                            .in_set(RenderSet::Cleanup)
224                            .after(RenderSet::Render),
225                    ),
226                );
227        }
228    }
229
230    fn finish(&self, app: &mut App) {
231        let mut mesh_bindings_shader_defs = Vec::with_capacity(1);
232
233        if let Some(render_app) = app.get_sub_app_mut(RenderApp) {
234            render_app
235                .init_resource::<ViewKeyCache>()
236                .init_resource::<ViewSpecializationTicks>()
237                .init_resource::<GpuPreprocessingSupport>()
238                .init_resource::<SkinUniforms>()
239                .add_systems(
240                    Render,
241                    check_views_need_specialization.in_set(PrepareAssets),
242                );
243
244            let gpu_preprocessing_support =
245                render_app.world().resource::<GpuPreprocessingSupport>();
246            let use_gpu_instance_buffer_builder =
247                self.use_gpu_instance_buffer_builder && gpu_preprocessing_support.is_available();
248
249            let render_mesh_instances = RenderMeshInstances::new(use_gpu_instance_buffer_builder);
250            render_app.insert_resource(render_mesh_instances);
251
252            if use_gpu_instance_buffer_builder {
253                render_app
254                    .init_resource::<gpu_preprocessing::BatchedInstanceBuffers<
255                        MeshUniform,
256                        MeshInputUniform
257                    >>()
258                    .init_resource::<RenderMeshInstanceGpuQueues>()
259                    .init_resource::<MeshesToReextractNextFrame>()
260                    .add_systems(
261                        ExtractSchedule,
262                        extract_meshes_for_gpu_building.in_set(ExtractMeshesSet),
263                    )
264                    .add_systems(
265                        Render,
266                        (
267                            gpu_preprocessing::write_batched_instance_buffers::<MeshPipeline>
268                                .in_set(RenderSet::PrepareResourcesFlush),
269                            gpu_preprocessing::delete_old_work_item_buffers::<MeshPipeline>
270                                .in_set(RenderSet::PrepareResources),
271                            collect_meshes_for_gpu_building
272                                .in_set(RenderSet::PrepareMeshes)
273                                // This must be before
274                                // `set_mesh_motion_vector_flags` so it doesn't
275                                // overwrite those flags.
276                                .before(set_mesh_motion_vector_flags),
277                        ),
278                    );
279            } else {
280                let render_device = render_app.world().resource::<RenderDevice>();
281                let cpu_batched_instance_buffer =
282                    no_gpu_preprocessing::BatchedInstanceBuffer::<MeshUniform>::new(render_device);
283                render_app
284                    .insert_resource(cpu_batched_instance_buffer)
285                    .add_systems(
286                        ExtractSchedule,
287                        extract_meshes_for_cpu_building.in_set(ExtractMeshesSet),
288                    )
289                    .add_systems(
290                        Render,
291                        no_gpu_preprocessing::write_batched_instance_buffer::<MeshPipeline>
292                            .in_set(RenderSet::PrepareResourcesFlush),
293                    );
294            };
295
296            let render_device = render_app.world().resource::<RenderDevice>();
297            if let Some(per_object_buffer_batch_size) =
298                GpuArrayBuffer::<MeshUniform>::batch_size(render_device)
299            {
300                mesh_bindings_shader_defs.push(ShaderDefVal::UInt(
301                    "PER_OBJECT_BUFFER_BATCH_SIZE".into(),
302                    per_object_buffer_batch_size,
303                ));
304            }
305
306            render_app
307                .init_resource::<MeshPipelineViewLayouts>()
308                .init_resource::<MeshPipeline>();
309        }
310
311        // Load the mesh_bindings shader module here as it depends on runtime information about
312        // whether storage buffers are supported, or the maximum uniform buffer binding size.
313        load_internal_asset!(
314            app,
315            MESH_BINDINGS_HANDLE,
316            "mesh_bindings.wgsl",
317            Shader::from_wgsl_with_defs,
318            mesh_bindings_shader_defs
319        );
320    }
321}
322
323#[derive(Resource, Deref, DerefMut, Default, Debug, Clone)]
324pub struct ViewKeyCache(HashMap<RetainedViewEntity, MeshPipelineKey>);
325
326#[derive(Resource, Deref, DerefMut, Default, Debug, Clone)]
327pub struct ViewSpecializationTicks(HashMap<RetainedViewEntity, Tick>);
328
329pub fn check_views_need_specialization(
330    mut view_key_cache: ResMut<ViewKeyCache>,
331    mut view_specialization_ticks: ResMut<ViewSpecializationTicks>,
332    mut views: Query<(
333        &ExtractedView,
334        &Msaa,
335        Option<&Tonemapping>,
336        Option<&DebandDither>,
337        Option<&ShadowFilteringMethod>,
338        Has<ScreenSpaceAmbientOcclusion>,
339        (
340            Has<NormalPrepass>,
341            Has<DepthPrepass>,
342            Has<MotionVectorPrepass>,
343            Has<DeferredPrepass>,
344        ),
345        Option<&Camera3d>,
346        Has<TemporalJitter>,
347        Option<&Projection>,
348        Has<DistanceFog>,
349        (
350            Has<RenderViewLightProbes<EnvironmentMapLight>>,
351            Has<RenderViewLightProbes<IrradianceVolume>>,
352        ),
353        Has<OrderIndependentTransparencySettings>,
354    )>,
355    ticks: SystemChangeTick,
356) {
357    for (
358        view,
359        msaa,
360        tonemapping,
361        dither,
362        shadow_filter_method,
363        ssao,
364        (normal_prepass, depth_prepass, motion_vector_prepass, deferred_prepass),
365        camera_3d,
366        temporal_jitter,
367        projection,
368        distance_fog,
369        (has_environment_maps, has_irradiance_volumes),
370        has_oit,
371    ) in views.iter_mut()
372    {
373        let mut view_key = MeshPipelineKey::from_msaa_samples(msaa.samples())
374            | MeshPipelineKey::from_hdr(view.hdr);
375
376        if normal_prepass {
377            view_key |= MeshPipelineKey::NORMAL_PREPASS;
378        }
379
380        if depth_prepass {
381            view_key |= MeshPipelineKey::DEPTH_PREPASS;
382        }
383
384        if motion_vector_prepass {
385            view_key |= MeshPipelineKey::MOTION_VECTOR_PREPASS;
386        }
387
388        if deferred_prepass {
389            view_key |= MeshPipelineKey::DEFERRED_PREPASS;
390        }
391
392        if temporal_jitter {
393            view_key |= MeshPipelineKey::TEMPORAL_JITTER;
394        }
395
396        if has_environment_maps {
397            view_key |= MeshPipelineKey::ENVIRONMENT_MAP;
398        }
399
400        if has_irradiance_volumes {
401            view_key |= MeshPipelineKey::IRRADIANCE_VOLUME;
402        }
403
404        if has_oit {
405            view_key |= MeshPipelineKey::OIT_ENABLED;
406        }
407
408        if let Some(projection) = projection {
409            view_key |= match projection {
410                Projection::Perspective(_) => MeshPipelineKey::VIEW_PROJECTION_PERSPECTIVE,
411                Projection::Orthographic(_) => MeshPipelineKey::VIEW_PROJECTION_ORTHOGRAPHIC,
412                Projection::Custom(_) => MeshPipelineKey::VIEW_PROJECTION_NONSTANDARD,
413            };
414        }
415
416        match shadow_filter_method.unwrap_or(&ShadowFilteringMethod::default()) {
417            ShadowFilteringMethod::Hardware2x2 => {
418                view_key |= MeshPipelineKey::SHADOW_FILTER_METHOD_HARDWARE_2X2;
419            }
420            ShadowFilteringMethod::Gaussian => {
421                view_key |= MeshPipelineKey::SHADOW_FILTER_METHOD_GAUSSIAN;
422            }
423            ShadowFilteringMethod::Temporal => {
424                view_key |= MeshPipelineKey::SHADOW_FILTER_METHOD_TEMPORAL;
425            }
426        }
427
428        if !view.hdr {
429            if let Some(tonemapping) = tonemapping {
430                view_key |= MeshPipelineKey::TONEMAP_IN_SHADER;
431                view_key |= tonemapping_pipeline_key(*tonemapping);
432            }
433            if let Some(DebandDither::Enabled) = dither {
434                view_key |= MeshPipelineKey::DEBAND_DITHER;
435            }
436        }
437        if ssao {
438            view_key |= MeshPipelineKey::SCREEN_SPACE_AMBIENT_OCCLUSION;
439        }
440        if distance_fog {
441            view_key |= MeshPipelineKey::DISTANCE_FOG;
442        }
443        if let Some(camera_3d) = camera_3d {
444            view_key |= screen_space_specular_transmission_pipeline_key(
445                camera_3d.screen_space_specular_transmission_quality,
446            );
447        }
448        if !view_key_cache
449            .get_mut(&view.retained_view_entity)
450            .is_some_and(|current_key| *current_key == view_key)
451        {
452            view_key_cache.insert(view.retained_view_entity, view_key);
453            view_specialization_ticks.insert(view.retained_view_entity, ticks.this_run());
454        }
455    }
456}
457
458#[derive(Component)]
459pub struct MeshTransforms {
460    pub world_from_local: Affine3,
461    pub previous_world_from_local: Affine3,
462    pub flags: u32,
463}
464
465#[derive(ShaderType, Clone)]
466pub struct MeshUniform {
467    // Affine 4x3 matrices transposed to 3x4
468    pub world_from_local: [Vec4; 3],
469    pub previous_world_from_local: [Vec4; 3],
470    // 3x3 matrix packed in mat2x4 and f32 as:
471    //   [0].xyz, [1].x,
472    //   [1].yz, [2].xy
473    //   [2].z
474    pub local_from_world_transpose_a: [Vec4; 2],
475    pub local_from_world_transpose_b: f32,
476    pub flags: u32,
477    // Four 16-bit unsigned normalized UV values packed into a `UVec2`:
478    //
479    //                         <--- MSB                   LSB --->
480    //                         +---- min v ----+ +---- min u ----+
481    //     lightmap_uv_rect.x: vvvvvvvv vvvvvvvv uuuuuuuu uuuuuuuu,
482    //                         +---- max v ----+ +---- max u ----+
483    //     lightmap_uv_rect.y: VVVVVVVV VVVVVVVV UUUUUUUU UUUUUUUU,
484    //
485    // (MSB: most significant bit; LSB: least significant bit.)
486    pub lightmap_uv_rect: UVec2,
487    /// The index of this mesh's first vertex in the vertex buffer.
488    ///
489    /// Multiple meshes can be packed into a single vertex buffer (see
490    /// [`MeshAllocator`]). This value stores the offset of the first vertex in
491    /// this mesh in that buffer.
492    pub first_vertex_index: u32,
493    /// The current skin index, or `u32::MAX` if there's no skin.
494    pub current_skin_index: u32,
495    /// The material and lightmap indices, packed into 32 bits.
496    ///
497    /// Low 16 bits: index of the material inside the bind group data.
498    /// High 16 bits: index of the lightmap in the binding array.
499    pub material_and_lightmap_bind_group_slot: u32,
500    /// User supplied tag to identify this mesh instance.
501    pub tag: u32,
502    /// Padding.
503    pub pad: u32,
504}
505
506/// Information that has to be transferred from CPU to GPU in order to produce
507/// the full [`MeshUniform`].
508///
509/// This is essentially a subset of the fields in [`MeshUniform`] above.
510#[derive(ShaderType, Pod, Zeroable, Clone, Copy, Default, Debug)]
511#[repr(C)]
512pub struct MeshInputUniform {
513    /// Affine 4x3 matrix transposed to 3x4.
514    pub world_from_local: [Vec4; 3],
515    /// Four 16-bit unsigned normalized UV values packed into a `UVec2`:
516    ///
517    /// ```text
518    ///                         <--- MSB                   LSB --->
519    ///                         +---- min v ----+ +---- min u ----+
520    ///     lightmap_uv_rect.x: vvvvvvvv vvvvvvvv uuuuuuuu uuuuuuuu,
521    ///                         +---- max v ----+ +---- max u ----+
522    ///     lightmap_uv_rect.y: VVVVVVVV VVVVVVVV UUUUUUUU UUUUUUUU,
523    ///
524    /// (MSB: most significant bit; LSB: least significant bit.)
525    /// ```
526    pub lightmap_uv_rect: UVec2,
527    /// Various [`MeshFlags`].
528    pub flags: u32,
529    /// The index of this mesh's [`MeshInputUniform`] in the previous frame's
530    /// buffer, if applicable.
531    ///
532    /// This is used for TAA. If not present, this will be `u32::MAX`.
533    pub previous_input_index: u32,
534    /// The index of this mesh's first vertex in the vertex buffer.
535    ///
536    /// Multiple meshes can be packed into a single vertex buffer (see
537    /// [`MeshAllocator`]). This value stores the offset of the first vertex in
538    /// this mesh in that buffer.
539    pub first_vertex_index: u32,
540    /// The index of this mesh's first index in the index buffer, if any.
541    ///
542    /// Multiple meshes can be packed into a single index buffer (see
543    /// [`MeshAllocator`]). This value stores the offset of the first index in
544    /// this mesh in that buffer.
545    ///
546    /// If this mesh isn't indexed, this value is ignored.
547    pub first_index_index: u32,
548    /// For an indexed mesh, the number of indices that make it up; for a
549    /// non-indexed mesh, the number of vertices in it.
550    pub index_count: u32,
551    /// The current skin index, or `u32::MAX` if there's no skin.
552    pub current_skin_index: u32,
553    /// The material and lightmap indices, packed into 32 bits.
554    ///
555    /// Low 16 bits: index of the material inside the bind group data.
556    /// High 16 bits: index of the lightmap in the binding array.
557    pub material_and_lightmap_bind_group_slot: u32,
558    /// The number of the frame on which this [`MeshInputUniform`] was built.
559    ///
560    /// This is used to validate the previous transform and skin. If this
561    /// [`MeshInputUniform`] wasn't updated on this frame, then we know that
562    /// neither this mesh's transform nor that of its joints have been updated
563    /// on this frame, and therefore the transforms of both this mesh and its
564    /// joints must be identical to those for the previous frame.
565    pub timestamp: u32,
566    /// User supplied tag to identify this mesh instance.
567    pub tag: u32,
568    /// Padding.
569    pub pad: u32,
570}
571
572/// Information about each mesh instance needed to cull it on GPU.
573///
574/// This consists of its axis-aligned bounding box (AABB).
575#[derive(ShaderType, Pod, Zeroable, Clone, Copy, Default)]
576#[repr(C)]
577pub struct MeshCullingData {
578    /// The 3D center of the AABB in model space, padded with an extra unused
579    /// float value.
580    pub aabb_center: Vec4,
581    /// The 3D extents of the AABB in model space, divided by two, padded with
582    /// an extra unused float value.
583    pub aabb_half_extents: Vec4,
584}
585
586/// A GPU buffer that holds the information needed to cull meshes on GPU.
587///
588/// At the moment, this simply holds each mesh's AABB.
589///
590/// To avoid wasting CPU time in the CPU culling case, this buffer will be empty
591/// if GPU culling isn't in use.
592#[derive(Resource, Deref, DerefMut)]
593pub struct MeshCullingDataBuffer(RawBufferVec<MeshCullingData>);
594
595impl MeshUniform {
596    pub fn new(
597        mesh_transforms: &MeshTransforms,
598        first_vertex_index: u32,
599        material_bind_group_slot: MaterialBindGroupSlot,
600        maybe_lightmap: Option<(LightmapSlotIndex, Rect)>,
601        current_skin_index: Option<u32>,
602        tag: Option<u32>,
603    ) -> Self {
604        let (local_from_world_transpose_a, local_from_world_transpose_b) =
605            mesh_transforms.world_from_local.inverse_transpose_3x3();
606        let lightmap_bind_group_slot = match maybe_lightmap {
607            None => u16::MAX,
608            Some((slot_index, _)) => slot_index.into(),
609        };
610
611        Self {
612            world_from_local: mesh_transforms.world_from_local.to_transpose(),
613            previous_world_from_local: mesh_transforms.previous_world_from_local.to_transpose(),
614            lightmap_uv_rect: pack_lightmap_uv_rect(maybe_lightmap.map(|(_, uv_rect)| uv_rect)),
615            local_from_world_transpose_a,
616            local_from_world_transpose_b,
617            flags: mesh_transforms.flags,
618            first_vertex_index,
619            current_skin_index: current_skin_index.unwrap_or(u32::MAX),
620            material_and_lightmap_bind_group_slot: u32::from(material_bind_group_slot)
621                | ((lightmap_bind_group_slot as u32) << 16),
622            tag: tag.unwrap_or(0),
623            pad: 0,
624        }
625    }
626}
627
628// NOTE: These must match the bit flags in bevy_pbr/src/render/mesh_types.wgsl!
629bitflags::bitflags! {
630    /// Various flags and tightly-packed values on a mesh.
631    ///
632    /// Flags grow from the top bit down; other values grow from the bottom bit
633    /// up.
634    #[repr(transparent)]
635    pub struct MeshFlags: u32 {
636        /// Bitmask for the 16-bit index into the LOD array.
637        ///
638        /// This will be `u16::MAX` if this mesh has no LOD.
639        const LOD_INDEX_MASK              = (1 << 16) - 1;
640        /// Disables frustum culling for this mesh.
641        ///
642        /// This corresponds to the
643        /// [`bevy_render::view::visibility::NoFrustumCulling`] component.
644        const NO_FRUSTUM_CULLING          = 1 << 28;
645        const SHADOW_RECEIVER             = 1 << 29;
646        const TRANSMITTED_SHADOW_RECEIVER = 1 << 30;
647        // Indicates the sign of the determinant of the 3x3 model matrix. If the sign is positive,
648        // then the flag should be set, else it should not be set.
649        const SIGN_DETERMINANT_MODEL_3X3  = 1 << 31;
650        const NONE                        = 0;
651        const UNINITIALIZED               = 0xFFFFFFFF;
652    }
653}
654
655impl MeshFlags {
656    fn from_components(
657        transform: &GlobalTransform,
658        lod_index: Option<NonMaxU16>,
659        no_frustum_culling: bool,
660        not_shadow_receiver: bool,
661        transmitted_receiver: bool,
662    ) -> MeshFlags {
663        let mut mesh_flags = if not_shadow_receiver {
664            MeshFlags::empty()
665        } else {
666            MeshFlags::SHADOW_RECEIVER
667        };
668        if no_frustum_culling {
669            mesh_flags |= MeshFlags::NO_FRUSTUM_CULLING;
670        }
671        if transmitted_receiver {
672            mesh_flags |= MeshFlags::TRANSMITTED_SHADOW_RECEIVER;
673        }
674        if transform.affine().matrix3.determinant().is_sign_positive() {
675            mesh_flags |= MeshFlags::SIGN_DETERMINANT_MODEL_3X3;
676        }
677
678        let lod_index_bits = match lod_index {
679            None => u16::MAX,
680            Some(lod_index) => u16::from(lod_index),
681        };
682        mesh_flags |=
683            MeshFlags::from_bits_retain((lod_index_bits as u32) << MeshFlags::LOD_INDEX_SHIFT);
684
685        mesh_flags
686    }
687
688    /// The first bit of the LOD index.
689    pub const LOD_INDEX_SHIFT: u32 = 0;
690}
691
692bitflags::bitflags! {
693    /// Various useful flags for [`RenderMeshInstance`]s.
694    #[derive(Clone, Copy)]
695    pub struct RenderMeshInstanceFlags: u8 {
696        /// The mesh casts shadows.
697        const SHADOW_CASTER           = 1 << 0;
698        /// The mesh can participate in automatic batching.
699        const AUTOMATIC_BATCHING      = 1 << 1;
700        /// The mesh had a transform last frame and so is eligible for motion
701        /// vector computation.
702        const HAS_PREVIOUS_TRANSFORM  = 1 << 2;
703        /// The mesh had a skin last frame and so that skin should be taken into
704        /// account for motion vector computation.
705        const HAS_PREVIOUS_SKIN       = 1 << 3;
706        /// The mesh had morph targets last frame and so they should be taken
707        /// into account for motion vector computation.
708        const HAS_PREVIOUS_MORPH      = 1 << 4;
709    }
710}
711
712/// CPU data that the render world keeps for each entity, when *not* using GPU
713/// mesh uniform building.
714#[derive(Deref, DerefMut)]
715pub struct RenderMeshInstanceCpu {
716    /// Data shared between both the CPU mesh uniform building and the GPU mesh
717    /// uniform building paths.
718    #[deref]
719    pub shared: RenderMeshInstanceShared,
720    /// The transform of the mesh.
721    ///
722    /// This will be written into the [`MeshUniform`] at the appropriate time.
723    pub transforms: MeshTransforms,
724}
725
726/// CPU data that the render world needs to keep for each entity that contains a
727/// mesh when using GPU mesh uniform building.
728#[derive(Deref, DerefMut)]
729pub struct RenderMeshInstanceGpu {
730    /// Data shared between both the CPU mesh uniform building and the GPU mesh
731    /// uniform building paths.
732    #[deref]
733    pub shared: RenderMeshInstanceShared,
734    /// The translation of the mesh.
735    ///
736    /// This is the only part of the transform that we have to keep on CPU (for
737    /// distance sorting).
738    pub translation: Vec3,
739    /// The index of the [`MeshInputUniform`] in the buffer.
740    pub current_uniform_index: NonMaxU32,
741}
742
743/// CPU data that the render world needs to keep about each entity that contains
744/// a mesh.
745pub struct RenderMeshInstanceShared {
746    /// The [`AssetId`] of the mesh.
747    pub mesh_asset_id: AssetId<Mesh>,
748    /// A slot for the material bind group index.
749    pub material_bindings_index: MaterialBindingId,
750    /// Various flags.
751    pub flags: RenderMeshInstanceFlags,
752    /// Index of the slab that the lightmap resides in, if a lightmap is
753    /// present.
754    pub lightmap_slab_index: Option<LightmapSlabIndex>,
755    /// User supplied tag to identify this mesh instance.
756    pub tag: u32,
757}
758
759/// Information that is gathered during the parallel portion of mesh extraction
760/// when GPU mesh uniform building is enabled.
761///
762/// From this, the [`MeshInputUniform`] and [`RenderMeshInstanceGpu`] are
763/// prepared.
764pub struct RenderMeshInstanceGpuBuilder {
765    /// Data that will be placed on the [`RenderMeshInstanceGpu`].
766    pub shared: RenderMeshInstanceShared,
767    /// The current transform.
768    pub world_from_local: Affine3,
769    /// Four 16-bit unsigned normalized UV values packed into a [`UVec2`]:
770    ///
771    /// ```text
772    ///                         <--- MSB                   LSB --->
773    ///                         +---- min v ----+ +---- min u ----+
774    ///     lightmap_uv_rect.x: vvvvvvvv vvvvvvvv uuuuuuuu uuuuuuuu,
775    ///                         +---- max v ----+ +---- max u ----+
776    ///     lightmap_uv_rect.y: VVVVVVVV VVVVVVVV UUUUUUUU UUUUUUUU,
777    ///
778    /// (MSB: most significant bit; LSB: least significant bit.)
779    /// ```
780    pub lightmap_uv_rect: UVec2,
781    /// The index of the previous mesh input.
782    pub previous_input_index: Option<NonMaxU32>,
783    /// Various flags.
784    pub mesh_flags: MeshFlags,
785}
786
787/// The per-thread queues used during [`extract_meshes_for_gpu_building`].
788///
789/// There are two varieties of these: one for when culling happens on CPU and
790/// one for when culling happens on GPU. Having the two varieties avoids wasting
791/// space if GPU culling is disabled.
792#[derive(Default)]
793pub enum RenderMeshInstanceGpuQueue {
794    /// The default value.
795    ///
796    /// This becomes [`RenderMeshInstanceGpuQueue::CpuCulling`] or
797    /// [`RenderMeshInstanceGpuQueue::GpuCulling`] once extraction starts.
798    #[default]
799    None,
800    /// The version of [`RenderMeshInstanceGpuQueue`] that omits the
801    /// [`MeshCullingData`], so that we don't waste space when GPU
802    /// culling is disabled.
803    CpuCulling {
804        /// Stores GPU data for each entity that became visible or changed in
805        /// such a way that necessitates updating the [`MeshInputUniform`] (e.g.
806        /// changed transform).
807        changed: Vec<(MainEntity, RenderMeshInstanceGpuBuilder)>,
808        /// Stores the IDs of entities that became invisible this frame.
809        removed: Vec<MainEntity>,
810    },
811    /// The version of [`RenderMeshInstanceGpuQueue`] that contains the
812    /// [`MeshCullingData`], used when any view has GPU culling
813    /// enabled.
814    GpuCulling {
815        /// Stores GPU data for each entity that became visible or changed in
816        /// such a way that necessitates updating the [`MeshInputUniform`] (e.g.
817        /// changed transform).
818        changed: Vec<(MainEntity, RenderMeshInstanceGpuBuilder, MeshCullingData)>,
819        /// Stores the IDs of entities that became invisible this frame.
820        removed: Vec<MainEntity>,
821    },
822}
823
824/// The per-thread queues containing mesh instances, populated during the
825/// extract phase.
826///
827/// These are filled in [`extract_meshes_for_gpu_building`] and consumed in
828/// [`collect_meshes_for_gpu_building`].
829#[derive(Resource, Default, Deref, DerefMut)]
830pub struct RenderMeshInstanceGpuQueues(Parallel<RenderMeshInstanceGpuQueue>);
831
832/// Holds a list of meshes that couldn't be extracted this frame because their
833/// materials weren't prepared yet.
834///
835/// On subsequent frames, we try to reextract those meshes.
836#[derive(Resource, Default, Deref, DerefMut)]
837pub struct MeshesToReextractNextFrame(MainEntityHashSet);
838
839impl RenderMeshInstanceShared {
840    /// A gpu builder will provide the mesh instance id
841    /// during [`RenderMeshInstanceGpuBuilder::update`].
842    fn for_gpu_building(
843        previous_transform: Option<&PreviousGlobalTransform>,
844        mesh: &Mesh3d,
845        tag: Option<&MeshTag>,
846        not_shadow_caster: bool,
847        no_automatic_batching: bool,
848    ) -> Self {
849        Self::for_cpu_building(
850            previous_transform,
851            mesh,
852            tag,
853            default(),
854            not_shadow_caster,
855            no_automatic_batching,
856        )
857    }
858
859    /// The cpu builder does not have an equivalent [`RenderMeshInstanceGpuBuilder::update`].
860    fn for_cpu_building(
861        previous_transform: Option<&PreviousGlobalTransform>,
862        mesh: &Mesh3d,
863        tag: Option<&MeshTag>,
864        material_bindings_index: MaterialBindingId,
865        not_shadow_caster: bool,
866        no_automatic_batching: bool,
867    ) -> Self {
868        let mut mesh_instance_flags = RenderMeshInstanceFlags::empty();
869        mesh_instance_flags.set(RenderMeshInstanceFlags::SHADOW_CASTER, !not_shadow_caster);
870        mesh_instance_flags.set(
871            RenderMeshInstanceFlags::AUTOMATIC_BATCHING,
872            !no_automatic_batching,
873        );
874        mesh_instance_flags.set(
875            RenderMeshInstanceFlags::HAS_PREVIOUS_TRANSFORM,
876            previous_transform.is_some(),
877        );
878
879        RenderMeshInstanceShared {
880            mesh_asset_id: mesh.id(),
881            flags: mesh_instance_flags,
882            material_bindings_index,
883            lightmap_slab_index: None,
884            tag: tag.map_or(0, |i| **i),
885        }
886    }
887
888    /// Returns true if this entity is eligible to participate in automatic
889    /// batching.
890    #[inline]
891    pub fn should_batch(&self) -> bool {
892        self.flags
893            .contains(RenderMeshInstanceFlags::AUTOMATIC_BATCHING)
894    }
895}
896
897/// Information that the render world keeps about each entity that contains a
898/// mesh.
899///
900/// The set of information needed is different depending on whether CPU or GPU
901/// [`MeshUniform`] building is in use.
902#[derive(Resource)]
903pub enum RenderMeshInstances {
904    /// Information needed when using CPU mesh instance data building.
905    CpuBuilding(RenderMeshInstancesCpu),
906    /// Information needed when using GPU mesh instance data building.
907    GpuBuilding(RenderMeshInstancesGpu),
908}
909
910/// Information that the render world keeps about each entity that contains a
911/// mesh, when using CPU mesh instance data building.
912#[derive(Default, Deref, DerefMut)]
913pub struct RenderMeshInstancesCpu(MainEntityHashMap<RenderMeshInstanceCpu>);
914
915/// Information that the render world keeps about each entity that contains a
916/// mesh, when using GPU mesh instance data building.
917#[derive(Default, Deref, DerefMut)]
918pub struct RenderMeshInstancesGpu(MainEntityHashMap<RenderMeshInstanceGpu>);
919
920impl RenderMeshInstances {
921    /// Creates a new [`RenderMeshInstances`] instance.
922    fn new(use_gpu_instance_buffer_builder: bool) -> RenderMeshInstances {
923        if use_gpu_instance_buffer_builder {
924            RenderMeshInstances::GpuBuilding(RenderMeshInstancesGpu::default())
925        } else {
926            RenderMeshInstances::CpuBuilding(RenderMeshInstancesCpu::default())
927        }
928    }
929
930    /// Returns the ID of the mesh asset attached to the given entity, if any.
931    pub fn mesh_asset_id(&self, entity: MainEntity) -> Option<AssetId<Mesh>> {
932        match *self {
933            RenderMeshInstances::CpuBuilding(ref instances) => instances.mesh_asset_id(entity),
934            RenderMeshInstances::GpuBuilding(ref instances) => instances.mesh_asset_id(entity),
935        }
936    }
937
938    /// Constructs [`RenderMeshQueueData`] for the given entity, if it has a
939    /// mesh attached.
940    pub fn render_mesh_queue_data(&self, entity: MainEntity) -> Option<RenderMeshQueueData> {
941        match *self {
942            RenderMeshInstances::CpuBuilding(ref instances) => {
943                instances.render_mesh_queue_data(entity)
944            }
945            RenderMeshInstances::GpuBuilding(ref instances) => {
946                instances.render_mesh_queue_data(entity)
947            }
948        }
949    }
950
951    /// Inserts the given flags into the CPU or GPU render mesh instance data
952    /// for the given mesh as appropriate.
953    fn insert_mesh_instance_flags(&mut self, entity: MainEntity, flags: RenderMeshInstanceFlags) {
954        match *self {
955            RenderMeshInstances::CpuBuilding(ref mut instances) => {
956                instances.insert_mesh_instance_flags(entity, flags);
957            }
958            RenderMeshInstances::GpuBuilding(ref mut instances) => {
959                instances.insert_mesh_instance_flags(entity, flags);
960            }
961        }
962    }
963}
964
965impl RenderMeshInstancesCpu {
966    fn mesh_asset_id(&self, entity: MainEntity) -> Option<AssetId<Mesh>> {
967        self.get(&entity)
968            .map(|render_mesh_instance| render_mesh_instance.mesh_asset_id)
969    }
970
971    fn render_mesh_queue_data(&self, entity: MainEntity) -> Option<RenderMeshQueueData> {
972        self.get(&entity)
973            .map(|render_mesh_instance| RenderMeshQueueData {
974                shared: &render_mesh_instance.shared,
975                translation: render_mesh_instance.transforms.world_from_local.translation,
976                current_uniform_index: InputUniformIndex::default(),
977            })
978    }
979
980    /// Inserts the given flags into the render mesh instance data for the given
981    /// mesh.
982    fn insert_mesh_instance_flags(&mut self, entity: MainEntity, flags: RenderMeshInstanceFlags) {
983        if let Some(instance) = self.get_mut(&entity) {
984            instance.flags.insert(flags);
985        }
986    }
987}
988
989impl RenderMeshInstancesGpu {
990    fn mesh_asset_id(&self, entity: MainEntity) -> Option<AssetId<Mesh>> {
991        self.get(&entity)
992            .map(|render_mesh_instance| render_mesh_instance.mesh_asset_id)
993    }
994
995    fn render_mesh_queue_data(&self, entity: MainEntity) -> Option<RenderMeshQueueData> {
996        self.get(&entity)
997            .map(|render_mesh_instance| RenderMeshQueueData {
998                shared: &render_mesh_instance.shared,
999                translation: render_mesh_instance.translation,
1000                current_uniform_index: InputUniformIndex(
1001                    render_mesh_instance.current_uniform_index.into(),
1002                ),
1003            })
1004    }
1005
1006    /// Inserts the given flags into the render mesh instance data for the given
1007    /// mesh.
1008    fn insert_mesh_instance_flags(&mut self, entity: MainEntity, flags: RenderMeshInstanceFlags) {
1009        if let Some(instance) = self.get_mut(&entity) {
1010            instance.flags.insert(flags);
1011        }
1012    }
1013}
1014
1015impl RenderMeshInstanceGpuQueue {
1016    /// Clears out a [`RenderMeshInstanceGpuQueue`], creating or recreating it
1017    /// as necessary.
1018    ///
1019    /// `any_gpu_culling` should be set to true if any view has GPU culling
1020    /// enabled.
1021    fn init(&mut self, any_gpu_culling: bool) {
1022        match (any_gpu_culling, &mut *self) {
1023            (true, RenderMeshInstanceGpuQueue::GpuCulling { changed, removed }) => {
1024                changed.clear();
1025                removed.clear();
1026            }
1027            (true, _) => {
1028                *self = RenderMeshInstanceGpuQueue::GpuCulling {
1029                    changed: vec![],
1030                    removed: vec![],
1031                }
1032            }
1033            (false, RenderMeshInstanceGpuQueue::CpuCulling { changed, removed }) => {
1034                changed.clear();
1035                removed.clear();
1036            }
1037            (false, _) => {
1038                *self = RenderMeshInstanceGpuQueue::CpuCulling {
1039                    changed: vec![],
1040                    removed: vec![],
1041                }
1042            }
1043        }
1044    }
1045
1046    /// Adds a new mesh to this queue.
1047    fn push(
1048        &mut self,
1049        entity: MainEntity,
1050        instance_builder: RenderMeshInstanceGpuBuilder,
1051        culling_data_builder: Option<MeshCullingData>,
1052    ) {
1053        match (&mut *self, culling_data_builder) {
1054            (
1055                &mut RenderMeshInstanceGpuQueue::CpuCulling {
1056                    changed: ref mut queue,
1057                    ..
1058                },
1059                None,
1060            ) => {
1061                queue.push((entity, instance_builder));
1062            }
1063            (
1064                &mut RenderMeshInstanceGpuQueue::GpuCulling {
1065                    changed: ref mut queue,
1066                    ..
1067                },
1068                Some(culling_data_builder),
1069            ) => {
1070                queue.push((entity, instance_builder, culling_data_builder));
1071            }
1072            (_, None) => {
1073                *self = RenderMeshInstanceGpuQueue::CpuCulling {
1074                    changed: vec![(entity, instance_builder)],
1075                    removed: vec![],
1076                };
1077            }
1078            (_, Some(culling_data_builder)) => {
1079                *self = RenderMeshInstanceGpuQueue::GpuCulling {
1080                    changed: vec![(entity, instance_builder, culling_data_builder)],
1081                    removed: vec![],
1082                };
1083            }
1084        }
1085    }
1086
1087    /// Adds the given entity to the `removed` list, queuing it for removal.
1088    ///
1089    /// The `gpu_culling` parameter specifies whether GPU culling is enabled.
1090    fn remove(&mut self, entity: MainEntity, gpu_culling: bool) {
1091        match (&mut *self, gpu_culling) {
1092            (RenderMeshInstanceGpuQueue::None, false) => {
1093                *self = RenderMeshInstanceGpuQueue::CpuCulling {
1094                    changed: vec![],
1095                    removed: vec![entity],
1096                }
1097            }
1098            (RenderMeshInstanceGpuQueue::None, true) => {
1099                *self = RenderMeshInstanceGpuQueue::GpuCulling {
1100                    changed: vec![],
1101                    removed: vec![entity],
1102                }
1103            }
1104            (RenderMeshInstanceGpuQueue::CpuCulling { removed, .. }, _)
1105            | (RenderMeshInstanceGpuQueue::GpuCulling { removed, .. }, _) => {
1106                removed.push(entity);
1107            }
1108        }
1109    }
1110}
1111
1112impl RenderMeshInstanceGpuBuilder {
1113    /// Flushes this mesh instance to the [`RenderMeshInstanceGpu`] and
1114    /// [`MeshInputUniform`] tables, replacing the existing entry if applicable.
1115    fn update(
1116        mut self,
1117        entity: MainEntity,
1118        render_mesh_instances: &mut MainEntityHashMap<RenderMeshInstanceGpu>,
1119        current_input_buffer: &mut InstanceInputUniformBuffer<MeshInputUniform>,
1120        previous_input_buffer: &mut InstanceInputUniformBuffer<MeshInputUniform>,
1121        mesh_allocator: &MeshAllocator,
1122        mesh_material_ids: &RenderMaterialInstances,
1123        render_material_bindings: &RenderMaterialBindings,
1124        render_lightmaps: &RenderLightmaps,
1125        skin_uniforms: &SkinUniforms,
1126        timestamp: FrameCount,
1127        meshes_to_reextract_next_frame: &mut MeshesToReextractNextFrame,
1128    ) -> Option<u32> {
1129        let (first_vertex_index, vertex_count) =
1130            match mesh_allocator.mesh_vertex_slice(&self.shared.mesh_asset_id) {
1131                Some(mesh_vertex_slice) => (
1132                    mesh_vertex_slice.range.start,
1133                    mesh_vertex_slice.range.end - mesh_vertex_slice.range.start,
1134                ),
1135                None => (0, 0),
1136            };
1137        let (mesh_is_indexed, first_index_index, index_count) =
1138            match mesh_allocator.mesh_index_slice(&self.shared.mesh_asset_id) {
1139                Some(mesh_index_slice) => (
1140                    true,
1141                    mesh_index_slice.range.start,
1142                    mesh_index_slice.range.end - mesh_index_slice.range.start,
1143                ),
1144                None => (false, 0, 0),
1145            };
1146        let current_skin_index = match skin_uniforms.skin_byte_offset(entity) {
1147            Some(skin_index) => skin_index.index(),
1148            None => u32::MAX,
1149        };
1150
1151        // Look up the material index. If we couldn't fetch the material index,
1152        // then the material hasn't been prepared yet, perhaps because it hasn't
1153        // yet loaded. In that case, add the mesh to
1154        // `meshes_to_reextract_next_frame` and bail.
1155        let mesh_material = mesh_material_ids.mesh_material(entity);
1156        let mesh_material_binding_id = if mesh_material != DUMMY_MESH_MATERIAL.untyped() {
1157            match render_material_bindings.get(&mesh_material) {
1158                Some(binding_id) => *binding_id,
1159                None => {
1160                    meshes_to_reextract_next_frame.insert(entity);
1161                    return None;
1162                }
1163            }
1164        } else {
1165            // Use a dummy material binding ID.
1166            MaterialBindingId::default()
1167        };
1168        self.shared.material_bindings_index = mesh_material_binding_id;
1169
1170        let lightmap_slot = match render_lightmaps.render_lightmaps.get(&entity) {
1171            Some(render_lightmap) => u16::from(*render_lightmap.slot_index),
1172            None => u16::MAX,
1173        };
1174        let lightmap_slab_index = render_lightmaps
1175            .render_lightmaps
1176            .get(&entity)
1177            .map(|lightmap| lightmap.slab_index);
1178        self.shared.lightmap_slab_index = lightmap_slab_index;
1179
1180        // Create the mesh input uniform.
1181        let mut mesh_input_uniform = MeshInputUniform {
1182            world_from_local: self.world_from_local.to_transpose(),
1183            lightmap_uv_rect: self.lightmap_uv_rect,
1184            flags: self.mesh_flags.bits(),
1185            previous_input_index: u32::MAX,
1186            timestamp: timestamp.0,
1187            first_vertex_index,
1188            first_index_index,
1189            index_count: if mesh_is_indexed {
1190                index_count
1191            } else {
1192                vertex_count
1193            },
1194            current_skin_index,
1195            material_and_lightmap_bind_group_slot: u32::from(
1196                self.shared.material_bindings_index.slot,
1197            ) | ((lightmap_slot as u32) << 16),
1198            tag: self.shared.tag,
1199            pad: 0,
1200        };
1201
1202        // Did the last frame contain this entity as well?
1203        let current_uniform_index;
1204        match render_mesh_instances.entry(entity) {
1205            Entry::Occupied(mut occupied_entry) => {
1206                // Yes, it did. Replace its entry with the new one.
1207
1208                // Reserve a slot.
1209                current_uniform_index = u32::from(occupied_entry.get_mut().current_uniform_index);
1210
1211                // Save the old mesh input uniform. The mesh preprocessing
1212                // shader will need it to compute motion vectors.
1213                let previous_mesh_input_uniform =
1214                    current_input_buffer.get_unchecked(current_uniform_index);
1215                let previous_input_index = previous_input_buffer.add(previous_mesh_input_uniform);
1216                mesh_input_uniform.previous_input_index = previous_input_index;
1217
1218                // Write in the new mesh input uniform.
1219                current_input_buffer.set(current_uniform_index, mesh_input_uniform);
1220
1221                occupied_entry.replace_entry_with(|_, _| {
1222                    Some(RenderMeshInstanceGpu {
1223                        translation: self.world_from_local.translation,
1224                        shared: self.shared,
1225                        current_uniform_index: NonMaxU32::new(current_uniform_index)
1226                            .unwrap_or_default(),
1227                    })
1228                });
1229            }
1230
1231            Entry::Vacant(vacant_entry) => {
1232                // No, this is a new entity. Push its data on to the buffer.
1233                current_uniform_index = current_input_buffer.add(mesh_input_uniform);
1234
1235                vacant_entry.insert(RenderMeshInstanceGpu {
1236                    translation: self.world_from_local.translation,
1237                    shared: self.shared,
1238                    current_uniform_index: NonMaxU32::new(current_uniform_index)
1239                        .unwrap_or_default(),
1240                });
1241            }
1242        }
1243
1244        Some(current_uniform_index)
1245    }
1246}
1247
1248/// Removes a [`MeshInputUniform`] corresponding to an entity that became
1249/// invisible from the buffer.
1250fn remove_mesh_input_uniform(
1251    entity: MainEntity,
1252    render_mesh_instances: &mut MainEntityHashMap<RenderMeshInstanceGpu>,
1253    current_input_buffer: &mut InstanceInputUniformBuffer<MeshInputUniform>,
1254) -> Option<u32> {
1255    // Remove the uniform data.
1256    let removed_render_mesh_instance = render_mesh_instances.remove(&entity)?;
1257
1258    let removed_uniform_index = removed_render_mesh_instance.current_uniform_index.get();
1259    current_input_buffer.remove(removed_uniform_index);
1260    Some(removed_uniform_index)
1261}
1262
1263impl MeshCullingData {
1264    /// Returns a new [`MeshCullingData`] initialized with the given AABB.
1265    ///
1266    /// If no AABB is provided, an infinitely-large one is conservatively
1267    /// chosen.
1268    fn new(aabb: Option<&Aabb>) -> Self {
1269        match aabb {
1270            Some(aabb) => MeshCullingData {
1271                aabb_center: aabb.center.extend(0.0),
1272                aabb_half_extents: aabb.half_extents.extend(0.0),
1273            },
1274            None => MeshCullingData {
1275                aabb_center: Vec3::ZERO.extend(0.0),
1276                aabb_half_extents: Vec3::INFINITY.extend(0.0),
1277            },
1278        }
1279    }
1280
1281    /// Flushes this mesh instance culling data to the
1282    /// [`MeshCullingDataBuffer`], replacing the existing entry if applicable.
1283    fn update(
1284        &self,
1285        mesh_culling_data_buffer: &mut MeshCullingDataBuffer,
1286        instance_data_index: usize,
1287    ) {
1288        while mesh_culling_data_buffer.len() < instance_data_index + 1 {
1289            mesh_culling_data_buffer.push(MeshCullingData::default());
1290        }
1291        mesh_culling_data_buffer.values_mut()[instance_data_index] = *self;
1292    }
1293}
1294
1295impl Default for MeshCullingDataBuffer {
1296    #[inline]
1297    fn default() -> Self {
1298        Self(RawBufferVec::new(BufferUsages::STORAGE))
1299    }
1300}
1301
1302/// Data that [`crate::material::queue_material_meshes`] and similar systems
1303/// need in order to place entities that contain meshes in the right batch.
1304#[derive(Deref)]
1305pub struct RenderMeshQueueData<'a> {
1306    /// General information about the mesh instance.
1307    #[deref]
1308    pub shared: &'a RenderMeshInstanceShared,
1309    /// The translation of the mesh instance.
1310    pub translation: Vec3,
1311    /// The index of the [`MeshInputUniform`] in the GPU buffer for this mesh
1312    /// instance.
1313    pub current_uniform_index: InputUniformIndex,
1314}
1315
1316/// A [`SystemSet`] that encompasses both [`extract_meshes_for_cpu_building`]
1317/// and [`extract_meshes_for_gpu_building`].
1318#[derive(SystemSet, Clone, PartialEq, Eq, Debug, Hash)]
1319pub struct ExtractMeshesSet;
1320
1321/// Extracts meshes from the main world into the render world, populating the
1322/// [`RenderMeshInstances`].
1323///
1324/// This is the variant of the system that runs when we're *not* using GPU
1325/// [`MeshUniform`] building.
1326pub fn extract_meshes_for_cpu_building(
1327    mut render_mesh_instances: ResMut<RenderMeshInstances>,
1328    mesh_material_ids: Res<RenderMaterialInstances>,
1329    render_material_bindings: Res<RenderMaterialBindings>,
1330    render_visibility_ranges: Res<RenderVisibilityRanges>,
1331    mut render_mesh_instance_queues: Local<Parallel<Vec<(Entity, RenderMeshInstanceCpu)>>>,
1332    meshes_query: Extract<
1333        Query<(
1334            Entity,
1335            &ViewVisibility,
1336            &GlobalTransform,
1337            Option<&PreviousGlobalTransform>,
1338            &Mesh3d,
1339            Option<&MeshTag>,
1340            Has<NoFrustumCulling>,
1341            Has<NotShadowReceiver>,
1342            Has<TransmittedShadowReceiver>,
1343            Has<NotShadowCaster>,
1344            Has<NoAutomaticBatching>,
1345            Has<VisibilityRange>,
1346        )>,
1347    >,
1348) {
1349    meshes_query.par_iter().for_each_init(
1350        || render_mesh_instance_queues.borrow_local_mut(),
1351        |queue,
1352         (
1353            entity,
1354            view_visibility,
1355            transform,
1356            previous_transform,
1357            mesh,
1358            tag,
1359            no_frustum_culling,
1360            not_shadow_receiver,
1361            transmitted_receiver,
1362            not_shadow_caster,
1363            no_automatic_batching,
1364            visibility_range,
1365        )| {
1366            if !view_visibility.get() {
1367                return;
1368            }
1369
1370            let mut lod_index = None;
1371            if visibility_range {
1372                lod_index = render_visibility_ranges.lod_index_for_entity(entity.into());
1373            }
1374
1375            let mesh_flags = MeshFlags::from_components(
1376                transform,
1377                lod_index,
1378                no_frustum_culling,
1379                not_shadow_receiver,
1380                transmitted_receiver,
1381            );
1382
1383            let mesh_material = mesh_material_ids.mesh_material(MainEntity::from(entity));
1384
1385            let material_bindings_index = render_material_bindings
1386                .get(&mesh_material)
1387                .copied()
1388                .unwrap_or_default();
1389
1390            let shared = RenderMeshInstanceShared::for_cpu_building(
1391                previous_transform,
1392                mesh,
1393                tag,
1394                material_bindings_index,
1395                not_shadow_caster,
1396                no_automatic_batching,
1397            );
1398
1399            let world_from_local = transform.affine();
1400            queue.push((
1401                entity,
1402                RenderMeshInstanceCpu {
1403                    transforms: MeshTransforms {
1404                        world_from_local: (&world_from_local).into(),
1405                        previous_world_from_local: (&previous_transform
1406                            .map(|t| t.0)
1407                            .unwrap_or(world_from_local))
1408                            .into(),
1409                        flags: mesh_flags.bits(),
1410                    },
1411                    shared,
1412                },
1413            ));
1414        },
1415    );
1416
1417    // Collect the render mesh instances.
1418    let RenderMeshInstances::CpuBuilding(ref mut render_mesh_instances) = *render_mesh_instances
1419    else {
1420        panic!(
1421            "`extract_meshes_for_cpu_building` should only be called if we're using CPU \
1422            `MeshUniform` building"
1423        );
1424    };
1425
1426    render_mesh_instances.clear();
1427    for queue in render_mesh_instance_queues.iter_mut() {
1428        for (entity, render_mesh_instance) in queue.drain(..) {
1429            render_mesh_instances.insert(entity.into(), render_mesh_instance);
1430        }
1431    }
1432}
1433
1434/// All the data that we need from a mesh in the main world.
1435type GpuMeshExtractionQuery = (
1436    Entity,
1437    Read<ViewVisibility>,
1438    Read<GlobalTransform>,
1439    Option<Read<PreviousGlobalTransform>>,
1440    Option<Read<Lightmap>>,
1441    Option<Read<Aabb>>,
1442    Read<Mesh3d>,
1443    Option<Read<MeshTag>>,
1444    Has<NoFrustumCulling>,
1445    Has<NotShadowReceiver>,
1446    Has<TransmittedShadowReceiver>,
1447    Has<NotShadowCaster>,
1448    Has<NoAutomaticBatching>,
1449    Has<VisibilityRange>,
1450);
1451
1452/// Extracts meshes from the main world into the render world and queues
1453/// [`MeshInputUniform`]s to be uploaded to the GPU.
1454///
1455/// This is optimized to only look at entities that have changed since the last
1456/// frame.
1457///
1458/// This is the variant of the system that runs when we're using GPU
1459/// [`MeshUniform`] building.
1460pub fn extract_meshes_for_gpu_building(
1461    mut render_mesh_instances: ResMut<RenderMeshInstances>,
1462    render_visibility_ranges: Res<RenderVisibilityRanges>,
1463    mut render_mesh_instance_queues: ResMut<RenderMeshInstanceGpuQueues>,
1464    changed_meshes_query: Extract<
1465        Query<
1466            GpuMeshExtractionQuery,
1467            Or<(
1468                Changed<ViewVisibility>,
1469                Changed<GlobalTransform>,
1470                Changed<PreviousGlobalTransform>,
1471                Changed<Lightmap>,
1472                Changed<Aabb>,
1473                Changed<Mesh3d>,
1474                Changed<NoFrustumCulling>,
1475                Changed<NotShadowReceiver>,
1476                Changed<TransmittedShadowReceiver>,
1477                Changed<NotShadowCaster>,
1478                Changed<NoAutomaticBatching>,
1479                Changed<VisibilityRange>,
1480                Changed<SkinnedMesh>,
1481            )>,
1482        >,
1483    >,
1484    all_meshes_query: Extract<Query<GpuMeshExtractionQuery>>,
1485    mut removed_visibilities_query: Extract<RemovedComponents<ViewVisibility>>,
1486    mut removed_global_transforms_query: Extract<RemovedComponents<GlobalTransform>>,
1487    mut removed_meshes_query: Extract<RemovedComponents<Mesh3d>>,
1488    gpu_culling_query: Extract<Query<(), (With<Camera>, Without<NoIndirectDrawing>)>>,
1489    meshes_to_reextract_next_frame: ResMut<MeshesToReextractNextFrame>,
1490) {
1491    let any_gpu_culling = !gpu_culling_query.is_empty();
1492
1493    for render_mesh_instance_queue in render_mesh_instance_queues.iter_mut() {
1494        render_mesh_instance_queue.init(any_gpu_culling);
1495    }
1496
1497    // Collect render mesh instances. Build up the uniform buffer.
1498
1499    let RenderMeshInstances::GpuBuilding(ref mut render_mesh_instances) = *render_mesh_instances
1500    else {
1501        panic!(
1502            "`extract_meshes_for_gpu_building` should only be called if we're \
1503            using GPU `MeshUniform` building"
1504        );
1505    };
1506
1507    // Find all meshes that have changed, and record information needed to
1508    // construct the `MeshInputUniform` for them.
1509    changed_meshes_query.par_iter().for_each_init(
1510        || render_mesh_instance_queues.borrow_local_mut(),
1511        |queue, query_row| {
1512            extract_mesh_for_gpu_building(
1513                query_row,
1514                &render_visibility_ranges,
1515                render_mesh_instances,
1516                queue,
1517                any_gpu_culling,
1518            );
1519        },
1520    );
1521
1522    // Process materials that `collect_meshes_for_gpu_building` marked as
1523    // needing to be reextracted. This will happen when we extracted a mesh on
1524    // some previous frame, but its material hadn't been prepared yet, perhaps
1525    // because the material hadn't yet been loaded. We reextract such materials
1526    // on subsequent frames so that `collect_meshes_for_gpu_building` will check
1527    // to see if their materials have been prepared.
1528    let mut queue = render_mesh_instance_queues.borrow_local_mut();
1529    for &mesh_entity in &**meshes_to_reextract_next_frame {
1530        if let Ok(query_row) = all_meshes_query.get(*mesh_entity) {
1531            extract_mesh_for_gpu_building(
1532                query_row,
1533                &render_visibility_ranges,
1534                render_mesh_instances,
1535                &mut queue,
1536                any_gpu_culling,
1537            );
1538        }
1539    }
1540
1541    // Also record info about each mesh that became invisible.
1542    for entity in removed_visibilities_query
1543        .read()
1544        .chain(removed_global_transforms_query.read())
1545        .chain(removed_meshes_query.read())
1546    {
1547        // Only queue a mesh for removal if we didn't pick it up above.
1548        // It's possible that a necessary component was removed and re-added in
1549        // the same frame.
1550        let entity = MainEntity::from(entity);
1551        if !changed_meshes_query.contains(*entity)
1552            && !meshes_to_reextract_next_frame.contains(&entity)
1553        {
1554            queue.remove(entity, any_gpu_culling);
1555        }
1556    }
1557}
1558
1559fn extract_mesh_for_gpu_building(
1560    (
1561        entity,
1562        view_visibility,
1563        transform,
1564        previous_transform,
1565        lightmap,
1566        aabb,
1567        mesh,
1568        tag,
1569        no_frustum_culling,
1570        not_shadow_receiver,
1571        transmitted_receiver,
1572        not_shadow_caster,
1573        no_automatic_batching,
1574        visibility_range,
1575    ): <GpuMeshExtractionQuery as QueryData>::Item<'_>,
1576    render_visibility_ranges: &RenderVisibilityRanges,
1577    render_mesh_instances: &RenderMeshInstancesGpu,
1578    queue: &mut RenderMeshInstanceGpuQueue,
1579    any_gpu_culling: bool,
1580) {
1581    if !view_visibility.get() {
1582        queue.remove(entity.into(), any_gpu_culling);
1583        return;
1584    }
1585
1586    let mut lod_index = None;
1587    if visibility_range {
1588        lod_index = render_visibility_ranges.lod_index_for_entity(entity.into());
1589    }
1590
1591    let mesh_flags = MeshFlags::from_components(
1592        transform,
1593        lod_index,
1594        no_frustum_culling,
1595        not_shadow_receiver,
1596        transmitted_receiver,
1597    );
1598
1599    let shared = RenderMeshInstanceShared::for_gpu_building(
1600        previous_transform,
1601        mesh,
1602        tag,
1603        not_shadow_caster,
1604        no_automatic_batching,
1605    );
1606
1607    let lightmap_uv_rect = pack_lightmap_uv_rect(lightmap.map(|lightmap| lightmap.uv_rect));
1608
1609    let gpu_mesh_culling_data = any_gpu_culling.then(|| MeshCullingData::new(aabb));
1610
1611    let previous_input_index = if shared
1612        .flags
1613        .contains(RenderMeshInstanceFlags::HAS_PREVIOUS_TRANSFORM)
1614    {
1615        render_mesh_instances
1616            .get(&MainEntity::from(entity))
1617            .map(|render_mesh_instance| render_mesh_instance.current_uniform_index)
1618    } else {
1619        None
1620    };
1621
1622    let gpu_mesh_instance_builder = RenderMeshInstanceGpuBuilder {
1623        shared,
1624        world_from_local: (&transform.affine()).into(),
1625        lightmap_uv_rect,
1626        mesh_flags,
1627        previous_input_index,
1628    };
1629
1630    queue.push(
1631        entity.into(),
1632        gpu_mesh_instance_builder,
1633        gpu_mesh_culling_data,
1634    );
1635}
1636
1637/// A system that sets the [`RenderMeshInstanceFlags`] for each mesh based on
1638/// whether the previous frame had skins and/or morph targets.
1639///
1640/// Ordinarily, [`RenderMeshInstanceFlags`] are set during the extraction phase.
1641/// However, we can't do that for the flags related to skins and morph targets
1642/// because the previous frame's skin and morph targets are the responsibility
1643/// of [`extract_skins`] and [`extract_morphs`] respectively. We want to run
1644/// those systems in parallel with mesh extraction for performance, so we need
1645/// to defer setting of these mesh instance flags to after extraction, which
1646/// this system does. An alternative to having skin- and morph-target-related
1647/// data in [`RenderMeshInstanceFlags`] would be to have
1648/// [`crate::material::queue_material_meshes`] check the skin and morph target
1649/// tables for each mesh, but that would be too slow in the hot mesh queuing
1650/// loop.
1651pub(crate) fn set_mesh_motion_vector_flags(
1652    mut render_mesh_instances: ResMut<RenderMeshInstances>,
1653    skin_uniforms: Res<SkinUniforms>,
1654    morph_indices: Res<MorphIndices>,
1655) {
1656    for &entity in skin_uniforms.all_skins() {
1657        render_mesh_instances
1658            .insert_mesh_instance_flags(entity, RenderMeshInstanceFlags::HAS_PREVIOUS_SKIN);
1659    }
1660    for &entity in morph_indices.prev.keys() {
1661        render_mesh_instances
1662            .insert_mesh_instance_flags(entity, RenderMeshInstanceFlags::HAS_PREVIOUS_MORPH);
1663    }
1664}
1665
1666/// Creates the [`RenderMeshInstanceGpu`]s and [`MeshInputUniform`]s when GPU
1667/// mesh uniforms are built.
1668pub fn collect_meshes_for_gpu_building(
1669    render_mesh_instances: ResMut<RenderMeshInstances>,
1670    batched_instance_buffers: ResMut<
1671        gpu_preprocessing::BatchedInstanceBuffers<MeshUniform, MeshInputUniform>,
1672    >,
1673    mut mesh_culling_data_buffer: ResMut<MeshCullingDataBuffer>,
1674    mut render_mesh_instance_queues: ResMut<RenderMeshInstanceGpuQueues>,
1675    mesh_allocator: Res<MeshAllocator>,
1676    mesh_material_ids: Res<RenderMaterialInstances>,
1677    render_material_bindings: Res<RenderMaterialBindings>,
1678    render_lightmaps: Res<RenderLightmaps>,
1679    skin_uniforms: Res<SkinUniforms>,
1680    frame_count: Res<FrameCount>,
1681    mut meshes_to_reextract_next_frame: ResMut<MeshesToReextractNextFrame>,
1682) {
1683    let RenderMeshInstances::GpuBuilding(render_mesh_instances) =
1684        render_mesh_instances.into_inner()
1685    else {
1686        return;
1687    };
1688
1689    // We're going to rebuild `meshes_to_reextract_next_frame`.
1690    meshes_to_reextract_next_frame.clear();
1691
1692    // Collect render mesh instances. Build up the uniform buffer.
1693    let gpu_preprocessing::BatchedInstanceBuffers {
1694        current_input_buffer,
1695        previous_input_buffer,
1696        ..
1697    } = batched_instance_buffers.into_inner();
1698
1699    previous_input_buffer.clear();
1700
1701    // Build the [`RenderMeshInstance`]s and [`MeshInputUniform`]s.
1702
1703    for queue in render_mesh_instance_queues.iter_mut() {
1704        match *queue {
1705            RenderMeshInstanceGpuQueue::None => {
1706                // This can only happen if the queue is empty.
1707            }
1708
1709            RenderMeshInstanceGpuQueue::CpuCulling {
1710                ref mut changed,
1711                ref mut removed,
1712            } => {
1713                for (entity, mesh_instance_builder) in changed.drain(..) {
1714                    mesh_instance_builder.update(
1715                        entity,
1716                        &mut *render_mesh_instances,
1717                        current_input_buffer,
1718                        previous_input_buffer,
1719                        &mesh_allocator,
1720                        &mesh_material_ids,
1721                        &render_material_bindings,
1722                        &render_lightmaps,
1723                        &skin_uniforms,
1724                        *frame_count,
1725                        &mut meshes_to_reextract_next_frame,
1726                    );
1727                }
1728
1729                for entity in removed.drain(..) {
1730                    remove_mesh_input_uniform(
1731                        entity,
1732                        &mut *render_mesh_instances,
1733                        current_input_buffer,
1734                    );
1735                }
1736            }
1737
1738            RenderMeshInstanceGpuQueue::GpuCulling {
1739                ref mut changed,
1740                ref mut removed,
1741            } => {
1742                for (entity, mesh_instance_builder, mesh_culling_builder) in changed.drain(..) {
1743                    let Some(instance_data_index) = mesh_instance_builder.update(
1744                        entity,
1745                        &mut *render_mesh_instances,
1746                        current_input_buffer,
1747                        previous_input_buffer,
1748                        &mesh_allocator,
1749                        &mesh_material_ids,
1750                        &render_material_bindings,
1751                        &render_lightmaps,
1752                        &skin_uniforms,
1753                        *frame_count,
1754                        &mut meshes_to_reextract_next_frame,
1755                    ) else {
1756                        continue;
1757                    };
1758                    mesh_culling_builder
1759                        .update(&mut mesh_culling_data_buffer, instance_data_index as usize);
1760                }
1761
1762                for entity in removed.drain(..) {
1763                    remove_mesh_input_uniform(
1764                        entity,
1765                        &mut *render_mesh_instances,
1766                        current_input_buffer,
1767                    );
1768                }
1769            }
1770        }
1771    }
1772
1773    // Buffers can't be empty. Make sure there's something in the previous input buffer.
1774    previous_input_buffer.ensure_nonempty();
1775}
1776
1777/// All data needed to construct a pipeline for rendering 3D meshes.
1778#[derive(Resource, Clone)]
1779pub struct MeshPipeline {
1780    /// A reference to all the mesh pipeline view layouts.
1781    pub view_layouts: MeshPipelineViewLayouts,
1782    // This dummy white texture is to be used in place of optional StandardMaterial textures
1783    pub dummy_white_gpu_image: GpuImage,
1784    pub clustered_forward_buffer_binding_type: BufferBindingType,
1785    pub mesh_layouts: MeshLayouts,
1786    /// `MeshUniform`s are stored in arrays in buffers. If storage buffers are available, they
1787    /// are used and this will be `None`, otherwise uniform buffers will be used with batches
1788    /// of this many `MeshUniform`s, stored at dynamic offsets within the uniform buffer.
1789    /// Use code like this in custom shaders:
1790    /// ```wgsl
1791    /// ##ifdef PER_OBJECT_BUFFER_BATCH_SIZE
1792    /// @group(1) @binding(0) var<uniform> mesh: array<Mesh, #{PER_OBJECT_BUFFER_BATCH_SIZE}u>;
1793    /// ##else
1794    /// @group(1) @binding(0) var<storage> mesh: array<Mesh>;
1795    /// ##endif // PER_OBJECT_BUFFER_BATCH_SIZE
1796    /// ```
1797    pub per_object_buffer_batch_size: Option<u32>,
1798
1799    /// Whether binding arrays (a.k.a. bindless textures) are usable on the
1800    /// current render device.
1801    ///
1802    /// This affects whether reflection probes can be used.
1803    pub binding_arrays_are_usable: bool,
1804
1805    /// Whether clustered decals are usable on the current render device.
1806    pub clustered_decals_are_usable: bool,
1807
1808    /// Whether skins will use uniform buffers on account of storage buffers
1809    /// being unavailable on this platform.
1810    pub skins_use_uniform_buffers: bool,
1811}
1812
1813impl FromWorld for MeshPipeline {
1814    fn from_world(world: &mut World) -> Self {
1815        let mut system_state: SystemState<(
1816            Res<RenderDevice>,
1817            Res<RenderAdapter>,
1818            Res<DefaultImageSampler>,
1819            Res<RenderQueue>,
1820            Res<MeshPipelineViewLayouts>,
1821        )> = SystemState::new(world);
1822        let (render_device, render_adapter, default_sampler, render_queue, view_layouts) =
1823            system_state.get_mut(world);
1824
1825        let clustered_forward_buffer_binding_type = render_device
1826            .get_supported_read_only_binding_type(CLUSTERED_FORWARD_STORAGE_BUFFER_COUNT);
1827
1828        // A 1x1x1 'all 1.0' texture to use as a dummy texture to use in place of optional StandardMaterial textures
1829        let dummy_white_gpu_image = {
1830            let image = Image::default();
1831            let texture = render_device.create_texture(&image.texture_descriptor);
1832            let sampler = match image.sampler {
1833                ImageSampler::Default => (**default_sampler).clone(),
1834                ImageSampler::Descriptor(ref descriptor) => {
1835                    render_device.create_sampler(&descriptor.as_wgpu())
1836                }
1837            };
1838
1839            let format_size = image.texture_descriptor.format.pixel_size();
1840            render_queue.write_texture(
1841                texture.as_image_copy(),
1842                image.data.as_ref().expect("Image was created without data"),
1843                TexelCopyBufferLayout {
1844                    offset: 0,
1845                    bytes_per_row: Some(image.width() * format_size as u32),
1846                    rows_per_image: None,
1847                },
1848                image.texture_descriptor.size,
1849            );
1850
1851            let texture_view = texture.create_view(&TextureViewDescriptor::default());
1852            GpuImage {
1853                texture,
1854                texture_view,
1855                texture_format: image.texture_descriptor.format,
1856                sampler,
1857                size: image.texture_descriptor.size,
1858                mip_level_count: image.texture_descriptor.mip_level_count,
1859            }
1860        };
1861
1862        MeshPipeline {
1863            view_layouts: view_layouts.clone(),
1864            clustered_forward_buffer_binding_type,
1865            dummy_white_gpu_image,
1866            mesh_layouts: MeshLayouts::new(&render_device, &render_adapter),
1867            per_object_buffer_batch_size: GpuArrayBuffer::<MeshUniform>::batch_size(&render_device),
1868            binding_arrays_are_usable: binding_arrays_are_usable(&render_device, &render_adapter),
1869            clustered_decals_are_usable: decal::clustered::clustered_decals_are_usable(
1870                &render_device,
1871                &render_adapter,
1872            ),
1873            skins_use_uniform_buffers: skins_use_uniform_buffers(&render_device),
1874        }
1875    }
1876}
1877
1878impl MeshPipeline {
1879    pub fn get_image_texture<'a>(
1880        &'a self,
1881        gpu_images: &'a RenderAssets<GpuImage>,
1882        handle_option: &Option<Handle<Image>>,
1883    ) -> Option<(&'a TextureView, &'a Sampler)> {
1884        if let Some(handle) = handle_option {
1885            let gpu_image = gpu_images.get(handle)?;
1886            Some((&gpu_image.texture_view, &gpu_image.sampler))
1887        } else {
1888            Some((
1889                &self.dummy_white_gpu_image.texture_view,
1890                &self.dummy_white_gpu_image.sampler,
1891            ))
1892        }
1893    }
1894
1895    pub fn get_view_layout(&self, layout_key: MeshPipelineViewLayoutKey) -> &BindGroupLayout {
1896        self.view_layouts.get_view_layout(layout_key)
1897    }
1898}
1899
1900impl GetBatchData for MeshPipeline {
1901    type Param = (
1902        SRes<RenderMeshInstances>,
1903        SRes<RenderLightmaps>,
1904        SRes<RenderAssets<RenderMesh>>,
1905        SRes<MeshAllocator>,
1906        SRes<SkinUniforms>,
1907    );
1908    // The material bind group ID, the mesh ID, and the lightmap ID,
1909    // respectively.
1910    type CompareData = (
1911        MaterialBindGroupIndex,
1912        AssetId<Mesh>,
1913        Option<LightmapSlabIndex>,
1914    );
1915
1916    type BufferData = MeshUniform;
1917
1918    fn get_batch_data(
1919        (mesh_instances, lightmaps, _, mesh_allocator, skin_uniforms): &SystemParamItem<
1920            Self::Param,
1921        >,
1922        (_entity, main_entity): (Entity, MainEntity),
1923    ) -> Option<(Self::BufferData, Option<Self::CompareData>)> {
1924        let RenderMeshInstances::CpuBuilding(ref mesh_instances) = **mesh_instances else {
1925            error!(
1926                "`get_batch_data` should never be called in GPU mesh uniform \
1927                building mode"
1928            );
1929            return None;
1930        };
1931        let mesh_instance = mesh_instances.get(&main_entity)?;
1932        let first_vertex_index =
1933            match mesh_allocator.mesh_vertex_slice(&mesh_instance.mesh_asset_id) {
1934                Some(mesh_vertex_slice) => mesh_vertex_slice.range.start,
1935                None => 0,
1936            };
1937        let maybe_lightmap = lightmaps.render_lightmaps.get(&main_entity);
1938
1939        let current_skin_index = skin_uniforms.skin_index(main_entity);
1940        let material_bind_group_index = mesh_instance.material_bindings_index;
1941
1942        Some((
1943            MeshUniform::new(
1944                &mesh_instance.transforms,
1945                first_vertex_index,
1946                material_bind_group_index.slot,
1947                maybe_lightmap.map(|lightmap| (lightmap.slot_index, lightmap.uv_rect)),
1948                current_skin_index,
1949                Some(mesh_instance.tag),
1950            ),
1951            mesh_instance.should_batch().then_some((
1952                material_bind_group_index.group,
1953                mesh_instance.mesh_asset_id,
1954                maybe_lightmap.map(|lightmap| lightmap.slab_index),
1955            )),
1956        ))
1957    }
1958}
1959
1960impl GetFullBatchData for MeshPipeline {
1961    type BufferInputData = MeshInputUniform;
1962
1963    fn get_index_and_compare_data(
1964        (mesh_instances, lightmaps, _, _, _): &SystemParamItem<Self::Param>,
1965        main_entity: MainEntity,
1966    ) -> Option<(NonMaxU32, Option<Self::CompareData>)> {
1967        // This should only be called during GPU building.
1968        let RenderMeshInstances::GpuBuilding(ref mesh_instances) = **mesh_instances else {
1969            error!(
1970                "`get_index_and_compare_data` should never be called in CPU mesh uniform building \
1971                mode"
1972            );
1973            return None;
1974        };
1975
1976        let mesh_instance = mesh_instances.get(&main_entity)?;
1977        let maybe_lightmap = lightmaps.render_lightmaps.get(&main_entity);
1978
1979        Some((
1980            mesh_instance.current_uniform_index,
1981            mesh_instance.should_batch().then_some((
1982                mesh_instance.material_bindings_index.group,
1983                mesh_instance.mesh_asset_id,
1984                maybe_lightmap.map(|lightmap| lightmap.slab_index),
1985            )),
1986        ))
1987    }
1988
1989    fn get_binned_batch_data(
1990        (mesh_instances, lightmaps, _, mesh_allocator, skin_uniforms): &SystemParamItem<
1991            Self::Param,
1992        >,
1993        main_entity: MainEntity,
1994    ) -> Option<Self::BufferData> {
1995        let RenderMeshInstances::CpuBuilding(ref mesh_instances) = **mesh_instances else {
1996            error!(
1997                "`get_binned_batch_data` should never be called in GPU mesh uniform building mode"
1998            );
1999            return None;
2000        };
2001        let mesh_instance = mesh_instances.get(&main_entity)?;
2002        let first_vertex_index =
2003            match mesh_allocator.mesh_vertex_slice(&mesh_instance.mesh_asset_id) {
2004                Some(mesh_vertex_slice) => mesh_vertex_slice.range.start,
2005                None => 0,
2006            };
2007        let maybe_lightmap = lightmaps.render_lightmaps.get(&main_entity);
2008
2009        let current_skin_index = skin_uniforms.skin_index(main_entity);
2010
2011        Some(MeshUniform::new(
2012            &mesh_instance.transforms,
2013            first_vertex_index,
2014            mesh_instance.material_bindings_index.slot,
2015            maybe_lightmap.map(|lightmap| (lightmap.slot_index, lightmap.uv_rect)),
2016            current_skin_index,
2017            Some(mesh_instance.tag),
2018        ))
2019    }
2020
2021    fn get_binned_index(
2022        (mesh_instances, _, _, _, _): &SystemParamItem<Self::Param>,
2023        main_entity: MainEntity,
2024    ) -> Option<NonMaxU32> {
2025        // This should only be called during GPU building.
2026        let RenderMeshInstances::GpuBuilding(ref mesh_instances) = **mesh_instances else {
2027            error!(
2028                "`get_binned_index` should never be called in CPU mesh uniform \
2029                building mode"
2030            );
2031            return None;
2032        };
2033
2034        mesh_instances
2035            .get(&main_entity)
2036            .map(|entity| entity.current_uniform_index)
2037    }
2038
2039    fn write_batch_indirect_parameters_metadata(
2040        indexed: bool,
2041        base_output_index: u32,
2042        batch_set_index: Option<NonMaxU32>,
2043        phase_indirect_parameters_buffers: &mut UntypedPhaseIndirectParametersBuffers,
2044        indirect_parameters_offset: u32,
2045    ) {
2046        let indirect_parameters = IndirectParametersCpuMetadata {
2047            base_output_index,
2048            batch_set_index: match batch_set_index {
2049                Some(batch_set_index) => u32::from(batch_set_index),
2050                None => !0,
2051            },
2052        };
2053
2054        if indexed {
2055            phase_indirect_parameters_buffers
2056                .indexed
2057                .set(indirect_parameters_offset, indirect_parameters);
2058        } else {
2059            phase_indirect_parameters_buffers
2060                .non_indexed
2061                .set(indirect_parameters_offset, indirect_parameters);
2062        }
2063    }
2064}
2065
2066bitflags::bitflags! {
2067    #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
2068    #[repr(transparent)]
2069    // NOTE: Apparently quadro drivers support up to 64x MSAA.
2070    /// MSAA uses the highest 3 bits for the MSAA log2(sample count) to support up to 128x MSAA.
2071    pub struct MeshPipelineKey: u64 {
2072        // Nothing
2073        const NONE                              = 0;
2074
2075        // Inherited bits
2076        const MORPH_TARGETS                     = BaseMeshPipelineKey::MORPH_TARGETS.bits();
2077
2078        // Flag bits
2079        const HDR                               = 1 << 0;
2080        const TONEMAP_IN_SHADER                 = 1 << 1;
2081        const DEBAND_DITHER                     = 1 << 2;
2082        const DEPTH_PREPASS                     = 1 << 3;
2083        const NORMAL_PREPASS                    = 1 << 4;
2084        const DEFERRED_PREPASS                  = 1 << 5;
2085        const MOTION_VECTOR_PREPASS             = 1 << 6;
2086        const MAY_DISCARD                       = 1 << 7; // Guards shader codepaths that may discard, allowing early depth tests in most cases
2087                                                            // See: https://www.khronos.org/opengl/wiki/Early_Fragment_Test
2088        const ENVIRONMENT_MAP                   = 1 << 8;
2089        const SCREEN_SPACE_AMBIENT_OCCLUSION    = 1 << 9;
2090        const UNCLIPPED_DEPTH_ORTHO             = 1 << 10; // Disables depth clipping for use with directional light shadow views
2091                                                            // Emulated via fragment shader depth on hardware that doesn't support it natively
2092                                                            // See: https://www.w3.org/TR/webgpu/#depth-clipping and https://therealmjp.github.io/posts/shadow-maps/#disabling-z-clipping
2093        const TEMPORAL_JITTER                   = 1 << 11;
2094        const READS_VIEW_TRANSMISSION_TEXTURE   = 1 << 12;
2095        const LIGHTMAPPED                       = 1 << 13;
2096        const LIGHTMAP_BICUBIC_SAMPLING         = 1 << 14;
2097        const IRRADIANCE_VOLUME                 = 1 << 15;
2098        const VISIBILITY_RANGE_DITHER           = 1 << 16;
2099        const SCREEN_SPACE_REFLECTIONS          = 1 << 17;
2100        const HAS_PREVIOUS_SKIN                 = 1 << 18;
2101        const HAS_PREVIOUS_MORPH                = 1 << 19;
2102        const OIT_ENABLED                       = 1 << 20;
2103        const DISTANCE_FOG                      = 1 << 21;
2104        const LAST_FLAG                         = Self::DISTANCE_FOG.bits();
2105
2106        // Bitfields
2107        const MSAA_RESERVED_BITS                = Self::MSAA_MASK_BITS << Self::MSAA_SHIFT_BITS;
2108        const BLEND_RESERVED_BITS               = Self::BLEND_MASK_BITS << Self::BLEND_SHIFT_BITS; // ← Bitmask reserving bits for the blend state
2109        const BLEND_OPAQUE                      = 0 << Self::BLEND_SHIFT_BITS;                     // ← Values are just sequential within the mask
2110        const BLEND_PREMULTIPLIED_ALPHA         = 1 << Self::BLEND_SHIFT_BITS;                     // ← As blend states is on 3 bits, it can range from 0 to 7
2111        const BLEND_MULTIPLY                    = 2 << Self::BLEND_SHIFT_BITS;                     // ← See `BLEND_MASK_BITS` for the number of bits available
2112        const BLEND_ALPHA                       = 3 << Self::BLEND_SHIFT_BITS;                     //
2113        const BLEND_ALPHA_TO_COVERAGE           = 4 << Self::BLEND_SHIFT_BITS;                     // ← We still have room for three more values without adding more bits
2114        const TONEMAP_METHOD_RESERVED_BITS      = Self::TONEMAP_METHOD_MASK_BITS << Self::TONEMAP_METHOD_SHIFT_BITS;
2115        const TONEMAP_METHOD_NONE               = 0 << Self::TONEMAP_METHOD_SHIFT_BITS;
2116        const TONEMAP_METHOD_REINHARD           = 1 << Self::TONEMAP_METHOD_SHIFT_BITS;
2117        const TONEMAP_METHOD_REINHARD_LUMINANCE = 2 << Self::TONEMAP_METHOD_SHIFT_BITS;
2118        const TONEMAP_METHOD_ACES_FITTED        = 3 << Self::TONEMAP_METHOD_SHIFT_BITS;
2119        const TONEMAP_METHOD_AGX                = 4 << Self::TONEMAP_METHOD_SHIFT_BITS;
2120        const TONEMAP_METHOD_SOMEWHAT_BORING_DISPLAY_TRANSFORM = 5 << Self::TONEMAP_METHOD_SHIFT_BITS;
2121        const TONEMAP_METHOD_TONY_MC_MAPFACE    = 6 << Self::TONEMAP_METHOD_SHIFT_BITS;
2122        const TONEMAP_METHOD_BLENDER_FILMIC     = 7 << Self::TONEMAP_METHOD_SHIFT_BITS;
2123        const SHADOW_FILTER_METHOD_RESERVED_BITS = Self::SHADOW_FILTER_METHOD_MASK_BITS << Self::SHADOW_FILTER_METHOD_SHIFT_BITS;
2124        const SHADOW_FILTER_METHOD_HARDWARE_2X2  = 0 << Self::SHADOW_FILTER_METHOD_SHIFT_BITS;
2125        const SHADOW_FILTER_METHOD_GAUSSIAN      = 1 << Self::SHADOW_FILTER_METHOD_SHIFT_BITS;
2126        const SHADOW_FILTER_METHOD_TEMPORAL      = 2 << Self::SHADOW_FILTER_METHOD_SHIFT_BITS;
2127        const VIEW_PROJECTION_RESERVED_BITS     = Self::VIEW_PROJECTION_MASK_BITS << Self::VIEW_PROJECTION_SHIFT_BITS;
2128        const VIEW_PROJECTION_NONSTANDARD       = 0 << Self::VIEW_PROJECTION_SHIFT_BITS;
2129        const VIEW_PROJECTION_PERSPECTIVE       = 1 << Self::VIEW_PROJECTION_SHIFT_BITS;
2130        const VIEW_PROJECTION_ORTHOGRAPHIC      = 2 << Self::VIEW_PROJECTION_SHIFT_BITS;
2131        const VIEW_PROJECTION_RESERVED          = 3 << Self::VIEW_PROJECTION_SHIFT_BITS;
2132        const SCREEN_SPACE_SPECULAR_TRANSMISSION_RESERVED_BITS = Self::SCREEN_SPACE_SPECULAR_TRANSMISSION_MASK_BITS << Self::SCREEN_SPACE_SPECULAR_TRANSMISSION_SHIFT_BITS;
2133        const SCREEN_SPACE_SPECULAR_TRANSMISSION_LOW    = 0 << Self::SCREEN_SPACE_SPECULAR_TRANSMISSION_SHIFT_BITS;
2134        const SCREEN_SPACE_SPECULAR_TRANSMISSION_MEDIUM = 1 << Self::SCREEN_SPACE_SPECULAR_TRANSMISSION_SHIFT_BITS;
2135        const SCREEN_SPACE_SPECULAR_TRANSMISSION_HIGH   = 2 << Self::SCREEN_SPACE_SPECULAR_TRANSMISSION_SHIFT_BITS;
2136        const SCREEN_SPACE_SPECULAR_TRANSMISSION_ULTRA  = 3 << Self::SCREEN_SPACE_SPECULAR_TRANSMISSION_SHIFT_BITS;
2137        const ALL_RESERVED_BITS =
2138            Self::BLEND_RESERVED_BITS.bits() |
2139            Self::MSAA_RESERVED_BITS.bits() |
2140            Self::TONEMAP_METHOD_RESERVED_BITS.bits() |
2141            Self::SHADOW_FILTER_METHOD_RESERVED_BITS.bits() |
2142            Self::VIEW_PROJECTION_RESERVED_BITS.bits() |
2143            Self::SCREEN_SPACE_SPECULAR_TRANSMISSION_RESERVED_BITS.bits();
2144    }
2145}
2146
2147impl MeshPipelineKey {
2148    const MSAA_MASK_BITS: u64 = 0b111;
2149    const MSAA_SHIFT_BITS: u64 = Self::LAST_FLAG.bits().trailing_zeros() as u64 + 1;
2150
2151    const BLEND_MASK_BITS: u64 = 0b111;
2152    const BLEND_SHIFT_BITS: u64 = Self::MSAA_MASK_BITS.count_ones() as u64 + Self::MSAA_SHIFT_BITS;
2153
2154    const TONEMAP_METHOD_MASK_BITS: u64 = 0b111;
2155    const TONEMAP_METHOD_SHIFT_BITS: u64 =
2156        Self::BLEND_MASK_BITS.count_ones() as u64 + Self::BLEND_SHIFT_BITS;
2157
2158    const SHADOW_FILTER_METHOD_MASK_BITS: u64 = 0b11;
2159    const SHADOW_FILTER_METHOD_SHIFT_BITS: u64 =
2160        Self::TONEMAP_METHOD_MASK_BITS.count_ones() as u64 + Self::TONEMAP_METHOD_SHIFT_BITS;
2161
2162    const VIEW_PROJECTION_MASK_BITS: u64 = 0b11;
2163    const VIEW_PROJECTION_SHIFT_BITS: u64 = Self::SHADOW_FILTER_METHOD_MASK_BITS.count_ones()
2164        as u64
2165        + Self::SHADOW_FILTER_METHOD_SHIFT_BITS;
2166
2167    const SCREEN_SPACE_SPECULAR_TRANSMISSION_MASK_BITS: u64 = 0b11;
2168    const SCREEN_SPACE_SPECULAR_TRANSMISSION_SHIFT_BITS: u64 =
2169        Self::VIEW_PROJECTION_MASK_BITS.count_ones() as u64 + Self::VIEW_PROJECTION_SHIFT_BITS;
2170
2171    pub fn from_msaa_samples(msaa_samples: u32) -> Self {
2172        let msaa_bits =
2173            (msaa_samples.trailing_zeros() as u64 & Self::MSAA_MASK_BITS) << Self::MSAA_SHIFT_BITS;
2174        Self::from_bits_retain(msaa_bits)
2175    }
2176
2177    pub fn from_hdr(hdr: bool) -> Self {
2178        if hdr {
2179            MeshPipelineKey::HDR
2180        } else {
2181            MeshPipelineKey::NONE
2182        }
2183    }
2184
2185    pub fn msaa_samples(&self) -> u32 {
2186        1 << ((self.bits() >> Self::MSAA_SHIFT_BITS) & Self::MSAA_MASK_BITS)
2187    }
2188
2189    pub fn from_primitive_topology(primitive_topology: PrimitiveTopology) -> Self {
2190        let primitive_topology_bits = ((primitive_topology as u64)
2191            & BaseMeshPipelineKey::PRIMITIVE_TOPOLOGY_MASK_BITS)
2192            << BaseMeshPipelineKey::PRIMITIVE_TOPOLOGY_SHIFT_BITS;
2193        Self::from_bits_retain(primitive_topology_bits)
2194    }
2195
2196    pub fn primitive_topology(&self) -> PrimitiveTopology {
2197        let primitive_topology_bits = (self.bits()
2198            >> BaseMeshPipelineKey::PRIMITIVE_TOPOLOGY_SHIFT_BITS)
2199            & BaseMeshPipelineKey::PRIMITIVE_TOPOLOGY_MASK_BITS;
2200        match primitive_topology_bits {
2201            x if x == PrimitiveTopology::PointList as u64 => PrimitiveTopology::PointList,
2202            x if x == PrimitiveTopology::LineList as u64 => PrimitiveTopology::LineList,
2203            x if x == PrimitiveTopology::LineStrip as u64 => PrimitiveTopology::LineStrip,
2204            x if x == PrimitiveTopology::TriangleList as u64 => PrimitiveTopology::TriangleList,
2205            x if x == PrimitiveTopology::TriangleStrip as u64 => PrimitiveTopology::TriangleStrip,
2206            _ => PrimitiveTopology::default(),
2207        }
2208    }
2209}
2210
2211// Ensure that we didn't overflow the number of bits available in `MeshPipelineKey`.
2212const_assert_eq!(
2213    (((MeshPipelineKey::LAST_FLAG.bits() << 1) - 1) | MeshPipelineKey::ALL_RESERVED_BITS.bits())
2214        & BaseMeshPipelineKey::all().bits(),
2215    0
2216);
2217
2218// Ensure that the reserved bits don't overlap with the topology bits
2219const_assert_eq!(
2220    (BaseMeshPipelineKey::PRIMITIVE_TOPOLOGY_MASK_BITS
2221        << BaseMeshPipelineKey::PRIMITIVE_TOPOLOGY_SHIFT_BITS)
2222        & MeshPipelineKey::ALL_RESERVED_BITS.bits(),
2223    0
2224);
2225
2226fn is_skinned(layout: &MeshVertexBufferLayoutRef) -> bool {
2227    layout.0.contains(Mesh::ATTRIBUTE_JOINT_INDEX)
2228        && layout.0.contains(Mesh::ATTRIBUTE_JOINT_WEIGHT)
2229}
2230pub fn setup_morph_and_skinning_defs(
2231    mesh_layouts: &MeshLayouts,
2232    layout: &MeshVertexBufferLayoutRef,
2233    offset: u32,
2234    key: &MeshPipelineKey,
2235    shader_defs: &mut Vec<ShaderDefVal>,
2236    vertex_attributes: &mut Vec<VertexAttributeDescriptor>,
2237    skins_use_uniform_buffers: bool,
2238) -> BindGroupLayout {
2239    let is_morphed = key.intersects(MeshPipelineKey::MORPH_TARGETS);
2240    let is_lightmapped = key.intersects(MeshPipelineKey::LIGHTMAPPED);
2241    let motion_vector_prepass = key.intersects(MeshPipelineKey::MOTION_VECTOR_PREPASS);
2242
2243    if skins_use_uniform_buffers {
2244        shader_defs.push("SKINS_USE_UNIFORM_BUFFERS".into());
2245    }
2246
2247    let mut add_skin_data = || {
2248        shader_defs.push("SKINNED".into());
2249        vertex_attributes.push(Mesh::ATTRIBUTE_JOINT_INDEX.at_shader_location(offset));
2250        vertex_attributes.push(Mesh::ATTRIBUTE_JOINT_WEIGHT.at_shader_location(offset + 1));
2251    };
2252
2253    match (
2254        is_skinned(layout),
2255        is_morphed,
2256        is_lightmapped,
2257        motion_vector_prepass,
2258    ) {
2259        (true, false, _, true) => {
2260            add_skin_data();
2261            mesh_layouts.skinned_motion.clone()
2262        }
2263        (true, false, _, false) => {
2264            add_skin_data();
2265            mesh_layouts.skinned.clone()
2266        }
2267        (true, true, _, true) => {
2268            add_skin_data();
2269            shader_defs.push("MORPH_TARGETS".into());
2270            mesh_layouts.morphed_skinned_motion.clone()
2271        }
2272        (true, true, _, false) => {
2273            add_skin_data();
2274            shader_defs.push("MORPH_TARGETS".into());
2275            mesh_layouts.morphed_skinned.clone()
2276        }
2277        (false, true, _, true) => {
2278            shader_defs.push("MORPH_TARGETS".into());
2279            mesh_layouts.morphed_motion.clone()
2280        }
2281        (false, true, _, false) => {
2282            shader_defs.push("MORPH_TARGETS".into());
2283            mesh_layouts.morphed.clone()
2284        }
2285        (false, false, true, _) => mesh_layouts.lightmapped.clone(),
2286        (false, false, false, _) => mesh_layouts.model_only.clone(),
2287    }
2288}
2289
2290impl SpecializedMeshPipeline for MeshPipeline {
2291    type Key = MeshPipelineKey;
2292
2293    fn specialize(
2294        &self,
2295        key: Self::Key,
2296        layout: &MeshVertexBufferLayoutRef,
2297    ) -> Result<RenderPipelineDescriptor, SpecializedMeshPipelineError> {
2298        let mut shader_defs = Vec::new();
2299        let mut vertex_attributes = Vec::new();
2300
2301        // Let the shader code know that it's running in a mesh pipeline.
2302        shader_defs.push("MESH_PIPELINE".into());
2303
2304        shader_defs.push("VERTEX_OUTPUT_INSTANCE_INDEX".into());
2305
2306        if layout.0.contains(Mesh::ATTRIBUTE_POSITION) {
2307            shader_defs.push("VERTEX_POSITIONS".into());
2308            vertex_attributes.push(Mesh::ATTRIBUTE_POSITION.at_shader_location(0));
2309        }
2310
2311        if layout.0.contains(Mesh::ATTRIBUTE_NORMAL) {
2312            shader_defs.push("VERTEX_NORMALS".into());
2313            vertex_attributes.push(Mesh::ATTRIBUTE_NORMAL.at_shader_location(1));
2314        }
2315
2316        if layout.0.contains(Mesh::ATTRIBUTE_UV_0) {
2317            shader_defs.push("VERTEX_UVS".into());
2318            shader_defs.push("VERTEX_UVS_A".into());
2319            vertex_attributes.push(Mesh::ATTRIBUTE_UV_0.at_shader_location(2));
2320        }
2321
2322        if layout.0.contains(Mesh::ATTRIBUTE_UV_1) {
2323            shader_defs.push("VERTEX_UVS".into());
2324            shader_defs.push("VERTEX_UVS_B".into());
2325            vertex_attributes.push(Mesh::ATTRIBUTE_UV_1.at_shader_location(3));
2326        }
2327
2328        if layout.0.contains(Mesh::ATTRIBUTE_TANGENT) {
2329            shader_defs.push("VERTEX_TANGENTS".into());
2330            vertex_attributes.push(Mesh::ATTRIBUTE_TANGENT.at_shader_location(4));
2331        }
2332
2333        if layout.0.contains(Mesh::ATTRIBUTE_COLOR) {
2334            shader_defs.push("VERTEX_COLORS".into());
2335            vertex_attributes.push(Mesh::ATTRIBUTE_COLOR.at_shader_location(5));
2336        }
2337
2338        if cfg!(feature = "pbr_transmission_textures") {
2339            shader_defs.push("PBR_TRANSMISSION_TEXTURES_SUPPORTED".into());
2340        }
2341        if cfg!(feature = "pbr_multi_layer_material_textures") {
2342            shader_defs.push("PBR_MULTI_LAYER_MATERIAL_TEXTURES_SUPPORTED".into());
2343        }
2344        if cfg!(feature = "pbr_anisotropy_texture") {
2345            shader_defs.push("PBR_ANISOTROPY_TEXTURE_SUPPORTED".into());
2346        }
2347        if cfg!(feature = "pbr_specular_textures") {
2348            shader_defs.push("PBR_SPECULAR_TEXTURES_SUPPORTED".into());
2349        }
2350
2351        let mut bind_group_layout = vec![self.get_view_layout(key.into()).clone()];
2352
2353        if key.msaa_samples() > 1 {
2354            shader_defs.push("MULTISAMPLED".into());
2355        };
2356
2357        bind_group_layout.push(setup_morph_and_skinning_defs(
2358            &self.mesh_layouts,
2359            layout,
2360            6,
2361            &key,
2362            &mut shader_defs,
2363            &mut vertex_attributes,
2364            self.skins_use_uniform_buffers,
2365        ));
2366
2367        if key.contains(MeshPipelineKey::SCREEN_SPACE_AMBIENT_OCCLUSION) {
2368            shader_defs.push("SCREEN_SPACE_AMBIENT_OCCLUSION".into());
2369        }
2370
2371        let vertex_buffer_layout = layout.0.get_layout(&vertex_attributes)?;
2372
2373        let (label, blend, depth_write_enabled);
2374        let pass = key.intersection(MeshPipelineKey::BLEND_RESERVED_BITS);
2375        let (mut is_opaque, mut alpha_to_coverage_enabled) = (false, false);
2376        if key.contains(MeshPipelineKey::OIT_ENABLED) && pass == MeshPipelineKey::BLEND_ALPHA {
2377            label = "oit_mesh_pipeline".into();
2378            // TODO tail blending would need alpha blending
2379            blend = None;
2380            shader_defs.push("OIT_ENABLED".into());
2381            // TODO it should be possible to use this to combine MSAA and OIT
2382            // alpha_to_coverage_enabled = true;
2383            depth_write_enabled = false;
2384        } else if pass == MeshPipelineKey::BLEND_ALPHA {
2385            label = "alpha_blend_mesh_pipeline".into();
2386            blend = Some(BlendState::ALPHA_BLENDING);
2387            // For the transparent pass, fragments that are closer will be alpha blended
2388            // but their depth is not written to the depth buffer
2389            depth_write_enabled = false;
2390        } else if pass == MeshPipelineKey::BLEND_PREMULTIPLIED_ALPHA {
2391            label = "premultiplied_alpha_mesh_pipeline".into();
2392            blend = Some(BlendState::PREMULTIPLIED_ALPHA_BLENDING);
2393            shader_defs.push("PREMULTIPLY_ALPHA".into());
2394            shader_defs.push("BLEND_PREMULTIPLIED_ALPHA".into());
2395            // For the transparent pass, fragments that are closer will be alpha blended
2396            // but their depth is not written to the depth buffer
2397            depth_write_enabled = false;
2398        } else if pass == MeshPipelineKey::BLEND_MULTIPLY {
2399            label = "multiply_mesh_pipeline".into();
2400            blend = Some(BlendState {
2401                color: BlendComponent {
2402                    src_factor: BlendFactor::Dst,
2403                    dst_factor: BlendFactor::OneMinusSrcAlpha,
2404                    operation: BlendOperation::Add,
2405                },
2406                alpha: BlendComponent::OVER,
2407            });
2408            shader_defs.push("PREMULTIPLY_ALPHA".into());
2409            shader_defs.push("BLEND_MULTIPLY".into());
2410            // For the multiply pass, fragments that are closer will be alpha blended
2411            // but their depth is not written to the depth buffer
2412            depth_write_enabled = false;
2413        } else if pass == MeshPipelineKey::BLEND_ALPHA_TO_COVERAGE {
2414            label = "alpha_to_coverage_mesh_pipeline".into();
2415            // BlendState::REPLACE is not needed here, and None will be potentially much faster in some cases
2416            blend = None;
2417            // For the opaque and alpha mask passes, fragments that are closer will replace
2418            // the current fragment value in the output and the depth is written to the
2419            // depth buffer
2420            depth_write_enabled = true;
2421            is_opaque = !key.contains(MeshPipelineKey::READS_VIEW_TRANSMISSION_TEXTURE);
2422            alpha_to_coverage_enabled = true;
2423            shader_defs.push("ALPHA_TO_COVERAGE".into());
2424        } else {
2425            label = "opaque_mesh_pipeline".into();
2426            // BlendState::REPLACE is not needed here, and None will be potentially much faster in some cases
2427            blend = None;
2428            // For the opaque and alpha mask passes, fragments that are closer will replace
2429            // the current fragment value in the output and the depth is written to the
2430            // depth buffer
2431            depth_write_enabled = true;
2432            is_opaque = !key.contains(MeshPipelineKey::READS_VIEW_TRANSMISSION_TEXTURE);
2433        }
2434
2435        if key.contains(MeshPipelineKey::NORMAL_PREPASS) {
2436            shader_defs.push("NORMAL_PREPASS".into());
2437        }
2438
2439        if key.contains(MeshPipelineKey::DEPTH_PREPASS) {
2440            shader_defs.push("DEPTH_PREPASS".into());
2441        }
2442
2443        if key.contains(MeshPipelineKey::MOTION_VECTOR_PREPASS) {
2444            shader_defs.push("MOTION_VECTOR_PREPASS".into());
2445        }
2446
2447        if key.contains(MeshPipelineKey::HAS_PREVIOUS_SKIN) {
2448            shader_defs.push("HAS_PREVIOUS_SKIN".into());
2449        }
2450
2451        if key.contains(MeshPipelineKey::HAS_PREVIOUS_MORPH) {
2452            shader_defs.push("HAS_PREVIOUS_MORPH".into());
2453        }
2454
2455        if key.contains(MeshPipelineKey::DEFERRED_PREPASS) {
2456            shader_defs.push("DEFERRED_PREPASS".into());
2457        }
2458
2459        if key.contains(MeshPipelineKey::NORMAL_PREPASS) && key.msaa_samples() == 1 && is_opaque {
2460            shader_defs.push("LOAD_PREPASS_NORMALS".into());
2461        }
2462
2463        let view_projection = key.intersection(MeshPipelineKey::VIEW_PROJECTION_RESERVED_BITS);
2464        if view_projection == MeshPipelineKey::VIEW_PROJECTION_NONSTANDARD {
2465            shader_defs.push("VIEW_PROJECTION_NONSTANDARD".into());
2466        } else if view_projection == MeshPipelineKey::VIEW_PROJECTION_PERSPECTIVE {
2467            shader_defs.push("VIEW_PROJECTION_PERSPECTIVE".into());
2468        } else if view_projection == MeshPipelineKey::VIEW_PROJECTION_ORTHOGRAPHIC {
2469            shader_defs.push("VIEW_PROJECTION_ORTHOGRAPHIC".into());
2470        }
2471
2472        #[cfg(all(feature = "webgl", target_arch = "wasm32", not(feature = "webgpu")))]
2473        shader_defs.push("WEBGL2".into());
2474
2475        #[cfg(feature = "experimental_pbr_pcss")]
2476        shader_defs.push("PCSS_SAMPLERS_AVAILABLE".into());
2477
2478        if key.contains(MeshPipelineKey::TONEMAP_IN_SHADER) {
2479            shader_defs.push("TONEMAP_IN_SHADER".into());
2480            shader_defs.push(ShaderDefVal::UInt(
2481                "TONEMAPPING_LUT_TEXTURE_BINDING_INDEX".into(),
2482                TONEMAPPING_LUT_TEXTURE_BINDING_INDEX,
2483            ));
2484            shader_defs.push(ShaderDefVal::UInt(
2485                "TONEMAPPING_LUT_SAMPLER_BINDING_INDEX".into(),
2486                TONEMAPPING_LUT_SAMPLER_BINDING_INDEX,
2487            ));
2488
2489            let method = key.intersection(MeshPipelineKey::TONEMAP_METHOD_RESERVED_BITS);
2490
2491            if method == MeshPipelineKey::TONEMAP_METHOD_NONE {
2492                shader_defs.push("TONEMAP_METHOD_NONE".into());
2493            } else if method == MeshPipelineKey::TONEMAP_METHOD_REINHARD {
2494                shader_defs.push("TONEMAP_METHOD_REINHARD".into());
2495            } else if method == MeshPipelineKey::TONEMAP_METHOD_REINHARD_LUMINANCE {
2496                shader_defs.push("TONEMAP_METHOD_REINHARD_LUMINANCE".into());
2497            } else if method == MeshPipelineKey::TONEMAP_METHOD_ACES_FITTED {
2498                shader_defs.push("TONEMAP_METHOD_ACES_FITTED".into());
2499            } else if method == MeshPipelineKey::TONEMAP_METHOD_AGX {
2500                shader_defs.push("TONEMAP_METHOD_AGX".into());
2501            } else if method == MeshPipelineKey::TONEMAP_METHOD_SOMEWHAT_BORING_DISPLAY_TRANSFORM {
2502                shader_defs.push("TONEMAP_METHOD_SOMEWHAT_BORING_DISPLAY_TRANSFORM".into());
2503            } else if method == MeshPipelineKey::TONEMAP_METHOD_BLENDER_FILMIC {
2504                shader_defs.push("TONEMAP_METHOD_BLENDER_FILMIC".into());
2505            } else if method == MeshPipelineKey::TONEMAP_METHOD_TONY_MC_MAPFACE {
2506                shader_defs.push("TONEMAP_METHOD_TONY_MC_MAPFACE".into());
2507            }
2508
2509            // Debanding is tied to tonemapping in the shader, cannot run without it.
2510            if key.contains(MeshPipelineKey::DEBAND_DITHER) {
2511                shader_defs.push("DEBAND_DITHER".into());
2512            }
2513        }
2514
2515        if key.contains(MeshPipelineKey::MAY_DISCARD) {
2516            shader_defs.push("MAY_DISCARD".into());
2517        }
2518
2519        if key.contains(MeshPipelineKey::ENVIRONMENT_MAP) {
2520            shader_defs.push("ENVIRONMENT_MAP".into());
2521        }
2522
2523        if key.contains(MeshPipelineKey::IRRADIANCE_VOLUME) && IRRADIANCE_VOLUMES_ARE_USABLE {
2524            shader_defs.push("IRRADIANCE_VOLUME".into());
2525        }
2526
2527        if key.contains(MeshPipelineKey::LIGHTMAPPED) {
2528            shader_defs.push("LIGHTMAP".into());
2529        }
2530        if key.contains(MeshPipelineKey::LIGHTMAP_BICUBIC_SAMPLING) {
2531            shader_defs.push("LIGHTMAP_BICUBIC_SAMPLING".into());
2532        }
2533
2534        if key.contains(MeshPipelineKey::TEMPORAL_JITTER) {
2535            shader_defs.push("TEMPORAL_JITTER".into());
2536        }
2537
2538        let shadow_filter_method =
2539            key.intersection(MeshPipelineKey::SHADOW_FILTER_METHOD_RESERVED_BITS);
2540        if shadow_filter_method == MeshPipelineKey::SHADOW_FILTER_METHOD_HARDWARE_2X2 {
2541            shader_defs.push("SHADOW_FILTER_METHOD_HARDWARE_2X2".into());
2542        } else if shadow_filter_method == MeshPipelineKey::SHADOW_FILTER_METHOD_GAUSSIAN {
2543            shader_defs.push("SHADOW_FILTER_METHOD_GAUSSIAN".into());
2544        } else if shadow_filter_method == MeshPipelineKey::SHADOW_FILTER_METHOD_TEMPORAL {
2545            shader_defs.push("SHADOW_FILTER_METHOD_TEMPORAL".into());
2546        }
2547
2548        let blur_quality =
2549            key.intersection(MeshPipelineKey::SCREEN_SPACE_SPECULAR_TRANSMISSION_RESERVED_BITS);
2550
2551        shader_defs.push(ShaderDefVal::Int(
2552            "SCREEN_SPACE_SPECULAR_TRANSMISSION_BLUR_TAPS".into(),
2553            match blur_quality {
2554                MeshPipelineKey::SCREEN_SPACE_SPECULAR_TRANSMISSION_LOW => 4,
2555                MeshPipelineKey::SCREEN_SPACE_SPECULAR_TRANSMISSION_MEDIUM => 8,
2556                MeshPipelineKey::SCREEN_SPACE_SPECULAR_TRANSMISSION_HIGH => 16,
2557                MeshPipelineKey::SCREEN_SPACE_SPECULAR_TRANSMISSION_ULTRA => 32,
2558                _ => unreachable!(), // Not possible, since the mask is 2 bits, and we've covered all 4 cases
2559            },
2560        ));
2561
2562        if key.contains(MeshPipelineKey::VISIBILITY_RANGE_DITHER) {
2563            shader_defs.push("VISIBILITY_RANGE_DITHER".into());
2564        }
2565
2566        if key.contains(MeshPipelineKey::DISTANCE_FOG) {
2567            shader_defs.push("DISTANCE_FOG".into());
2568        }
2569
2570        if self.binding_arrays_are_usable {
2571            shader_defs.push("MULTIPLE_LIGHT_PROBES_IN_ARRAY".into());
2572            shader_defs.push("MULTIPLE_LIGHTMAPS_IN_ARRAY".into());
2573        }
2574
2575        if IRRADIANCE_VOLUMES_ARE_USABLE {
2576            shader_defs.push("IRRADIANCE_VOLUMES_ARE_USABLE".into());
2577        }
2578
2579        if self.clustered_decals_are_usable {
2580            shader_defs.push("CLUSTERED_DECALS_ARE_USABLE".into());
2581        }
2582
2583        let format = if key.contains(MeshPipelineKey::HDR) {
2584            ViewTarget::TEXTURE_FORMAT_HDR
2585        } else {
2586            TextureFormat::bevy_default()
2587        };
2588
2589        // This is defined here so that custom shaders that use something other than
2590        // the mesh binding from bevy_pbr::mesh_bindings can easily make use of this
2591        // in their own shaders.
2592        if let Some(per_object_buffer_batch_size) = self.per_object_buffer_batch_size {
2593            shader_defs.push(ShaderDefVal::UInt(
2594                "PER_OBJECT_BUFFER_BATCH_SIZE".into(),
2595                per_object_buffer_batch_size,
2596            ));
2597        }
2598
2599        Ok(RenderPipelineDescriptor {
2600            vertex: VertexState {
2601                shader: MESH_SHADER_HANDLE,
2602                entry_point: "vertex".into(),
2603                shader_defs: shader_defs.clone(),
2604                buffers: vec![vertex_buffer_layout],
2605            },
2606            fragment: Some(FragmentState {
2607                shader: MESH_SHADER_HANDLE,
2608                shader_defs,
2609                entry_point: "fragment".into(),
2610                targets: vec![Some(ColorTargetState {
2611                    format,
2612                    blend,
2613                    write_mask: ColorWrites::ALL,
2614                })],
2615            }),
2616            layout: bind_group_layout,
2617            push_constant_ranges: vec![],
2618            primitive: PrimitiveState {
2619                front_face: FrontFace::Ccw,
2620                cull_mode: Some(Face::Back),
2621                unclipped_depth: false,
2622                polygon_mode: PolygonMode::Fill,
2623                conservative: false,
2624                topology: key.primitive_topology(),
2625                strip_index_format: None,
2626            },
2627            depth_stencil: Some(DepthStencilState {
2628                format: CORE_3D_DEPTH_FORMAT,
2629                depth_write_enabled,
2630                depth_compare: CompareFunction::GreaterEqual,
2631                stencil: StencilState {
2632                    front: StencilFaceState::IGNORE,
2633                    back: StencilFaceState::IGNORE,
2634                    read_mask: 0,
2635                    write_mask: 0,
2636                },
2637                bias: DepthBiasState {
2638                    constant: 0,
2639                    slope_scale: 0.0,
2640                    clamp: 0.0,
2641                },
2642            }),
2643            multisample: MultisampleState {
2644                count: key.msaa_samples(),
2645                mask: !0,
2646                alpha_to_coverage_enabled,
2647            },
2648            label: Some(label),
2649            zero_initialize_workgroup_memory: false,
2650        })
2651    }
2652}
2653
2654/// The bind groups for meshes currently loaded.
2655///
2656/// If GPU mesh preprocessing isn't in use, these are global to the scene. If
2657/// GPU mesh preprocessing is in use, these are specific to a single phase.
2658#[derive(Default)]
2659pub struct MeshPhaseBindGroups {
2660    model_only: Option<BindGroup>,
2661    skinned: Option<MeshBindGroupPair>,
2662    morph_targets: HashMap<AssetId<Mesh>, MeshBindGroupPair>,
2663    lightmaps: HashMap<LightmapSlabIndex, BindGroup>,
2664}
2665
2666pub struct MeshBindGroupPair {
2667    motion_vectors: BindGroup,
2668    no_motion_vectors: BindGroup,
2669}
2670
2671/// All bind groups for meshes currently loaded.
2672#[derive(Resource)]
2673pub enum MeshBindGroups {
2674    /// The bind groups for the meshes for the entire scene, if GPU mesh
2675    /// preprocessing isn't in use.
2676    CpuPreprocessing(MeshPhaseBindGroups),
2677    /// A mapping from the type ID of a phase (e.g. [`Opaque3d`]) to the mesh
2678    /// bind groups for that phase.
2679    GpuPreprocessing(TypeIdMap<MeshPhaseBindGroups>),
2680}
2681
2682impl MeshPhaseBindGroups {
2683    pub fn reset(&mut self) {
2684        self.model_only = None;
2685        self.skinned = None;
2686        self.morph_targets.clear();
2687        self.lightmaps.clear();
2688    }
2689    /// Get the `BindGroup` for `RenderMesh` with given `handle_id` and lightmap
2690    /// key `lightmap`.
2691    pub fn get(
2692        &self,
2693        asset_id: AssetId<Mesh>,
2694        lightmap: Option<LightmapSlabIndex>,
2695        is_skinned: bool,
2696        morph: bool,
2697        motion_vectors: bool,
2698    ) -> Option<&BindGroup> {
2699        match (is_skinned, morph, lightmap) {
2700            (_, true, _) => self
2701                .morph_targets
2702                .get(&asset_id)
2703                .map(|bind_group_pair| bind_group_pair.get(motion_vectors)),
2704            (true, false, _) => self
2705                .skinned
2706                .as_ref()
2707                .map(|bind_group_pair| bind_group_pair.get(motion_vectors)),
2708            (false, false, Some(lightmap_slab)) => self.lightmaps.get(&lightmap_slab),
2709            (false, false, None) => self.model_only.as_ref(),
2710        }
2711    }
2712}
2713
2714impl MeshBindGroupPair {
2715    fn get(&self, motion_vectors: bool) -> &BindGroup {
2716        if motion_vectors {
2717            &self.motion_vectors
2718        } else {
2719            &self.no_motion_vectors
2720        }
2721    }
2722}
2723
2724/// Creates the per-mesh bind groups for each type of mesh and each phase.
2725pub fn prepare_mesh_bind_groups(
2726    mut commands: Commands,
2727    meshes: Res<RenderAssets<RenderMesh>>,
2728    mesh_pipeline: Res<MeshPipeline>,
2729    render_device: Res<RenderDevice>,
2730    cpu_batched_instance_buffer: Option<
2731        Res<no_gpu_preprocessing::BatchedInstanceBuffer<MeshUniform>>,
2732    >,
2733    gpu_batched_instance_buffers: Option<
2734        Res<gpu_preprocessing::BatchedInstanceBuffers<MeshUniform, MeshInputUniform>>,
2735    >,
2736    skins_uniform: Res<SkinUniforms>,
2737    weights_uniform: Res<MorphUniforms>,
2738    mut render_lightmaps: ResMut<RenderLightmaps>,
2739) {
2740    // CPU mesh preprocessing path.
2741    if let Some(cpu_batched_instance_buffer) = cpu_batched_instance_buffer {
2742        if let Some(instance_data_binding) = cpu_batched_instance_buffer
2743            .into_inner()
2744            .instance_data_binding()
2745        {
2746            // In this path, we only have a single set of bind groups for all phases.
2747            let cpu_preprocessing_mesh_bind_groups = prepare_mesh_bind_groups_for_phase(
2748                instance_data_binding,
2749                &meshes,
2750                &mesh_pipeline,
2751                &render_device,
2752                &skins_uniform,
2753                &weights_uniform,
2754                &mut render_lightmaps,
2755            );
2756
2757            commands.insert_resource(MeshBindGroups::CpuPreprocessing(
2758                cpu_preprocessing_mesh_bind_groups,
2759            ));
2760            return;
2761        }
2762    }
2763
2764    // GPU mesh preprocessing path.
2765    if let Some(gpu_batched_instance_buffers) = gpu_batched_instance_buffers {
2766        let mut gpu_preprocessing_mesh_bind_groups = TypeIdMap::default();
2767
2768        // Loop over each phase.
2769        for (phase_type_id, batched_phase_instance_buffers) in
2770            &gpu_batched_instance_buffers.phase_instance_buffers
2771        {
2772            let Some(instance_data_binding) =
2773                batched_phase_instance_buffers.instance_data_binding()
2774            else {
2775                continue;
2776            };
2777
2778            let mesh_phase_bind_groups = prepare_mesh_bind_groups_for_phase(
2779                instance_data_binding,
2780                &meshes,
2781                &mesh_pipeline,
2782                &render_device,
2783                &skins_uniform,
2784                &weights_uniform,
2785                &mut render_lightmaps,
2786            );
2787
2788            gpu_preprocessing_mesh_bind_groups.insert(*phase_type_id, mesh_phase_bind_groups);
2789        }
2790
2791        commands.insert_resource(MeshBindGroups::GpuPreprocessing(
2792            gpu_preprocessing_mesh_bind_groups,
2793        ));
2794    }
2795}
2796
2797/// Creates the per-mesh bind groups for each type of mesh, for a single phase.
2798fn prepare_mesh_bind_groups_for_phase(
2799    model: BindingResource,
2800    meshes: &RenderAssets<RenderMesh>,
2801    mesh_pipeline: &MeshPipeline,
2802    render_device: &RenderDevice,
2803    skins_uniform: &SkinUniforms,
2804    weights_uniform: &MorphUniforms,
2805    render_lightmaps: &mut RenderLightmaps,
2806) -> MeshPhaseBindGroups {
2807    let layouts = &mesh_pipeline.mesh_layouts;
2808
2809    // TODO: Reuse allocations.
2810    let mut groups = MeshPhaseBindGroups {
2811        model_only: Some(layouts.model_only(render_device, &model)),
2812        ..default()
2813    };
2814
2815    // Create the skinned mesh bind group with the current and previous buffers
2816    // (the latter being for motion vector computation).
2817    let (skin, prev_skin) = (&skins_uniform.current_buffer, &skins_uniform.prev_buffer);
2818    groups.skinned = Some(MeshBindGroupPair {
2819        motion_vectors: layouts.skinned_motion(render_device, &model, skin, prev_skin),
2820        no_motion_vectors: layouts.skinned(render_device, &model, skin),
2821    });
2822
2823    // Create the morphed bind groups just like we did for the skinned bind
2824    // group.
2825    if let Some(weights) = weights_uniform.current_buffer.buffer() {
2826        let prev_weights = weights_uniform.prev_buffer.buffer().unwrap_or(weights);
2827        for (id, gpu_mesh) in meshes.iter() {
2828            if let Some(targets) = gpu_mesh.morph_targets.as_ref() {
2829                let bind_group_pair = if is_skinned(&gpu_mesh.layout) {
2830                    let prev_skin = &skins_uniform.prev_buffer;
2831                    MeshBindGroupPair {
2832                        motion_vectors: layouts.morphed_skinned_motion(
2833                            render_device,
2834                            &model,
2835                            skin,
2836                            weights,
2837                            targets,
2838                            prev_skin,
2839                            prev_weights,
2840                        ),
2841                        no_motion_vectors: layouts.morphed_skinned(
2842                            render_device,
2843                            &model,
2844                            skin,
2845                            weights,
2846                            targets,
2847                        ),
2848                    }
2849                } else {
2850                    MeshBindGroupPair {
2851                        motion_vectors: layouts.morphed_motion(
2852                            render_device,
2853                            &model,
2854                            weights,
2855                            targets,
2856                            prev_weights,
2857                        ),
2858                        no_motion_vectors: layouts.morphed(render_device, &model, weights, targets),
2859                    }
2860                };
2861                groups.morph_targets.insert(id, bind_group_pair);
2862            }
2863        }
2864    }
2865
2866    // Create lightmap bindgroups. There will be one bindgroup for each slab.
2867    let bindless_supported = render_lightmaps.bindless_supported;
2868    for (lightmap_slab_id, lightmap_slab) in render_lightmaps.slabs.iter_mut().enumerate() {
2869        groups.lightmaps.insert(
2870            LightmapSlabIndex(NonMaxU32::new(lightmap_slab_id as u32).unwrap()),
2871            layouts.lightmapped(render_device, &model, lightmap_slab, bindless_supported),
2872        );
2873    }
2874
2875    groups
2876}
2877
2878pub struct SetMeshViewBindGroup<const I: usize>;
2879impl<P: PhaseItem, const I: usize> RenderCommand<P> for SetMeshViewBindGroup<I> {
2880    type Param = ();
2881    type ViewQuery = (
2882        Read<ViewUniformOffset>,
2883        Read<ViewLightsUniformOffset>,
2884        Read<ViewFogUniformOffset>,
2885        Read<ViewLightProbesUniformOffset>,
2886        Read<ViewScreenSpaceReflectionsUniformOffset>,
2887        Read<ViewEnvironmentMapUniformOffset>,
2888        Read<MeshViewBindGroup>,
2889        Option<Read<OrderIndependentTransparencySettingsOffset>>,
2890    );
2891    type ItemQuery = ();
2892
2893    #[inline]
2894    fn render<'w>(
2895        _item: &P,
2896        (
2897            view_uniform,
2898            view_lights,
2899            view_fog,
2900            view_light_probes,
2901            view_ssr,
2902            view_environment_map,
2903            mesh_view_bind_group,
2904            maybe_oit_layers_count_offset,
2905        ): ROQueryItem<'w, Self::ViewQuery>,
2906        _entity: Option<()>,
2907        _: SystemParamItem<'w, '_, Self::Param>,
2908        pass: &mut TrackedRenderPass<'w>,
2909    ) -> RenderCommandResult {
2910        let mut offsets: SmallVec<[u32; 8]> = smallvec![
2911            view_uniform.offset,
2912            view_lights.offset,
2913            view_fog.offset,
2914            **view_light_probes,
2915            **view_ssr,
2916            **view_environment_map,
2917        ];
2918        if let Some(layers_count_offset) = maybe_oit_layers_count_offset {
2919            offsets.push(layers_count_offset.offset);
2920        }
2921        pass.set_bind_group(I, &mesh_view_bind_group.value, &offsets);
2922
2923        RenderCommandResult::Success
2924    }
2925}
2926
2927pub struct SetMeshBindGroup<const I: usize>;
2928impl<P: PhaseItem, const I: usize> RenderCommand<P> for SetMeshBindGroup<I> {
2929    type Param = (
2930        SRes<RenderDevice>,
2931        SRes<MeshBindGroups>,
2932        SRes<RenderMeshInstances>,
2933        SRes<SkinUniforms>,
2934        SRes<MorphIndices>,
2935        SRes<RenderLightmaps>,
2936    );
2937    type ViewQuery = Has<MotionVectorPrepass>;
2938    type ItemQuery = ();
2939
2940    #[inline]
2941    fn render<'w>(
2942        item: &P,
2943        has_motion_vector_prepass: bool,
2944        _item_query: Option<()>,
2945        (
2946            render_device,
2947            bind_groups,
2948            mesh_instances,
2949            skin_uniforms,
2950            morph_indices,
2951            lightmaps,
2952        ): SystemParamItem<'w, '_, Self::Param>,
2953        pass: &mut TrackedRenderPass<'w>,
2954    ) -> RenderCommandResult {
2955        let bind_groups = bind_groups.into_inner();
2956        let mesh_instances = mesh_instances.into_inner();
2957        let skin_uniforms = skin_uniforms.into_inner();
2958        let morph_indices = morph_indices.into_inner();
2959
2960        let entity = &item.main_entity();
2961
2962        let Some(mesh_asset_id) = mesh_instances.mesh_asset_id(*entity) else {
2963            return RenderCommandResult::Success;
2964        };
2965
2966        let current_skin_byte_offset = skin_uniforms.skin_byte_offset(*entity);
2967        let current_morph_index = morph_indices.current.get(entity);
2968        let prev_morph_index = morph_indices.prev.get(entity);
2969
2970        let is_skinned = current_skin_byte_offset.is_some();
2971        let is_morphed = current_morph_index.is_some();
2972
2973        let lightmap_slab_index = lightmaps
2974            .render_lightmaps
2975            .get(entity)
2976            .map(|render_lightmap| render_lightmap.slab_index);
2977
2978        let Some(mesh_phase_bind_groups) = (match *bind_groups {
2979            MeshBindGroups::CpuPreprocessing(ref mesh_phase_bind_groups) => {
2980                Some(mesh_phase_bind_groups)
2981            }
2982            MeshBindGroups::GpuPreprocessing(ref mesh_phase_bind_groups) => {
2983                mesh_phase_bind_groups.get(&TypeId::of::<P>())
2984            }
2985        }) else {
2986            // This is harmless if e.g. we're rendering the `Shadow` phase and
2987            // there weren't any shadows.
2988            return RenderCommandResult::Success;
2989        };
2990
2991        let Some(bind_group) = mesh_phase_bind_groups.get(
2992            mesh_asset_id,
2993            lightmap_slab_index,
2994            is_skinned,
2995            is_morphed,
2996            has_motion_vector_prepass,
2997        ) else {
2998            return RenderCommandResult::Failure(
2999                "The MeshBindGroups resource wasn't set in the render phase. \
3000                It should be set by the prepare_mesh_bind_group system.\n\
3001                This is a bevy bug! Please open an issue.",
3002            );
3003        };
3004
3005        let mut dynamic_offsets: [u32; 3] = Default::default();
3006        let mut offset_count = 0;
3007        if let PhaseItemExtraIndex::DynamicOffset(dynamic_offset) = item.extra_index() {
3008            dynamic_offsets[offset_count] = dynamic_offset;
3009            offset_count += 1;
3010        }
3011        if let Some(current_skin_index) = current_skin_byte_offset {
3012            if skins_use_uniform_buffers(&render_device) {
3013                dynamic_offsets[offset_count] = current_skin_index.byte_offset;
3014                offset_count += 1;
3015            }
3016        }
3017        if let Some(current_morph_index) = current_morph_index {
3018            dynamic_offsets[offset_count] = current_morph_index.index;
3019            offset_count += 1;
3020        }
3021
3022        // Attach motion vectors if needed.
3023        if has_motion_vector_prepass {
3024            // Attach the previous skin index for motion vector computation.
3025            if skins_use_uniform_buffers(&render_device) {
3026                if let Some(current_skin_byte_offset) = current_skin_byte_offset {
3027                    dynamic_offsets[offset_count] = current_skin_byte_offset.byte_offset;
3028                    offset_count += 1;
3029                }
3030            }
3031
3032            // Attach the previous morph index for motion vector computation. If
3033            // there isn't one, just use zero as the shader will ignore it.
3034            if current_morph_index.is_some() {
3035                match prev_morph_index {
3036                    Some(prev_morph_index) => {
3037                        dynamic_offsets[offset_count] = prev_morph_index.index;
3038                    }
3039                    None => dynamic_offsets[offset_count] = 0,
3040                }
3041                offset_count += 1;
3042            }
3043        }
3044
3045        pass.set_bind_group(I, bind_group, &dynamic_offsets[0..offset_count]);
3046
3047        RenderCommandResult::Success
3048    }
3049}
3050
3051pub struct DrawMesh;
3052impl<P: PhaseItem> RenderCommand<P> for DrawMesh {
3053    type Param = (
3054        SRes<RenderAssets<RenderMesh>>,
3055        SRes<RenderMeshInstances>,
3056        SRes<IndirectParametersBuffers>,
3057        SRes<PipelineCache>,
3058        SRes<MeshAllocator>,
3059        Option<SRes<PreprocessPipelines>>,
3060        SRes<GpuPreprocessingSupport>,
3061    );
3062    type ViewQuery = Has<PreprocessBindGroups>;
3063    type ItemQuery = ();
3064    #[inline]
3065    fn render<'w>(
3066        item: &P,
3067        has_preprocess_bind_group: ROQueryItem<Self::ViewQuery>,
3068        _item_query: Option<()>,
3069        (
3070            meshes,
3071            mesh_instances,
3072            indirect_parameters_buffer,
3073            pipeline_cache,
3074            mesh_allocator,
3075            preprocess_pipelines,
3076            preprocessing_support,
3077        ): SystemParamItem<'w, '_, Self::Param>,
3078        pass: &mut TrackedRenderPass<'w>,
3079    ) -> RenderCommandResult {
3080        // If we're using GPU preprocessing, then we're dependent on that
3081        // compute shader having been run, which of course can only happen if
3082        // it's compiled. Otherwise, our mesh instance data won't be present.
3083        if let Some(preprocess_pipelines) = preprocess_pipelines {
3084            if !has_preprocess_bind_group
3085                || !preprocess_pipelines
3086                    .pipelines_are_loaded(&pipeline_cache, &preprocessing_support)
3087            {
3088                return RenderCommandResult::Skip;
3089            }
3090        }
3091
3092        let meshes = meshes.into_inner();
3093        let mesh_instances = mesh_instances.into_inner();
3094        let indirect_parameters_buffer = indirect_parameters_buffer.into_inner();
3095        let mesh_allocator = mesh_allocator.into_inner();
3096
3097        let Some(mesh_asset_id) = mesh_instances.mesh_asset_id(item.main_entity()) else {
3098            return RenderCommandResult::Skip;
3099        };
3100        let Some(gpu_mesh) = meshes.get(mesh_asset_id) else {
3101            return RenderCommandResult::Skip;
3102        };
3103        let Some(vertex_buffer_slice) = mesh_allocator.mesh_vertex_slice(&mesh_asset_id) else {
3104            return RenderCommandResult::Skip;
3105        };
3106
3107        pass.set_vertex_buffer(0, vertex_buffer_slice.buffer.slice(..));
3108
3109        let batch_range = item.batch_range();
3110
3111        // Draw either directly or indirectly, as appropriate. If we're in
3112        // indirect mode, we can additionally multi-draw. (We can't multi-draw
3113        // in direct mode because `wgpu` doesn't expose that functionality.)
3114        match &gpu_mesh.buffer_info {
3115            RenderMeshBufferInfo::Indexed {
3116                index_format,
3117                count,
3118            } => {
3119                let Some(index_buffer_slice) = mesh_allocator.mesh_index_slice(&mesh_asset_id)
3120                else {
3121                    return RenderCommandResult::Skip;
3122                };
3123
3124                pass.set_index_buffer(index_buffer_slice.buffer.slice(..), 0, *index_format);
3125
3126                match item.extra_index() {
3127                    PhaseItemExtraIndex::None | PhaseItemExtraIndex::DynamicOffset(_) => {
3128                        pass.draw_indexed(
3129                            index_buffer_slice.range.start
3130                                ..(index_buffer_slice.range.start + *count),
3131                            vertex_buffer_slice.range.start as i32,
3132                            batch_range.clone(),
3133                        );
3134                    }
3135                    PhaseItemExtraIndex::IndirectParametersIndex {
3136                        range: indirect_parameters_range,
3137                        batch_set_index,
3138                    } => {
3139                        // Look up the indirect parameters buffer, as well as
3140                        // the buffer we're going to use for
3141                        // `multi_draw_indexed_indirect_count` (if available).
3142                        let Some(phase_indirect_parameters_buffers) =
3143                            indirect_parameters_buffer.get(&TypeId::of::<P>())
3144                        else {
3145                            warn!(
3146                                "Not rendering mesh because indexed indirect parameters buffer \
3147                                 wasn't present for this phase",
3148                            );
3149                            return RenderCommandResult::Skip;
3150                        };
3151                        let (Some(indirect_parameters_buffer), Some(batch_sets_buffer)) = (
3152                            phase_indirect_parameters_buffers.indexed.data_buffer(),
3153                            phase_indirect_parameters_buffers
3154                                .indexed
3155                                .batch_sets_buffer(),
3156                        ) else {
3157                            warn!(
3158                                "Not rendering mesh because indexed indirect parameters buffer \
3159                                 wasn't present",
3160                            );
3161                            return RenderCommandResult::Skip;
3162                        };
3163
3164                        // Calculate the location of the indirect parameters
3165                        // within the buffer.
3166                        let indirect_parameters_offset = indirect_parameters_range.start as u64
3167                            * size_of::<IndirectParametersIndexed>() as u64;
3168                        let indirect_parameters_count =
3169                            indirect_parameters_range.end - indirect_parameters_range.start;
3170
3171                        // If we're using `multi_draw_indirect_count`, take the
3172                        // number of batches from the appropriate position in
3173                        // the batch sets buffer. Otherwise, supply the size of
3174                        // the batch set.
3175                        match batch_set_index {
3176                            Some(batch_set_index) => {
3177                                let count_offset = u32::from(batch_set_index)
3178                                    * (size_of::<IndirectBatchSet>() as u32);
3179                                pass.multi_draw_indexed_indirect_count(
3180                                    indirect_parameters_buffer,
3181                                    indirect_parameters_offset,
3182                                    batch_sets_buffer,
3183                                    count_offset as u64,
3184                                    indirect_parameters_count,
3185                                );
3186                            }
3187                            None => {
3188                                pass.multi_draw_indexed_indirect(
3189                                    indirect_parameters_buffer,
3190                                    indirect_parameters_offset,
3191                                    indirect_parameters_count,
3192                                );
3193                            }
3194                        }
3195                    }
3196                }
3197            }
3198
3199            RenderMeshBufferInfo::NonIndexed => match item.extra_index() {
3200                PhaseItemExtraIndex::None | PhaseItemExtraIndex::DynamicOffset(_) => {
3201                    pass.draw(vertex_buffer_slice.range, batch_range.clone());
3202                }
3203                PhaseItemExtraIndex::IndirectParametersIndex {
3204                    range: indirect_parameters_range,
3205                    batch_set_index,
3206                } => {
3207                    // Look up the indirect parameters buffer, as well as the
3208                    // buffer we're going to use for
3209                    // `multi_draw_indirect_count` (if available).
3210                    let Some(phase_indirect_parameters_buffers) =
3211                        indirect_parameters_buffer.get(&TypeId::of::<P>())
3212                    else {
3213                        warn!(
3214                            "Not rendering mesh because non-indexed indirect parameters buffer \
3215                                 wasn't present for this phase",
3216                        );
3217                        return RenderCommandResult::Skip;
3218                    };
3219                    let (Some(indirect_parameters_buffer), Some(batch_sets_buffer)) = (
3220                        phase_indirect_parameters_buffers.non_indexed.data_buffer(),
3221                        phase_indirect_parameters_buffers
3222                            .non_indexed
3223                            .batch_sets_buffer(),
3224                    ) else {
3225                        warn!(
3226                            "Not rendering mesh because non-indexed indirect parameters buffer \
3227                             wasn't present"
3228                        );
3229                        return RenderCommandResult::Skip;
3230                    };
3231
3232                    // Calculate the location of the indirect parameters within
3233                    // the buffer.
3234                    let indirect_parameters_offset = indirect_parameters_range.start as u64
3235                        * size_of::<IndirectParametersNonIndexed>() as u64;
3236                    let indirect_parameters_count =
3237                        indirect_parameters_range.end - indirect_parameters_range.start;
3238
3239                    // If we're using `multi_draw_indirect_count`, take the
3240                    // number of batches from the appropriate position in the
3241                    // batch sets buffer. Otherwise, supply the size of the
3242                    // batch set.
3243                    match batch_set_index {
3244                        Some(batch_set_index) => {
3245                            let count_offset =
3246                                u32::from(batch_set_index) * (size_of::<IndirectBatchSet>() as u32);
3247                            pass.multi_draw_indirect_count(
3248                                indirect_parameters_buffer,
3249                                indirect_parameters_offset,
3250                                batch_sets_buffer,
3251                                count_offset as u64,
3252                                indirect_parameters_count,
3253                            );
3254                        }
3255                        None => {
3256                            pass.multi_draw_indirect(
3257                                indirect_parameters_buffer,
3258                                indirect_parameters_offset,
3259                                indirect_parameters_count,
3260                            );
3261                        }
3262                    }
3263                }
3264            },
3265        }
3266        RenderCommandResult::Success
3267    }
3268}
3269
3270#[cfg(test)]
3271mod tests {
3272    use super::MeshPipelineKey;
3273    #[test]
3274    fn mesh_key_msaa_samples() {
3275        for i in [1, 2, 4, 8, 16, 32, 64, 128] {
3276            assert_eq!(MeshPipelineKey::from_msaa_samples(i).msaa_samples(), i);
3277        }
3278    }
3279}