bevy_pbr/render/
mesh.rs

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