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