Skip to main content

bevy_pbr/render/
mesh_view_bindings.rs

1use crate::{
2    AreaLightLuts, DfgLut, ScreenSpaceTransmission, ViewFogUniformOffset,
3    ViewLightProbesUniformOffset, ViewLightsUniformOffset, ViewScreenSpaceReflectionsUniformOffset,
4};
5use arrayvec::ArrayVec;
6use bevy_core_pipeline::{
7    oit::{
8        OitBuffers, OrderIndependentTransparencySettings,
9        OrderIndependentTransparencySettingsOffset,
10    },
11    prepass::ViewPrepassTextures,
12    tonemapping::{
13        get_lut_bind_group_layout_entries, get_lut_bindings, Tonemapping, TonemappingLuts,
14    },
15};
16use bevy_ecs::{
17    component::Component,
18    entity::Entity,
19    query::Has,
20    resource::Resource,
21    system::{Commands, Query, Res},
22};
23use bevy_light::{EnvironmentMapLight, IrradianceVolume};
24use bevy_math::Vec4;
25use bevy_platform::sync::Arc;
26use bevy_render::{
27    camera::ExtractedCamera,
28    globals::{GlobalsBuffer, GlobalsUniform},
29    render_asset::RenderAssets,
30    render_resource::{binding_types::*, *},
31    renderer::{RenderAdapter, RenderDevice},
32    texture::{FallbackImage, FallbackImageZero, GpuImage},
33    view::{
34        Msaa, RenderVisibilityRanges, ViewUniform, ViewUniformOffset, ViewUniforms,
35        VISIBILITY_RANGES_STORAGE_BUFFER_COUNT,
36    },
37};
38use core::fmt::Write;
39use core::num::NonZero;
40
41use crate::{
42    contact_shadows::{
43        ContactShadowsBuffer, ContactShadowsUniform, ViewContactShadowsUniformOffset,
44    },
45    decal::{
46        self,
47        clustered::{
48            DecalsBuffer, RenderClusteredDecals, RenderViewClusteredDecalBindGroupEntries,
49        },
50    },
51    environment_map::{self, RenderViewEnvironmentMapBindGroupEntries},
52    irradiance_volume::{
53        self, RenderViewIrradianceVolumeBindGroupEntries, IRRADIANCE_VOLUMES_ARE_USABLE,
54    },
55    prepass,
56    resources::{AtmosphereBuffer, AtmosphereSampler, AtmosphereTextures, GpuAtmosphere},
57    Bluenoise, ExtractedAtmosphere, FogMeta, GlobalClusterableObjectMeta, GpuClusteredLights,
58    GpuFog, GpuLights, LightMeta, LightProbesBuffer, LightProbesUniform, MeshPipeline,
59    MeshPipelineKey, RenderViewLightProbes, ScreenSpaceAmbientOcclusionResources,
60    ScreenSpaceReflectionsBuffer, ScreenSpaceReflectionsUniform, ShadowSamplers,
61    ViewClusterBindings, ViewShadowBindings, ViewTransmissionTexture,
62    CLUSTERED_FORWARD_STORAGE_BUFFER_COUNT,
63};
64
65#[cfg(all(feature = "webgl", target_arch = "wasm32", not(feature = "webgpu")))]
66use bevy_render::render_resource::binding_types::texture_cube;
67
68#[cfg(debug_assertions)]
69use {crate::MESH_PIPELINE_VIEW_LAYOUT_SAFE_MAX_TEXTURES, bevy_utils::once, tracing::warn};
70
71pub const TONEMAPPING_LUT_TEXTURE_BINDING_INDEX: u32 = 18;
72pub const TONEMAPPING_LUT_SAMPLER_BINDING_INDEX: u32 = 19;
73
74#[derive(#[automatically_derived]
impl ::core::clone::Clone for MeshPipelineViewLayout {
    #[inline]
    fn clone(&self) -> Self {
        Self {
            main_layout: ::core::clone::Clone::clone(&self.main_layout),
            binding_array_layout: ::core::clone::Clone::clone(&self.binding_array_layout),
            empty_layout: ::core::clone::Clone::clone(&self.empty_layout),
        }
    }
}Clone)]
75pub struct MeshPipelineViewLayout {
76    pub main_layout: BindGroupLayoutDescriptor,
77    pub binding_array_layout: BindGroupLayoutDescriptor,
78    pub empty_layout: BindGroupLayoutDescriptor,
79}
80
81#[doc = r" A key that uniquely identifies a [`MeshPipelineViewLayout`]."]
#[repr(transparent)]
pub struct MeshPipelineViewLayoutKey(<MeshPipelineViewLayoutKey as
    ::bitflags::__private::PublicFlags>::Internal);
#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for MeshPipelineViewLayoutKey { }
#[automatically_derived]
impl ::core::clone::Clone for MeshPipelineViewLayoutKey {
    #[inline]
    fn clone(&self) -> Self {
        let _:
                ::core::clone::AssertParamIsClone<<MeshPipelineViewLayoutKey
                as ::bitflags::__private::PublicFlags>::Internal>;
        *self
    }
}
#[automatically_derived]
impl ::core::marker::Copy for MeshPipelineViewLayoutKey { }
#[automatically_derived]
impl ::core::fmt::Debug for MeshPipelineViewLayoutKey {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_tuple_field1_finish(f,
            "MeshPipelineViewLayoutKey", &&self.0)
    }
}
#[automatically_derived]
impl ::core::marker::StructuralPartialEq for MeshPipelineViewLayoutKey { }
#[automatically_derived]
impl ::core::cmp::PartialEq for MeshPipelineViewLayoutKey {
    #[inline]
    fn eq(&self, other: &Self) -> bool { self.0 == other.0 }
}
#[automatically_derived]
impl ::core::cmp::Eq for MeshPipelineViewLayoutKey {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {
        let _:
                ::core::cmp::AssertParamIsEq<<MeshPipelineViewLayoutKey as
                ::bitflags::__private::PublicFlags>::Internal>;
    }
}
#[automatically_derived]
impl ::core::hash::Hash for MeshPipelineViewLayoutKey {
    #[inline]
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
        ::core::hash::Hash::hash(&self.0, state)
    }
}
#[allow(dead_code, deprecated, unused_doc_comments, unused_attributes,
unused_mut, unused_imports, non_upper_case_globals, clippy :: min_ident_chars,
clippy :: assign_op_pattern, clippy :: indexing_slicing, clippy ::
same_name_method, clippy :: iter_without_into_iter,)]
impl MeshPipelineViewLayoutKey {
    pub const MULTISAMPLED: Self = Self::from_bits_retain(1 << 0);
    pub const DEPTH_PREPASS: Self = Self::from_bits_retain(1 << 1);
    pub const NORMAL_PREPASS: Self = Self::from_bits_retain(1 << 2);
    pub const MOTION_VECTOR_PREPASS: Self = Self::from_bits_retain(1 << 3);
    pub const DEFERRED_PREPASS: Self = Self::from_bits_retain(1 << 4);
    pub const OIT_ENABLED: Self = Self::from_bits_retain(1 << 5);
    pub const ATMOSPHERE: Self = Self::from_bits_retain(1 << 6);
    pub const STBN: Self = Self::from_bits_retain(1 << 7);
    pub const TONEMAP_IN_SHADER: Self = Self::from_bits_retain(1 << 8);
    pub const ENVIRONMENT_MAP: Self = Self::from_bits_retain(1 << 9);
    pub const SCREEN_SPACE_AMBIENT_OCCLUSION: Self =
        Self::from_bits_retain(1 << 10);
    pub const IRRADIANCE_VOLUME: Self = Self::from_bits_retain(1 << 11);
    pub const SCREEN_SPACE_REFLECTIONS: Self =
        Self::from_bits_retain(1 << 12);
    pub const CONTACT_SHADOWS: Self = Self::from_bits_retain(1 << 13);
    pub const DISTANCE_FOG: Self = Self::from_bits_retain(1 << 14);
    pub const AREA_LIGHT_LUTS: Self = Self::from_bits_retain(1 << 15);
    pub const VIEW_TRANSMISSION_TEXTURE: Self =
        Self::from_bits_retain(1 << 16);
}
#[allow(dead_code, deprecated, unused_doc_comments, unused_attributes,
unused_mut, unused_imports, non_upper_case_globals, clippy :: min_ident_chars,
clippy :: assign_op_pattern, clippy :: indexing_slicing, clippy ::
same_name_method, clippy :: iter_without_into_iter,)]
impl ::bitflags::Flags for MeshPipelineViewLayoutKey {
    const FLAGS: &'static [::bitflags::Flag<MeshPipelineViewLayoutKey>] =
        {
            mod __bitflags_flag_names {
                #[allow(unused_imports)]
                use super::*;
                pub(super) const MULTISAMPLED: &'static str = "MULTISAMPLED";
                pub(super) const DEPTH_PREPASS: &'static str =
                    "DEPTH_PREPASS";
                pub(super) const NORMAL_PREPASS: &'static str =
                    "NORMAL_PREPASS";
                pub(super) const MOTION_VECTOR_PREPASS: &'static str =
                    "MOTION_VECTOR_PREPASS";
                pub(super) const DEFERRED_PREPASS: &'static str =
                    "DEFERRED_PREPASS";
                pub(super) const OIT_ENABLED: &'static str = "OIT_ENABLED";
                pub(super) const ATMOSPHERE: &'static str = "ATMOSPHERE";
                pub(super) const STBN: &'static str = "STBN";
                pub(super) const TONEMAP_IN_SHADER: &'static str =
                    "TONEMAP_IN_SHADER";
                pub(super) const ENVIRONMENT_MAP: &'static str =
                    "ENVIRONMENT_MAP";
                pub(super) const SCREEN_SPACE_AMBIENT_OCCLUSION: &'static str
                    =
                    "SCREEN_SPACE_AMBIENT_OCCLUSION";
                pub(super) const IRRADIANCE_VOLUME: &'static str =
                    "IRRADIANCE_VOLUME";
                pub(super) const SCREEN_SPACE_REFLECTIONS: &'static str =
                    "SCREEN_SPACE_REFLECTIONS";
                pub(super) const CONTACT_SHADOWS: &'static str =
                    "CONTACT_SHADOWS";
                pub(super) const DISTANCE_FOG: &'static str = "DISTANCE_FOG";
                pub(super) const AREA_LIGHT_LUTS: &'static str =
                    "AREA_LIGHT_LUTS";
                pub(super) const VIEW_TRANSMISSION_TEXTURE: &'static str =
                    "VIEW_TRANSMISSION_TEXTURE";
            }
            &[{
                            ::bitflags::Flag::new(__bitflags_flag_names::MULTISAMPLED,
                                MeshPipelineViewLayoutKey::MULTISAMPLED)
                        },
                        {
                            ::bitflags::Flag::new(__bitflags_flag_names::DEPTH_PREPASS,
                                MeshPipelineViewLayoutKey::DEPTH_PREPASS)
                        },
                        {
                            ::bitflags::Flag::new(__bitflags_flag_names::NORMAL_PREPASS,
                                MeshPipelineViewLayoutKey::NORMAL_PREPASS)
                        },
                        {
                            ::bitflags::Flag::new(__bitflags_flag_names::MOTION_VECTOR_PREPASS,
                                MeshPipelineViewLayoutKey::MOTION_VECTOR_PREPASS)
                        },
                        {
                            ::bitflags::Flag::new(__bitflags_flag_names::DEFERRED_PREPASS,
                                MeshPipelineViewLayoutKey::DEFERRED_PREPASS)
                        },
                        {
                            ::bitflags::Flag::new(__bitflags_flag_names::OIT_ENABLED,
                                MeshPipelineViewLayoutKey::OIT_ENABLED)
                        },
                        {
                            ::bitflags::Flag::new(__bitflags_flag_names::ATMOSPHERE,
                                MeshPipelineViewLayoutKey::ATMOSPHERE)
                        },
                        {
                            ::bitflags::Flag::new(__bitflags_flag_names::STBN,
                                MeshPipelineViewLayoutKey::STBN)
                        },
                        {
                            ::bitflags::Flag::new(__bitflags_flag_names::TONEMAP_IN_SHADER,
                                MeshPipelineViewLayoutKey::TONEMAP_IN_SHADER)
                        },
                        {
                            ::bitflags::Flag::new(__bitflags_flag_names::ENVIRONMENT_MAP,
                                MeshPipelineViewLayoutKey::ENVIRONMENT_MAP)
                        },
                        {
                            ::bitflags::Flag::new(__bitflags_flag_names::SCREEN_SPACE_AMBIENT_OCCLUSION,
                                MeshPipelineViewLayoutKey::SCREEN_SPACE_AMBIENT_OCCLUSION)
                        },
                        {
                            ::bitflags::Flag::new(__bitflags_flag_names::IRRADIANCE_VOLUME,
                                MeshPipelineViewLayoutKey::IRRADIANCE_VOLUME)
                        },
                        {
                            ::bitflags::Flag::new(__bitflags_flag_names::SCREEN_SPACE_REFLECTIONS,
                                MeshPipelineViewLayoutKey::SCREEN_SPACE_REFLECTIONS)
                        },
                        {
                            ::bitflags::Flag::new(__bitflags_flag_names::CONTACT_SHADOWS,
                                MeshPipelineViewLayoutKey::CONTACT_SHADOWS)
                        },
                        {
                            ::bitflags::Flag::new(__bitflags_flag_names::DISTANCE_FOG,
                                MeshPipelineViewLayoutKey::DISTANCE_FOG)
                        },
                        {
                            ::bitflags::Flag::new(__bitflags_flag_names::AREA_LIGHT_LUTS,
                                MeshPipelineViewLayoutKey::AREA_LIGHT_LUTS)
                        },
                        {
                            ::bitflags::Flag::new(__bitflags_flag_names::VIEW_TRANSMISSION_TEXTURE,
                                MeshPipelineViewLayoutKey::VIEW_TRANSMISSION_TEXTURE)
                        }]
        };
    type Bits = u32;
    fn bits(&self) -> u32 { MeshPipelineViewLayoutKey::bits(self) }
    fn from_bits_retain(bits: u32) -> MeshPipelineViewLayoutKey {
        MeshPipelineViewLayoutKey::from_bits_retain(bits)
    }
    fn all_named() -> MeshPipelineViewLayoutKey {
        const ALL_NAMED: u32 =
            {
                let mut truncated = <u32 as ::bitflags::Bits>::EMPTY;
                let mut i = 0;
                {
                    {
                        let flag =
                            &<MeshPipelineViewLayoutKey as ::bitflags::Flags>::FLAGS[i];
                        if flag.is_named() {
                            truncated = truncated | flag.value().bits();
                        }
                        i += 1;
                    }
                };
                {
                    {
                        let flag =
                            &<MeshPipelineViewLayoutKey as ::bitflags::Flags>::FLAGS[i];
                        if flag.is_named() {
                            truncated = truncated | flag.value().bits();
                        }
                        i += 1;
                    }
                };
                {
                    {
                        let flag =
                            &<MeshPipelineViewLayoutKey as ::bitflags::Flags>::FLAGS[i];
                        if flag.is_named() {
                            truncated = truncated | flag.value().bits();
                        }
                        i += 1;
                    }
                };
                {
                    {
                        let flag =
                            &<MeshPipelineViewLayoutKey as ::bitflags::Flags>::FLAGS[i];
                        if flag.is_named() {
                            truncated = truncated | flag.value().bits();
                        }
                        i += 1;
                    }
                };
                {
                    {
                        let flag =
                            &<MeshPipelineViewLayoutKey as ::bitflags::Flags>::FLAGS[i];
                        if flag.is_named() {
                            truncated = truncated | flag.value().bits();
                        }
                        i += 1;
                    }
                };
                {
                    {
                        let flag =
                            &<MeshPipelineViewLayoutKey as ::bitflags::Flags>::FLAGS[i];
                        if flag.is_named() {
                            truncated = truncated | flag.value().bits();
                        }
                        i += 1;
                    }
                };
                {
                    {
                        let flag =
                            &<MeshPipelineViewLayoutKey as ::bitflags::Flags>::FLAGS[i];
                        if flag.is_named() {
                            truncated = truncated | flag.value().bits();
                        }
                        i += 1;
                    }
                };
                {
                    {
                        let flag =
                            &<MeshPipelineViewLayoutKey as ::bitflags::Flags>::FLAGS[i];
                        if flag.is_named() {
                            truncated = truncated | flag.value().bits();
                        }
                        i += 1;
                    }
                };
                {
                    {
                        let flag =
                            &<MeshPipelineViewLayoutKey as ::bitflags::Flags>::FLAGS[i];
                        if flag.is_named() {
                            truncated = truncated | flag.value().bits();
                        }
                        i += 1;
                    }
                };
                {
                    {
                        let flag =
                            &<MeshPipelineViewLayoutKey as ::bitflags::Flags>::FLAGS[i];
                        if flag.is_named() {
                            truncated = truncated | flag.value().bits();
                        }
                        i += 1;
                    }
                };
                {
                    {
                        let flag =
                            &<MeshPipelineViewLayoutKey as ::bitflags::Flags>::FLAGS[i];
                        if flag.is_named() {
                            truncated = truncated | flag.value().bits();
                        }
                        i += 1;
                    }
                };
                {
                    {
                        let flag =
                            &<MeshPipelineViewLayoutKey as ::bitflags::Flags>::FLAGS[i];
                        if flag.is_named() {
                            truncated = truncated | flag.value().bits();
                        }
                        i += 1;
                    }
                };
                {
                    {
                        let flag =
                            &<MeshPipelineViewLayoutKey as ::bitflags::Flags>::FLAGS[i];
                        if flag.is_named() {
                            truncated = truncated | flag.value().bits();
                        }
                        i += 1;
                    }
                };
                {
                    {
                        let flag =
                            &<MeshPipelineViewLayoutKey as ::bitflags::Flags>::FLAGS[i];
                        if flag.is_named() {
                            truncated = truncated | flag.value().bits();
                        }
                        i += 1;
                    }
                };
                {
                    {
                        let flag =
                            &<MeshPipelineViewLayoutKey as ::bitflags::Flags>::FLAGS[i];
                        if flag.is_named() {
                            truncated = truncated | flag.value().bits();
                        }
                        i += 1;
                    }
                };
                {
                    {
                        let flag =
                            &<MeshPipelineViewLayoutKey as ::bitflags::Flags>::FLAGS[i];
                        if flag.is_named() {
                            truncated = truncated | flag.value().bits();
                        }
                        i += 1;
                    }
                };
                {
                    {
                        let flag =
                            &<MeshPipelineViewLayoutKey as ::bitflags::Flags>::FLAGS[i];
                        if flag.is_named() {
                            truncated = truncated | flag.value().bits();
                        }
                        i += 1;
                    }
                };
                let _ = i;
                truncated
            };
        MeshPipelineViewLayoutKey::from_bits_retain(ALL_NAMED)
    }
}
#[allow(dead_code, deprecated, unused_doc_comments, unused_attributes,
unused_mut, unused_imports, non_upper_case_globals, clippy :: min_ident_chars,
clippy :: assign_op_pattern, clippy :: indexing_slicing, clippy ::
same_name_method, clippy :: iter_without_into_iter,)]
const _: () =
    {
        #[repr(transparent)]
        pub struct InternalBitFlags(u32);
        #[automatically_derived]
        #[doc(hidden)]
        unsafe impl ::core::clone::TrivialClone for InternalBitFlags { }
        #[automatically_derived]
        impl ::core::clone::Clone for InternalBitFlags {
            #[inline]
            fn clone(&self) -> Self {
                let _: ::core::clone::AssertParamIsClone<u32>;
                *self
            }
        }
        #[automatically_derived]
        impl ::core::marker::Copy for InternalBitFlags { }
        #[automatically_derived]
        impl ::core::marker::StructuralPartialEq for InternalBitFlags { }
        #[automatically_derived]
        impl ::core::cmp::PartialEq for InternalBitFlags {
            #[inline]
            fn eq(&self, other: &Self) -> bool { self.0 == other.0 }
        }
        #[automatically_derived]
        impl ::core::cmp::Eq for InternalBitFlags {
            #[inline]
            #[doc(hidden)]
            #[coverage(off)]
            fn assert_fields_are_eq(&self) {
                let _: ::core::cmp::AssertParamIsEq<u32>;
            }
        }
        #[automatically_derived]
        impl ::core::cmp::PartialOrd for InternalBitFlags {
            #[inline]
            fn partial_cmp(&self, other: &Self)
                -> ::core::option::Option<::core::cmp::Ordering> {
                ::core::option::Option::Some(::core::cmp::Ord::cmp(self,
                        other))
            }
        }
        #[automatically_derived]
        impl ::core::cmp::Ord for InternalBitFlags {
            #[inline]
            fn cmp(&self, other: &Self) -> ::core::cmp::Ordering {
                ::core::cmp::Ord::cmp(&self.0, &other.0)
            }
        }
        #[automatically_derived]
        impl ::core::hash::Hash for InternalBitFlags {
            #[inline]
            fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
                ::core::hash::Hash::hash(&self.0, state)
            }
        }
        impl ::bitflags::__private::PublicFlags for MeshPipelineViewLayoutKey
            {
            type Primitive = u32;
            type Internal = InternalBitFlags;
        }
        impl ::bitflags::__private::core::default::Default for
            InternalBitFlags {
            #[inline]
            fn default() -> Self { InternalBitFlags::empty() }
        }
        impl ::bitflags::__private::core::fmt::Debug for InternalBitFlags {
            fn fmt(&self,
                f: &mut ::bitflags::__private::core::fmt::Formatter<'_>)
                -> ::bitflags::__private::core::fmt::Result {
                if self.is_empty() {
                    f.write_fmt(format_args!("{0:#x}",
                            <u32 as ::bitflags::Bits>::EMPTY))
                } else {
                    ::bitflags::__private::core::fmt::Display::fmt(self, f)
                }
            }
        }
        impl ::bitflags::__private::core::fmt::Display for InternalBitFlags {
            fn fmt(&self,
                f: &mut ::bitflags::__private::core::fmt::Formatter<'_>)
                -> ::bitflags::__private::core::fmt::Result {
                ::bitflags::parser::to_writer(&MeshPipelineViewLayoutKey(*self),
                    f)
            }
        }
        impl ::bitflags::__private::core::str::FromStr for InternalBitFlags {
            type Err = ::bitflags::parser::ParseError;
            fn from_str(s: &str)
                ->
                    ::bitflags::__private::core::result::Result<Self,
                    Self::Err> {
                ::bitflags::parser::from_str::<MeshPipelineViewLayoutKey>(s).map(|flags|
                        flags.0)
            }
        }
        impl ::bitflags::__private::core::convert::AsRef<u32> for
            InternalBitFlags {
            fn as_ref(&self) -> &u32 { &self.0 }
        }
        impl ::bitflags::__private::core::convert::From<u32> for
            InternalBitFlags {
            fn from(bits: u32) -> Self { Self::from_bits_retain(bits) }
        }
        impl InternalBitFlags {
            /// Get a flags value with all bits unset.
            #[inline]
            pub const fn empty() -> Self {
                Self(<u32 as ::bitflags::Bits>::EMPTY)
            }
            /// Get a flags value with all known bits set.
            #[inline]
            pub const fn all() -> Self {
                const ALL: InternalBitFlags =
                    {
                        let mut truncated = <u32 as ::bitflags::Bits>::EMPTY;
                        let mut _i = 0;
                        {
                            {
                                truncated |=
                                    <MeshPipelineViewLayoutKey as
                                                    ::bitflags::Flags>::FLAGS[_i].value().bits();
                                _i += 1;
                            }
                        };
                        {
                            {
                                truncated |=
                                    <MeshPipelineViewLayoutKey as
                                                    ::bitflags::Flags>::FLAGS[_i].value().bits();
                                _i += 1;
                            }
                        };
                        {
                            {
                                truncated |=
                                    <MeshPipelineViewLayoutKey as
                                                    ::bitflags::Flags>::FLAGS[_i].value().bits();
                                _i += 1;
                            }
                        };
                        {
                            {
                                truncated |=
                                    <MeshPipelineViewLayoutKey as
                                                    ::bitflags::Flags>::FLAGS[_i].value().bits();
                                _i += 1;
                            }
                        };
                        {
                            {
                                truncated |=
                                    <MeshPipelineViewLayoutKey as
                                                    ::bitflags::Flags>::FLAGS[_i].value().bits();
                                _i += 1;
                            }
                        };
                        {
                            {
                                truncated |=
                                    <MeshPipelineViewLayoutKey as
                                                    ::bitflags::Flags>::FLAGS[_i].value().bits();
                                _i += 1;
                            }
                        };
                        {
                            {
                                truncated |=
                                    <MeshPipelineViewLayoutKey as
                                                    ::bitflags::Flags>::FLAGS[_i].value().bits();
                                _i += 1;
                            }
                        };
                        {
                            {
                                truncated |=
                                    <MeshPipelineViewLayoutKey as
                                                    ::bitflags::Flags>::FLAGS[_i].value().bits();
                                _i += 1;
                            }
                        };
                        {
                            {
                                truncated |=
                                    <MeshPipelineViewLayoutKey as
                                                    ::bitflags::Flags>::FLAGS[_i].value().bits();
                                _i += 1;
                            }
                        };
                        {
                            {
                                truncated |=
                                    <MeshPipelineViewLayoutKey as
                                                    ::bitflags::Flags>::FLAGS[_i].value().bits();
                                _i += 1;
                            }
                        };
                        {
                            {
                                truncated |=
                                    <MeshPipelineViewLayoutKey as
                                                    ::bitflags::Flags>::FLAGS[_i].value().bits();
                                _i += 1;
                            }
                        };
                        {
                            {
                                truncated |=
                                    <MeshPipelineViewLayoutKey as
                                                    ::bitflags::Flags>::FLAGS[_i].value().bits();
                                _i += 1;
                            }
                        };
                        {
                            {
                                truncated |=
                                    <MeshPipelineViewLayoutKey as
                                                    ::bitflags::Flags>::FLAGS[_i].value().bits();
                                _i += 1;
                            }
                        };
                        {
                            {
                                truncated |=
                                    <MeshPipelineViewLayoutKey as
                                                    ::bitflags::Flags>::FLAGS[_i].value().bits();
                                _i += 1;
                            }
                        };
                        {
                            {
                                truncated |=
                                    <MeshPipelineViewLayoutKey as
                                                    ::bitflags::Flags>::FLAGS[_i].value().bits();
                                _i += 1;
                            }
                        };
                        {
                            {
                                truncated |=
                                    <MeshPipelineViewLayoutKey as
                                                    ::bitflags::Flags>::FLAGS[_i].value().bits();
                                _i += 1;
                            }
                        };
                        {
                            {
                                truncated |=
                                    <MeshPipelineViewLayoutKey as
                                                    ::bitflags::Flags>::FLAGS[_i].value().bits();
                                _i += 1;
                            }
                        };
                        InternalBitFlags(truncated)
                    };
                ALL
            }
            /// Get the underlying bits value.
            ///
            /// The returned value is exactly the bits set in this flags value.
            #[inline]
            pub const fn bits(&self) -> u32 { self.0 }
            /// Convert from a bits value.
            ///
            /// This method will return `None` if any unknown bits are set.
            #[inline]
            pub const fn from_bits(bits: u32)
                -> ::bitflags::__private::core::option::Option<Self> {
                let truncated = Self::from_bits_truncate(bits).0;
                if truncated == bits {
                    ::bitflags::__private::core::option::Option::Some(Self(bits))
                } else { ::bitflags::__private::core::option::Option::None }
            }
            /// Convert from a bits value, unsetting any unknown bits.
            #[inline]
            pub const fn from_bits_truncate(bits: u32) -> Self {
                Self(bits & Self::all().0)
            }
            /// Convert from a bits value exactly.
            #[inline]
            pub const fn from_bits_retain(bits: u32) -> Self { Self(bits) }
            /// Get a flags value with the bits of a flag with the given name set.
            ///
            /// This method will return `None` if `name` is empty or doesn't
            /// correspond to any named flag.
            #[inline]
            pub fn from_name(name: &str)
                -> ::bitflags::__private::core::option::Option<Self> {
                mod __bitflags_flag_names {
                    #[allow(unused_imports)]
                    use super::*;
                    pub(super) const MULTISAMPLED: &'static str =
                        "MULTISAMPLED";
                    pub(super) const DEPTH_PREPASS: &'static str =
                        "DEPTH_PREPASS";
                    pub(super) const NORMAL_PREPASS: &'static str =
                        "NORMAL_PREPASS";
                    pub(super) const MOTION_VECTOR_PREPASS: &'static str =
                        "MOTION_VECTOR_PREPASS";
                    pub(super) const DEFERRED_PREPASS: &'static str =
                        "DEFERRED_PREPASS";
                    pub(super) const OIT_ENABLED: &'static str = "OIT_ENABLED";
                    pub(super) const ATMOSPHERE: &'static str = "ATMOSPHERE";
                    pub(super) const STBN: &'static str = "STBN";
                    pub(super) const TONEMAP_IN_SHADER: &'static str =
                        "TONEMAP_IN_SHADER";
                    pub(super) const ENVIRONMENT_MAP: &'static str =
                        "ENVIRONMENT_MAP";
                    pub(super) const SCREEN_SPACE_AMBIENT_OCCLUSION:
                        &'static str =
                        "SCREEN_SPACE_AMBIENT_OCCLUSION";
                    pub(super) const IRRADIANCE_VOLUME: &'static str =
                        "IRRADIANCE_VOLUME";
                    pub(super) const SCREEN_SPACE_REFLECTIONS: &'static str =
                        "SCREEN_SPACE_REFLECTIONS";
                    pub(super) const CONTACT_SHADOWS: &'static str =
                        "CONTACT_SHADOWS";
                    pub(super) const DISTANCE_FOG: &'static str =
                        "DISTANCE_FOG";
                    pub(super) const AREA_LIGHT_LUTS: &'static str =
                        "AREA_LIGHT_LUTS";
                    pub(super) const VIEW_TRANSMISSION_TEXTURE: &'static str =
                        "VIEW_TRANSMISSION_TEXTURE";
                }
                {
                    {
                        if name == __bitflags_flag_names::MULTISAMPLED {
                            return ::bitflags::__private::core::option::Option::Some(Self(MeshPipelineViewLayoutKey::MULTISAMPLED.bits()));
                        }
                    };
                };
                {
                    {
                        if name == __bitflags_flag_names::DEPTH_PREPASS {
                            return ::bitflags::__private::core::option::Option::Some(Self(MeshPipelineViewLayoutKey::DEPTH_PREPASS.bits()));
                        }
                    };
                };
                {
                    {
                        if name == __bitflags_flag_names::NORMAL_PREPASS {
                            return ::bitflags::__private::core::option::Option::Some(Self(MeshPipelineViewLayoutKey::NORMAL_PREPASS.bits()));
                        }
                    };
                };
                {
                    {
                        if name == __bitflags_flag_names::MOTION_VECTOR_PREPASS {
                            return ::bitflags::__private::core::option::Option::Some(Self(MeshPipelineViewLayoutKey::MOTION_VECTOR_PREPASS.bits()));
                        }
                    };
                };
                {
                    {
                        if name == __bitflags_flag_names::DEFERRED_PREPASS {
                            return ::bitflags::__private::core::option::Option::Some(Self(MeshPipelineViewLayoutKey::DEFERRED_PREPASS.bits()));
                        }
                    };
                };
                {
                    {
                        if name == __bitflags_flag_names::OIT_ENABLED {
                            return ::bitflags::__private::core::option::Option::Some(Self(MeshPipelineViewLayoutKey::OIT_ENABLED.bits()));
                        }
                    };
                };
                {
                    {
                        if name == __bitflags_flag_names::ATMOSPHERE {
                            return ::bitflags::__private::core::option::Option::Some(Self(MeshPipelineViewLayoutKey::ATMOSPHERE.bits()));
                        }
                    };
                };
                {
                    {
                        if name == __bitflags_flag_names::STBN {
                            return ::bitflags::__private::core::option::Option::Some(Self(MeshPipelineViewLayoutKey::STBN.bits()));
                        }
                    };
                };
                {
                    {
                        if name == __bitflags_flag_names::TONEMAP_IN_SHADER {
                            return ::bitflags::__private::core::option::Option::Some(Self(MeshPipelineViewLayoutKey::TONEMAP_IN_SHADER.bits()));
                        }
                    };
                };
                {
                    {
                        if name == __bitflags_flag_names::ENVIRONMENT_MAP {
                            return ::bitflags::__private::core::option::Option::Some(Self(MeshPipelineViewLayoutKey::ENVIRONMENT_MAP.bits()));
                        }
                    };
                };
                {
                    {
                        if name ==
                                __bitflags_flag_names::SCREEN_SPACE_AMBIENT_OCCLUSION {
                            return ::bitflags::__private::core::option::Option::Some(Self(MeshPipelineViewLayoutKey::SCREEN_SPACE_AMBIENT_OCCLUSION.bits()));
                        }
                    };
                };
                {
                    {
                        if name == __bitflags_flag_names::IRRADIANCE_VOLUME {
                            return ::bitflags::__private::core::option::Option::Some(Self(MeshPipelineViewLayoutKey::IRRADIANCE_VOLUME.bits()));
                        }
                    };
                };
                {
                    {
                        if name == __bitflags_flag_names::SCREEN_SPACE_REFLECTIONS {
                            return ::bitflags::__private::core::option::Option::Some(Self(MeshPipelineViewLayoutKey::SCREEN_SPACE_REFLECTIONS.bits()));
                        }
                    };
                };
                {
                    {
                        if name == __bitflags_flag_names::CONTACT_SHADOWS {
                            return ::bitflags::__private::core::option::Option::Some(Self(MeshPipelineViewLayoutKey::CONTACT_SHADOWS.bits()));
                        }
                    };
                };
                {
                    {
                        if name == __bitflags_flag_names::DISTANCE_FOG {
                            return ::bitflags::__private::core::option::Option::Some(Self(MeshPipelineViewLayoutKey::DISTANCE_FOG.bits()));
                        }
                    };
                };
                {
                    {
                        if name == __bitflags_flag_names::AREA_LIGHT_LUTS {
                            return ::bitflags::__private::core::option::Option::Some(Self(MeshPipelineViewLayoutKey::AREA_LIGHT_LUTS.bits()));
                        }
                    };
                };
                {
                    {
                        if name == __bitflags_flag_names::VIEW_TRANSMISSION_TEXTURE
                            {
                            return ::bitflags::__private::core::option::Option::Some(Self(MeshPipelineViewLayoutKey::VIEW_TRANSMISSION_TEXTURE.bits()));
                        }
                    };
                };
                let _ = name;
                ::bitflags::__private::core::option::Option::None
            }
            /// Whether all bits in `self` are unset.
            #[inline]
            pub const fn is_empty(&self) -> bool {
                self.0 == <u32 as ::bitflags::Bits>::EMPTY
            }
            /// Whether all known bits in this flags value are set.
            #[inline]
            pub const fn is_all(&self) -> bool {
                Self::all().0 | self.0 == self.0
            }
            /// Whether any set bits in `other` are also set in `self`.
            #[inline]
            pub const fn intersects(&self, other: Self) -> bool {
                self.0 & other.0 != <u32 as ::bitflags::Bits>::EMPTY
            }
            /// Whether all set bits in `other` are also set in `self`.
            #[inline]
            pub const fn contains(&self, other: Self) -> bool {
                self.0 & other.0 == other.0
            }
            /// The bitwise or (`|`) of the bits in `self` and `other`.
            #[inline]
            pub fn insert(&mut self, other: Self) {
                *self = Self(self.0).union(other);
            }
            /// The intersection of `self` with the complement of `other` (`&!`).
            ///
            /// This method is not equivalent to `self & !other` when `other` has unknown bits set.
            /// `remove` won't truncate `other`, but the `!` operator will.
            #[inline]
            pub fn remove(&mut self, other: Self) {
                *self = Self(self.0).difference(other);
            }
            /// The bitwise exclusive-or (`^`) of the bits in `self` and `other`.
            #[inline]
            pub fn toggle(&mut self, other: Self) {
                *self = Self(self.0).symmetric_difference(other);
            }
            /// Call `insert` when `value` is `true` or `remove` when `value` is `false`.
            #[inline]
            pub fn set(&mut self, other: Self, value: bool) {
                if value { self.insert(other); } else { self.remove(other); }
            }
            /// The bitwise and (`&`) of the bits in `self` and `other`.
            #[inline]
            #[must_use]
            pub const fn intersection(self, other: Self) -> Self {
                Self(self.0 & other.0)
            }
            /// The bitwise or (`|`) of the bits in `self` and `other`.
            #[inline]
            #[must_use]
            pub const fn union(self, other: Self) -> Self {
                Self(self.0 | other.0)
            }
            /// The intersection of `self` with the complement of `other` (`&!`).
            ///
            /// This method is not equivalent to `self & !other` when `other` has unknown bits set.
            /// `difference` won't truncate `other`, but the `!` operator will.
            #[inline]
            #[must_use]
            pub const fn difference(self, other: Self) -> Self {
                Self(self.0 & !other.0)
            }
            /// The bitwise exclusive-or (`^`) of the bits in `self` and `other`.
            #[inline]
            #[must_use]
            pub const fn symmetric_difference(self, other: Self) -> Self {
                Self(self.0 ^ other.0)
            }
            /// The bitwise negation (`!`) of the bits in `self`, truncating the result.
            #[inline]
            #[must_use]
            pub const fn complement(self) -> Self {
                Self::from_bits_truncate(!self.0)
            }
        }
        impl ::bitflags::__private::core::fmt::Binary for InternalBitFlags {
            fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
                -> ::bitflags::__private::core::fmt::Result {
                let inner = self.0;
                ::bitflags::__private::core::fmt::Binary::fmt(&inner, f)
            }
        }
        impl ::bitflags::__private::core::fmt::Octal for InternalBitFlags {
            fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
                -> ::bitflags::__private::core::fmt::Result {
                let inner = self.0;
                ::bitflags::__private::core::fmt::Octal::fmt(&inner, f)
            }
        }
        impl ::bitflags::__private::core::fmt::LowerHex for InternalBitFlags {
            fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
                -> ::bitflags::__private::core::fmt::Result {
                let inner = self.0;
                ::bitflags::__private::core::fmt::LowerHex::fmt(&inner, f)
            }
        }
        impl ::bitflags::__private::core::fmt::UpperHex for InternalBitFlags {
            fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
                -> ::bitflags::__private::core::fmt::Result {
                let inner = self.0;
                ::bitflags::__private::core::fmt::UpperHex::fmt(&inner, f)
            }
        }
        impl ::bitflags::__private::core::ops::BitOr for InternalBitFlags {
            type Output = Self;
            /// The bitwise or (`|`) of the bits in `self` and `other`.
            #[inline]
            fn bitor(self, other: InternalBitFlags) -> Self {
                self.union(other)
            }
        }
        impl ::bitflags::__private::core::ops::BitOrAssign for
            InternalBitFlags {
            /// The bitwise or (`|`) of the bits in `self` and `other`.
            #[inline]
            fn bitor_assign(&mut self, other: Self) { self.insert(other); }
        }
        impl ::bitflags::__private::core::ops::BitXor for InternalBitFlags {
            type Output = Self;
            /// The bitwise exclusive-or (`^`) of the bits in `self` and `other`.
            #[inline]
            fn bitxor(self, other: Self) -> Self {
                self.symmetric_difference(other)
            }
        }
        impl ::bitflags::__private::core::ops::BitXorAssign for
            InternalBitFlags {
            /// The bitwise exclusive-or (`^`) of the bits in `self` and `other`.
            #[inline]
            fn bitxor_assign(&mut self, other: Self) { self.toggle(other); }
        }
        impl ::bitflags::__private::core::ops::BitAnd for InternalBitFlags {
            type Output = Self;
            /// The bitwise and (`&`) of the bits in `self` and `other`.
            #[inline]
            fn bitand(self, other: Self) -> Self { self.intersection(other) }
        }
        impl ::bitflags::__private::core::ops::BitAndAssign for
            InternalBitFlags {
            /// The bitwise and (`&`) of the bits in `self` and `other`.
            #[inline]
            fn bitand_assign(&mut self, other: Self) {
                *self =
                    Self::from_bits_retain(self.bits()).intersection(other);
            }
        }
        impl ::bitflags::__private::core::ops::Sub for InternalBitFlags {
            type Output = Self;
            /// The intersection of `self` with the complement of `other` (`&!`).
            ///
            /// This method is not equivalent to `self & !other` when `other` has unknown bits set.
            /// `difference` won't truncate `other`, but the `!` operator will.
            #[inline]
            fn sub(self, other: Self) -> Self { self.difference(other) }
        }
        impl ::bitflags::__private::core::ops::SubAssign for InternalBitFlags
            {
            /// The intersection of `self` with the complement of `other` (`&!`).
            ///
            /// This method is not equivalent to `self & !other` when `other` has unknown bits set.
            /// `difference` won't truncate `other`, but the `!` operator will.
            #[inline]
            fn sub_assign(&mut self, other: Self) { self.remove(other); }
        }
        impl ::bitflags::__private::core::ops::Not for InternalBitFlags {
            type Output = Self;
            /// The bitwise negation (`!`) of the bits in `self`, truncating the result.
            #[inline]
            fn not(self) -> Self { self.complement() }
        }
        impl ::bitflags::__private::core::iter::Extend<InternalBitFlags> for
            InternalBitFlags {
            /// The bitwise or (`|`) of the bits in each flags value.
            fn extend<T: ::bitflags::__private::core::iter::IntoIterator<Item
                = Self>>(&mut self, iterator: T) {
                for item in iterator { self.insert(item) }
            }
        }
        impl ::bitflags::__private::core::iter::FromIterator<InternalBitFlags>
            for InternalBitFlags {
            /// The bitwise or (`|`) of the bits in each flags value.
            fn from_iter<T: ::bitflags::__private::core::iter::IntoIterator<Item
                = Self>>(iterator: T) -> Self {
                use ::bitflags::__private::core::iter::Extend;
                let mut result = Self::empty();
                result.extend(iterator);
                result
            }
        }
        impl InternalBitFlags {
            /// Yield a set of contained flags values.
            ///
            /// Each yielded flags value will correspond to a defined named flag. Any unknown bits
            /// will be yielded together as a final flags value.
            #[inline]
            pub const fn iter(&self)
                -> ::bitflags::iter::Iter<MeshPipelineViewLayoutKey> {
                ::bitflags::iter::Iter::__private_const_new(<MeshPipelineViewLayoutKey
                        as ::bitflags::Flags>::FLAGS,
                    MeshPipelineViewLayoutKey::from_bits_retain(self.bits()),
                    MeshPipelineViewLayoutKey::from_bits_retain(self.bits()))
            }
            /// Yield a set of contained named flags values.
            ///
            /// This method is like [`iter`](#method.iter), except only yields bits in contained named flags.
            /// Any unknown bits, or bits not corresponding to a contained flag will not be yielded.
            #[inline]
            pub const fn iter_names(&self)
                -> ::bitflags::iter::IterNames<MeshPipelineViewLayoutKey> {
                ::bitflags::iter::IterNames::__private_const_new(<MeshPipelineViewLayoutKey
                        as ::bitflags::Flags>::FLAGS,
                    MeshPipelineViewLayoutKey::from_bits_retain(self.bits()),
                    MeshPipelineViewLayoutKey::from_bits_retain(self.bits()))
            }
        }
        impl ::bitflags::__private::core::iter::IntoIterator for
            InternalBitFlags {
            type Item = MeshPipelineViewLayoutKey;
            type IntoIter = ::bitflags::iter::Iter<MeshPipelineViewLayoutKey>;
            fn into_iter(self) -> Self::IntoIter { self.iter() }
        }
        impl InternalBitFlags {
            /// Returns a mutable reference to the raw value of the flags currently stored.
            #[inline]
            pub fn bits_mut(&mut self) -> &mut u32 { &mut self.0 }
        }
        impl ::bitflags::__private::serde::Serialize for InternalBitFlags {
            fn serialize<S: ::bitflags::__private::serde::Serializer>(&self,
                serializer: S)
                ->
                    ::bitflags::__private::core::result::Result<S::Ok,
                    S::Error> {
                ::bitflags::serde::serialize(&MeshPipelineViewLayoutKey::from_bits_retain(self.bits()),
                    serializer)
            }
        }
        impl<'de> ::bitflags::__private::serde::Deserialize<'de> for
            InternalBitFlags {
            fn deserialize<D: ::bitflags::__private::serde::Deserializer<'de>>(deserializer:
                    D)
                ->
                    ::bitflags::__private::core::result::Result<Self,
                    D::Error> {
                let flags: MeshPipelineViewLayoutKey =
                    ::bitflags::serde::deserialize(deserializer)?;
                ::bitflags::__private::core::result::Result::Ok(flags.0)
            }
        }
        unsafe impl ::bitflags::__private::bytemuck::Pod for InternalBitFlags
            where u32: ::bitflags::__private::bytemuck::Pod {}
        unsafe impl ::bitflags::__private::bytemuck::Zeroable for
            InternalBitFlags where
            u32: ::bitflags::__private::bytemuck::Zeroable {}
        impl MeshPipelineViewLayoutKey {
            /// Get a flags value with all bits unset.
            #[inline]
            pub const fn empty() -> Self { Self(InternalBitFlags::empty()) }
            /// Get a flags value with all known bits set.
            #[inline]
            pub const fn all() -> Self { Self(InternalBitFlags::all()) }
            /// Get the underlying bits value.
            ///
            /// The returned value is exactly the bits set in this flags value.
            #[inline]
            pub const fn bits(&self) -> u32 { self.0.bits() }
            /// Convert from a bits value.
            ///
            /// This method will return `None` if any unknown bits are set.
            #[inline]
            pub const fn from_bits(bits: u32)
                -> ::bitflags::__private::core::option::Option<Self> {
                match InternalBitFlags::from_bits(bits) {
                    ::bitflags::__private::core::option::Option::Some(bits) =>
                        ::bitflags::__private::core::option::Option::Some(Self(bits)),
                    ::bitflags::__private::core::option::Option::None =>
                        ::bitflags::__private::core::option::Option::None,
                }
            }
            /// Convert from a bits value, unsetting any unknown bits.
            #[inline]
            pub const fn from_bits_truncate(bits: u32) -> Self {
                Self(InternalBitFlags::from_bits_truncate(bits))
            }
            /// Convert from a bits value exactly.
            #[inline]
            pub const fn from_bits_retain(bits: u32) -> Self {
                Self(InternalBitFlags::from_bits_retain(bits))
            }
            /// Get a flags value with the bits of a flag with the given name set.
            ///
            /// This method will return `None` if `name` is empty or doesn't
            /// correspond to any named flag.
            #[inline]
            pub fn from_name(name: &str)
                -> ::bitflags::__private::core::option::Option<Self> {
                match InternalBitFlags::from_name(name) {
                    ::bitflags::__private::core::option::Option::Some(bits) =>
                        ::bitflags::__private::core::option::Option::Some(Self(bits)),
                    ::bitflags::__private::core::option::Option::None =>
                        ::bitflags::__private::core::option::Option::None,
                }
            }
            /// Whether all bits in `self` are unset.
            #[inline]
            pub const fn is_empty(&self) -> bool { self.0.is_empty() }
            /// Whether all known bits in this flags value are set.
            #[inline]
            pub const fn is_all(&self) -> bool { self.0.is_all() }
            /// Whether any set bits in `other` are also set in `self`.
            #[inline]
            pub const fn intersects(&self, other: Self) -> bool {
                self.0.intersects(other.0)
            }
            /// Whether all set bits in `other` are also set in `self`.
            #[inline]
            pub const fn contains(&self, other: Self) -> bool {
                self.0.contains(other.0)
            }
            /// The bitwise or (`|`) of the bits in `self` and `other`.
            #[inline]
            pub fn insert(&mut self, other: Self) { self.0.insert(other.0) }
            /// The intersection of `self` with the complement of `other` (`&!`).
            ///
            /// This method is not equivalent to `self & !other` when `other` has unknown bits set.
            /// `remove` won't truncate `other`, but the `!` operator will.
            #[inline]
            pub fn remove(&mut self, other: Self) { self.0.remove(other.0) }
            /// The bitwise exclusive-or (`^`) of the bits in `self` and `other`.
            #[inline]
            pub fn toggle(&mut self, other: Self) { self.0.toggle(other.0) }
            /// Call `insert` when `value` is `true` or `remove` when `value` is `false`.
            #[inline]
            pub fn set(&mut self, other: Self, value: bool) {
                self.0.set(other.0, value)
            }
            /// The bitwise and (`&`) of the bits in `self` and `other`.
            #[inline]
            #[must_use]
            pub const fn intersection(self, other: Self) -> Self {
                Self(self.0.intersection(other.0))
            }
            /// The bitwise or (`|`) of the bits in `self` and `other`.
            #[inline]
            #[must_use]
            pub const fn union(self, other: Self) -> Self {
                Self(self.0.union(other.0))
            }
            /// The intersection of `self` with the complement of `other` (`&!`).
            ///
            /// This method is not equivalent to `self & !other` when `other` has unknown bits set.
            /// `difference` won't truncate `other`, but the `!` operator will.
            #[inline]
            #[must_use]
            pub const fn difference(self, other: Self) -> Self {
                Self(self.0.difference(other.0))
            }
            /// The bitwise exclusive-or (`^`) of the bits in `self` and `other`.
            #[inline]
            #[must_use]
            pub const fn symmetric_difference(self, other: Self) -> Self {
                Self(self.0.symmetric_difference(other.0))
            }
            /// The bitwise negation (`!`) of the bits in `self`, truncating the result.
            #[inline]
            #[must_use]
            pub const fn complement(self) -> Self {
                Self(self.0.complement())
            }
        }
        impl ::bitflags::__private::core::fmt::Binary for
            MeshPipelineViewLayoutKey {
            fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
                -> ::bitflags::__private::core::fmt::Result {
                let inner = self.0;
                ::bitflags::__private::core::fmt::Binary::fmt(&inner, f)
            }
        }
        impl ::bitflags::__private::core::fmt::Octal for
            MeshPipelineViewLayoutKey {
            fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
                -> ::bitflags::__private::core::fmt::Result {
                let inner = self.0;
                ::bitflags::__private::core::fmt::Octal::fmt(&inner, f)
            }
        }
        impl ::bitflags::__private::core::fmt::LowerHex for
            MeshPipelineViewLayoutKey {
            fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
                -> ::bitflags::__private::core::fmt::Result {
                let inner = self.0;
                ::bitflags::__private::core::fmt::LowerHex::fmt(&inner, f)
            }
        }
        impl ::bitflags::__private::core::fmt::UpperHex for
            MeshPipelineViewLayoutKey {
            fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
                -> ::bitflags::__private::core::fmt::Result {
                let inner = self.0;
                ::bitflags::__private::core::fmt::UpperHex::fmt(&inner, f)
            }
        }
        impl ::bitflags::__private::core::ops::BitOr for
            MeshPipelineViewLayoutKey {
            type Output = Self;
            /// The bitwise or (`|`) of the bits in `self` and `other`.
            #[inline]
            fn bitor(self, other: MeshPipelineViewLayoutKey) -> Self {
                self.union(other)
            }
        }
        impl ::bitflags::__private::core::ops::BitOrAssign for
            MeshPipelineViewLayoutKey {
            /// The bitwise or (`|`) of the bits in `self` and `other`.
            #[inline]
            fn bitor_assign(&mut self, other: Self) { self.insert(other); }
        }
        impl ::bitflags::__private::core::ops::BitXor for
            MeshPipelineViewLayoutKey {
            type Output = Self;
            /// The bitwise exclusive-or (`^`) of the bits in `self` and `other`.
            #[inline]
            fn bitxor(self, other: Self) -> Self {
                self.symmetric_difference(other)
            }
        }
        impl ::bitflags::__private::core::ops::BitXorAssign for
            MeshPipelineViewLayoutKey {
            /// The bitwise exclusive-or (`^`) of the bits in `self` and `other`.
            #[inline]
            fn bitxor_assign(&mut self, other: Self) { self.toggle(other); }
        }
        impl ::bitflags::__private::core::ops::BitAnd for
            MeshPipelineViewLayoutKey {
            type Output = Self;
            /// The bitwise and (`&`) of the bits in `self` and `other`.
            #[inline]
            fn bitand(self, other: Self) -> Self { self.intersection(other) }
        }
        impl ::bitflags::__private::core::ops::BitAndAssign for
            MeshPipelineViewLayoutKey {
            /// The bitwise and (`&`) of the bits in `self` and `other`.
            #[inline]
            fn bitand_assign(&mut self, other: Self) {
                *self =
                    Self::from_bits_retain(self.bits()).intersection(other);
            }
        }
        impl ::bitflags::__private::core::ops::Sub for
            MeshPipelineViewLayoutKey {
            type Output = Self;
            /// The intersection of `self` with the complement of `other` (`&!`).
            ///
            /// This method is not equivalent to `self & !other` when `other` has unknown bits set.
            /// `difference` won't truncate `other`, but the `!` operator will.
            #[inline]
            fn sub(self, other: Self) -> Self { self.difference(other) }
        }
        impl ::bitflags::__private::core::ops::SubAssign for
            MeshPipelineViewLayoutKey {
            /// The intersection of `self` with the complement of `other` (`&!`).
            ///
            /// This method is not equivalent to `self & !other` when `other` has unknown bits set.
            /// `difference` won't truncate `other`, but the `!` operator will.
            #[inline]
            fn sub_assign(&mut self, other: Self) { self.remove(other); }
        }
        impl ::bitflags::__private::core::ops::Not for
            MeshPipelineViewLayoutKey {
            type Output = Self;
            /// The bitwise negation (`!`) of the bits in `self`, truncating the result.
            #[inline]
            fn not(self) -> Self { self.complement() }
        }
        impl ::bitflags::__private::core::iter::Extend<MeshPipelineViewLayoutKey>
            for MeshPipelineViewLayoutKey {
            /// The bitwise or (`|`) of the bits in each flags value.
            fn extend<T: ::bitflags::__private::core::iter::IntoIterator<Item
                = Self>>(&mut self, iterator: T) {
                for item in iterator { self.insert(item) }
            }
        }
        impl ::bitflags::__private::core::iter::FromIterator<MeshPipelineViewLayoutKey>
            for MeshPipelineViewLayoutKey {
            /// The bitwise or (`|`) of the bits in each flags value.
            fn from_iter<T: ::bitflags::__private::core::iter::IntoIterator<Item
                = Self>>(iterator: T) -> Self {
                use ::bitflags::__private::core::iter::Extend;
                let mut result = Self::empty();
                result.extend(iterator);
                result
            }
        }
        impl MeshPipelineViewLayoutKey {
            /// Yield a set of contained flags values.
            ///
            /// Each yielded flags value will correspond to a defined named flag. Any unknown bits
            /// will be yielded together as a final flags value.
            #[inline]
            pub const fn iter(&self)
                -> ::bitflags::iter::Iter<MeshPipelineViewLayoutKey> {
                ::bitflags::iter::Iter::__private_const_new(<MeshPipelineViewLayoutKey
                        as ::bitflags::Flags>::FLAGS,
                    MeshPipelineViewLayoutKey::from_bits_retain(self.bits()),
                    MeshPipelineViewLayoutKey::from_bits_retain(self.bits()))
            }
            /// Yield a set of contained named flags values.
            ///
            /// This method is like [`iter`](#method.iter), except only yields bits in contained named flags.
            /// Any unknown bits, or bits not corresponding to a contained flag will not be yielded.
            #[inline]
            pub const fn iter_names(&self)
                -> ::bitflags::iter::IterNames<MeshPipelineViewLayoutKey> {
                ::bitflags::iter::IterNames::__private_const_new(<MeshPipelineViewLayoutKey
                        as ::bitflags::Flags>::FLAGS,
                    MeshPipelineViewLayoutKey::from_bits_retain(self.bits()),
                    MeshPipelineViewLayoutKey::from_bits_retain(self.bits()))
            }
        }
        impl ::bitflags::__private::core::iter::IntoIterator for
            MeshPipelineViewLayoutKey {
            type Item = MeshPipelineViewLayoutKey;
            type IntoIter = ::bitflags::iter::Iter<MeshPipelineViewLayoutKey>;
            fn into_iter(self) -> Self::IntoIter { self.iter() }
        }
    };bitflags::bitflags! {
82    /// A key that uniquely identifies a [`MeshPipelineViewLayout`].
83    #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
84    #[repr(transparent)]
85    pub struct MeshPipelineViewLayoutKey: u32 {
86        const MULTISAMPLED                     = 1 << 0;
87        const DEPTH_PREPASS                    = 1 << 1;
88        const NORMAL_PREPASS                   = 1 << 2;
89        const MOTION_VECTOR_PREPASS            = 1 << 3;
90        const DEFERRED_PREPASS                 = 1 << 4;
91        const OIT_ENABLED                      = 1 << 5;
92        const ATMOSPHERE                       = 1 << 6;
93        const STBN                             = 1 << 7;
94        const TONEMAP_IN_SHADER                = 1 << 8;
95        const ENVIRONMENT_MAP                  = 1 << 9;
96        const SCREEN_SPACE_AMBIENT_OCCLUSION   = 1 << 10;
97        const IRRADIANCE_VOLUME                = 1 << 11;
98        const SCREEN_SPACE_REFLECTIONS         = 1 << 12;
99        const CONTACT_SHADOWS                  = 1 << 13;
100        const DISTANCE_FOG                     = 1 << 14;
101        const AREA_LIGHT_LUTS                  = 1 << 15;
102        const VIEW_TRANSMISSION_TEXTURE        = 1 << 16;
103    }
104}
105
106impl MeshPipelineViewLayoutKey {
107    /// Builds a unique label for each layout based on the flags
108    pub fn label(&self) -> String {
109        let iter = self
110            .iter_names()
111            .filter(|(_, key)| self.contains(*key))
112            .map(|(name, _)| name.to_lowercase());
113        let (lower, _) = iter.size_hint();
114        let sep = ",";
115        let mut result = String::with_capacity(sep.len() * lower);
116
117        for (i, name) in iter.enumerate() {
118            if i != 0 {
119                result.push_str(sep);
120            }
121            (&mut result).write_fmt(format_args!("{0}", name))write!(&mut result, "{}", name).unwrap();
122        }
123
124        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("mesh_view_layout:{0}", result))
    })format!("mesh_view_layout:{}", result)
125    }
126}
127
128impl From<MeshPipelineKey> for MeshPipelineViewLayoutKey {
129    fn from(value: MeshPipelineKey) -> Self {
130        let mut result = MeshPipelineViewLayoutKey::empty();
131
132        if value.msaa_samples() > 1 {
133            result |= MeshPipelineViewLayoutKey::MULTISAMPLED;
134        }
135        if value.contains(MeshPipelineKey::DEPTH_PREPASS) {
136            result |= MeshPipelineViewLayoutKey::DEPTH_PREPASS;
137        }
138        if value.contains(MeshPipelineKey::NORMAL_PREPASS) {
139            result |= MeshPipelineViewLayoutKey::NORMAL_PREPASS;
140        }
141        if value.contains(MeshPipelineKey::MOTION_VECTOR_PREPASS) {
142            result |= MeshPipelineViewLayoutKey::MOTION_VECTOR_PREPASS;
143        }
144        if value.contains(MeshPipelineKey::DEFERRED_PREPASS) {
145            result |= MeshPipelineViewLayoutKey::DEFERRED_PREPASS;
146        }
147        if value.contains(MeshPipelineKey::OIT_ENABLED) {
148            result |= MeshPipelineViewLayoutKey::OIT_ENABLED;
149        }
150        if value.contains(MeshPipelineKey::ATMOSPHERE) {
151            result |= MeshPipelineViewLayoutKey::ATMOSPHERE;
152        }
153
154        if truecfg!(feature = "bluenoise_texture") {
155            result |= MeshPipelineViewLayoutKey::STBN;
156        }
157
158        if truecfg!(feature = "area_light_luts") {
159            result |= MeshPipelineViewLayoutKey::AREA_LIGHT_LUTS;
160        }
161
162        if value.contains(MeshPipelineKey::TONEMAP_IN_SHADER) {
163            result |= MeshPipelineViewLayoutKey::TONEMAP_IN_SHADER;
164        }
165        if value.contains(MeshPipelineKey::ENVIRONMENT_MAP) {
166            result |= MeshPipelineViewLayoutKey::ENVIRONMENT_MAP;
167        }
168        if value.contains(MeshPipelineKey::SCREEN_SPACE_AMBIENT_OCCLUSION) {
169            result |= MeshPipelineViewLayoutKey::SCREEN_SPACE_AMBIENT_OCCLUSION;
170        }
171        if value.contains(MeshPipelineKey::IRRADIANCE_VOLUME) {
172            result |= MeshPipelineViewLayoutKey::IRRADIANCE_VOLUME;
173        }
174        if value.contains(MeshPipelineKey::SCREEN_SPACE_REFLECTIONS) {
175            result |= MeshPipelineViewLayoutKey::SCREEN_SPACE_REFLECTIONS;
176        }
177        if value.contains(MeshPipelineKey::CONTACT_SHADOWS) {
178            result |= MeshPipelineViewLayoutKey::CONTACT_SHADOWS;
179        }
180        if value.contains(MeshPipelineKey::DISTANCE_FOG) {
181            result |= MeshPipelineViewLayoutKey::DISTANCE_FOG;
182        }
183        if value.contains(MeshPipelineKey::VIEW_TRANSMISSION_TEXTURE) {
184            result |= MeshPipelineViewLayoutKey::VIEW_TRANSMISSION_TEXTURE;
185        }
186
187        result
188    }
189}
190
191impl From<Msaa> for MeshPipelineViewLayoutKey {
192    fn from(value: Msaa) -> Self {
193        let mut result = MeshPipelineViewLayoutKey::empty();
194
195        if value.samples() > 1 {
196            result |= MeshPipelineViewLayoutKey::MULTISAMPLED;
197        }
198
199        result
200    }
201}
202
203impl From<Option<&ViewPrepassTextures>> for MeshPipelineViewLayoutKey {
204    fn from(value: Option<&ViewPrepassTextures>) -> Self {
205        let mut result = MeshPipelineViewLayoutKey::empty();
206
207        if let Some(prepass_textures) = value {
208            if prepass_textures.depth.is_some() {
209                result |= MeshPipelineViewLayoutKey::DEPTH_PREPASS;
210            }
211            if prepass_textures.normal.is_some() {
212                result |= MeshPipelineViewLayoutKey::NORMAL_PREPASS;
213            }
214            if prepass_textures.motion_vectors.is_some() {
215                result |= MeshPipelineViewLayoutKey::MOTION_VECTOR_PREPASS;
216            }
217            if prepass_textures.deferred.is_some() {
218                result |= MeshPipelineViewLayoutKey::DEFERRED_PREPASS;
219            }
220        }
221
222        result
223    }
224}
225
226pub(crate) fn buffer_layout(
227    buffer_binding_type: BufferBindingType,
228    has_dynamic_offset: bool,
229    min_binding_size: Option<NonZero<u64>>,
230) -> BindGroupLayoutEntryBuilder {
231    match buffer_binding_type {
232        BufferBindingType::Uniform => uniform_buffer_sized(has_dynamic_offset, min_binding_size),
233        BufferBindingType::Storage { read_only } => {
234            if read_only {
235                storage_buffer_read_only_sized(has_dynamic_offset, min_binding_size)
236            } else {
237                storage_buffer_sized(has_dynamic_offset, min_binding_size)
238            }
239        }
240    }
241}
242
243/// Returns the appropriate bind group layout vec based on the parameters
244fn layout_entries(
245    layout_key: MeshPipelineViewLayoutKey,
246    &MeshPipelineViewLayoutParams {
247        clustered_forward_buffer_binding_type,
248        visibility_ranges_buffer_binding_type,
249        environment_map_entries,
250        irradiance_volume_entries,
251        clustered_decal_entries,
252        is_oit_supported,
253    }: &MeshPipelineViewLayoutParams,
254) -> [Vec<BindGroupLayoutEntry>; 2] {
255    let mut entries = DynamicBindGroupLayoutEntries::new_with_indices(
256        ShaderStages::FRAGMENT,
257        (
258            // View
259            (
260                0,
261                uniform_buffer::<ViewUniform>(true).visibility(ShaderStages::VERTEX_FRAGMENT),
262            ),
263            // Lights
264            (1, uniform_buffer::<GpuLights>(true)),
265            // Point Shadow Texture Cube Array
266            (
267                2,
268                #[cfg(all(
269                    not(target_abi = "sim"),
270                    any(
271                        not(feature = "webgl"),
272                        not(target_arch = "wasm32"),
273                        feature = "webgpu"
274                    )
275                ))]
276                texture_cube_array(TextureSampleType::Depth),
277                #[cfg(any(
278                    target_abi = "sim",
279                    all(feature = "webgl", target_arch = "wasm32", not(feature = "webgpu"))
280                ))]
281                texture_cube(TextureSampleType::Depth),
282            ),
283            // Point Shadow Texture Array Comparison Sampler
284            (3, sampler(SamplerBindingType::Comparison)),
285            // Point Shadow Texture Array Linear Sampler
286            #[cfg(feature = "experimental_pbr_pcss")]
287            (4, sampler(SamplerBindingType::Filtering)),
288            // Directional Shadow Texture Array
289            (
290                5,
291                #[cfg(any(
292                    not(feature = "webgl"),
293                    not(target_arch = "wasm32"),
294                    feature = "webgpu"
295                ))]
296                texture_2d_array(TextureSampleType::Depth),
297                #[cfg(all(feature = "webgl", target_arch = "wasm32", not(feature = "webgpu")))]
298                texture_2d(TextureSampleType::Depth),
299            ),
300            // Directional Shadow Texture Array Comparison Sampler
301            (6, sampler(SamplerBindingType::Comparison)),
302            // Directional Shadow Texture Array Linear Sampler
303            #[cfg(feature = "experimental_pbr_pcss")]
304            (7, sampler(SamplerBindingType::Filtering)),
305            // PointLights
306            (
307                8,
308                buffer_layout(
309                    clustered_forward_buffer_binding_type,
310                    false,
311                    Some(GpuClusteredLights::min_size(
312                        clustered_forward_buffer_binding_type,
313                    )),
314                ),
315            ),
316            // ClusteredLightIndexLists
317            (
318                9,
319                buffer_layout(
320                    clustered_forward_buffer_binding_type,
321                    false,
322                    Some(
323                        ViewClusterBindings::min_size_clusterable_object_index_lists(
324                            clustered_forward_buffer_binding_type,
325                        ),
326                    ),
327                ),
328            ),
329            // ClusterOffsetsAndCounts
330            (
331                10,
332                buffer_layout(
333                    clustered_forward_buffer_binding_type,
334                    false,
335                    Some(ViewClusterBindings::min_size_cluster_offsets_and_counts(
336                        clustered_forward_buffer_binding_type,
337                    )),
338                ),
339            ),
340            // Globals
341            (
342                11,
343                uniform_buffer::<GlobalsUniform>(false).visibility(ShaderStages::VERTEX_FRAGMENT),
344            ),
345            // Light probes
346            (12, uniform_buffer::<LightProbesUniform>(true)),
347            // Visibility ranges
348            (
349                14,
350                buffer_layout(
351                    visibility_ranges_buffer_binding_type,
352                    false,
353                    Some(Vec4::min_size()),
354                )
355                .visibility(ShaderStages::VERTEX),
356            ),
357        ),
358    );
359
360    if layout_key.contains(MeshPipelineViewLayoutKey::DISTANCE_FOG) {
361        entries = entries.extend_with_indices((
362            // Fog
363            (13, uniform_buffer::<GpuFog>(true)),
364        ));
365    }
366    if layout_key.contains(MeshPipelineViewLayoutKey::SCREEN_SPACE_REFLECTIONS) {
367        entries = entries.extend_with_indices((
368            // Screen space reflection settings
369            (15, uniform_buffer::<ScreenSpaceReflectionsUniform>(true)),
370        ));
371    }
372    if layout_key.contains(MeshPipelineViewLayoutKey::CONTACT_SHADOWS) {
373        entries = entries.extend_with_indices((
374            // Contact shadows settings
375            (16, uniform_buffer::<ContactShadowsUniform>(true)),
376        ));
377    }
378    if layout_key.contains(MeshPipelineViewLayoutKey::SCREEN_SPACE_AMBIENT_OCCLUSION) {
379        entries = entries.extend_with_indices((
380            // Screen space ambient occlusion texture
381            (
382                17,
383                texture_2d(TextureSampleType::Float { filterable: false }),
384            ),
385        ));
386    }
387
388    if layout_key.contains(MeshPipelineViewLayoutKey::TONEMAP_IN_SHADER) {
389        // Tonemapping
390        let tonemapping_lut_entries = get_lut_bind_group_layout_entries();
391        entries = entries.extend_with_indices((
392            (
393                TONEMAPPING_LUT_TEXTURE_BINDING_INDEX,
394                tonemapping_lut_entries[0],
395            ),
396            (
397                TONEMAPPING_LUT_SAMPLER_BINDING_INDEX,
398                tonemapping_lut_entries[1],
399            ),
400        ));
401    }
402
403    // Prepass
404    if truecfg!(any(feature = "webgpu", not(target_arch = "wasm32")))
405        || !layout_key.contains(MeshPipelineViewLayoutKey::MULTISAMPLED)
406    {
407        for (entry, binding) in prepass::get_bind_group_layout_entries(layout_key)
408            .iter()
409            .zip([20, 21, 22, 23])
410        {
411            if let Some(entry) = entry {
412                entries = entries.extend_with_indices(((binding as u32, *entry),));
413            }
414        }
415    }
416
417    // View Transmission Texture
418    if layout_key.contains(MeshPipelineViewLayoutKey::VIEW_TRANSMISSION_TEXTURE) {
419        entries = entries.extend_with_indices((
420            (
421                24,
422                texture_2d(TextureSampleType::Float { filterable: true }),
423            ),
424            (25, sampler(SamplerBindingType::Filtering)),
425        ));
426    }
427
428    // OIT
429    if layout_key.contains(MeshPipelineViewLayoutKey::OIT_ENABLED) {
430        // Check if we can use OIT. This is a hack to avoid errors on webgl --
431        // the OIT plugin will warn the user that OIT is not supported on their
432        // platform, so we don't need to do it here.
433        if is_oit_supported {
434            entries = entries.extend_with_indices((
435                (
436                    26,
437                    uniform_buffer::<OrderIndependentTransparencySettings>(true),
438                ),
439                // oit_nodes_capacity
440                (27, uniform_buffer::<u32>(false)),
441                // oit_nodes
442                (28, storage_buffer_sized(false, None)),
443                // oit_heads,
444                (29, storage_buffer_sized(false, None)),
445                // oit_atomic_counter
446                (
447                    30,
448                    storage_buffer_sized(false, NonZero::<u64>::new(size_of::<u32>() as u64)),
449                ),
450            ));
451        }
452    }
453
454    // Atmosphere
455    if layout_key.contains(MeshPipelineViewLayoutKey::ATMOSPHERE) {
456        entries = entries.extend_with_indices((
457            // transmittance LUT
458            (
459                31,
460                texture_2d(TextureSampleType::Float { filterable: true }),
461            ),
462            (32, sampler(SamplerBindingType::Filtering)),
463            // atmosphere data buffer
464            (33, storage_buffer_read_only::<GpuAtmosphere>(false)),
465        ));
466    }
467
468    // Blue noise
469    if layout_key.contains(MeshPipelineViewLayoutKey::STBN) {
470        entries = entries.extend_with_indices(((
471            34,
472            texture_2d_array(TextureSampleType::Float { filterable: false }),
473        ),));
474    }
475    // LTC LUTs for area lights
476    if truecfg!(feature = "area_light_luts") {
477        entries = entries.extend_with_indices((
478            (
479                35,
480                texture_2d_array(TextureSampleType::Float { filterable: true }),
481            ),
482            (36, sampler(SamplerBindingType::Filtering)),
483        ));
484    }
485    // DFG LUT
486    if truecfg!(feature = "dfg_lut") {
487        entries = entries.extend_with_indices((
488            (
489                37,
490                texture_2d(TextureSampleType::Float { filterable: true }),
491            ),
492            (38, sampler(SamplerBindingType::Filtering)),
493        ));
494    }
495
496    let mut binding_array_entries = DynamicBindGroupLayoutEntries::new(ShaderStages::FRAGMENT);
497    if layout_key.contains(MeshPipelineViewLayoutKey::ENVIRONMENT_MAP) {
498        binding_array_entries = binding_array_entries.extend_with_indices((
499            (0, environment_map_entries[0]),
500            (1, environment_map_entries[1]),
501            (2, environment_map_entries[2]),
502        ));
503    }
504
505    if layout_key.contains(MeshPipelineViewLayoutKey::IRRADIANCE_VOLUME) {
506        // Irradiance volumes
507        if IRRADIANCE_VOLUMES_ARE_USABLE {
508            binding_array_entries = binding_array_entries.extend_with_indices((
509                (3, irradiance_volume_entries[0]),
510                (4, irradiance_volume_entries[1]),
511            ));
512        }
513    }
514
515    // Clustered decals
516    if let Some(clustered_decal_entries) = clustered_decal_entries {
517        binding_array_entries = binding_array_entries.extend_with_indices((
518            (5, clustered_decal_entries[0]),
519            (6, clustered_decal_entries[1]),
520            (7, clustered_decal_entries[2]),
521        ));
522    }
523
524    [entries.to_vec(), binding_array_entries.to_vec()]
525}
526
527/// Parameters needed by [`layout_entries`].
528#[derive(#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for MeshPipelineViewLayoutParams { }
#[automatically_derived]
impl ::core::clone::Clone for MeshPipelineViewLayoutParams {
    #[inline]
    fn clone(&self) -> Self {
        let _: ::core::clone::AssertParamIsClone<BufferBindingType>;
        let _:
                ::core::clone::AssertParamIsClone<[BindGroupLayoutEntryBuilder; 3]>;
        let _:
                ::core::clone::AssertParamIsClone<[BindGroupLayoutEntryBuilder; 2]>;
        let _:
                ::core::clone::AssertParamIsClone<Option<[BindGroupLayoutEntryBuilder; 3]>>;
        let _: ::core::clone::AssertParamIsClone<bool>;
        *self
    }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for MeshPipelineViewLayoutParams { }Copy)]
529struct MeshPipelineViewLayoutParams {
530    clustered_forward_buffer_binding_type: BufferBindingType,
531    visibility_ranges_buffer_binding_type: BufferBindingType,
532    environment_map_entries: [BindGroupLayoutEntryBuilder; 3],
533    irradiance_volume_entries: [BindGroupLayoutEntryBuilder; 2],
534    clustered_decal_entries: Option<[BindGroupLayoutEntryBuilder; 3]>,
535    is_oit_supported: bool,
536}
537
538/// Stores the view layouts entries for creating bind group layouts of pipeline keys.
539#[derive(impl bevy_ecs::component::Component for MeshPipelineViewLayouts where
    Self: ::core::marker::Send + ::core::marker::Sync + 'static {
    const STORAGE_TYPE: bevy_ecs::component::StorageType =
        bevy_ecs::component::StorageType::SparseSet;
    type Mutability = bevy_ecs::component::Mutable;
    fn register_required_components(_requiree:
            bevy_ecs::component::ComponentId,
        required_components:
            &mut bevy_ecs::component::RequiredComponentsRegistrator) {
        let resource_component_id =
            if let ::core::option::Option::Some(id) =
                    required_components.components_registrator().component_id::<MeshPipelineViewLayouts>()
                {
                id
            } else {
                required_components.components_registrator().register_component::<MeshPipelineViewLayouts>()
            };
        required_components.register_required::<bevy_ecs::resource::IsResource>(move
                ||
                bevy_ecs::resource::IsResource::new(resource_component_id));
    }
    fn clone_behavior() -> bevy_ecs::component::ComponentCloneBehavior {
        use bevy_ecs::component::{
            DefaultCloneBehaviorBase, DefaultCloneBehaviorViaClone,
        };
        (&&&bevy_ecs::component::DefaultCloneBehaviorSpecialization::<Self>::default()).default_clone_behavior()
    }
    fn relationship_accessor()
        ->
            ::core::option::Option<bevy_ecs::relationship::ComponentRelationshipAccessor<Self>> {
        ::core::option::Option::None
    }
}
impl bevy_ecs::resource::Resource for MeshPipelineViewLayouts where
    Self: ::core::marker::Send + ::core::marker::Sync + 'static {}Resource, #[automatically_derived]
impl ::core::clone::Clone for MeshPipelineViewLayouts {
    #[inline]
    fn clone(&self) -> Self {
        Self { params: ::core::clone::Clone::clone(&self.params) }
    }
}Clone)]
540pub struct MeshPipelineViewLayouts {
541    params: Arc<MeshPipelineViewLayoutParams>,
542}
543
544pub fn init_mesh_pipeline_view_layouts(
545    mut commands: Commands,
546    render_device: Res<RenderDevice>,
547    render_adapter: Res<RenderAdapter>,
548) {
549    let clustered_forward_buffer_binding_type =
550        render_device.get_supported_read_only_binding_type(CLUSTERED_FORWARD_STORAGE_BUFFER_COUNT);
551    let visibility_ranges_buffer_binding_type =
552        render_device.get_supported_read_only_binding_type(VISIBILITY_RANGES_STORAGE_BUFFER_COUNT);
553
554    let res = MeshPipelineViewLayouts {
555        params: Arc::new(MeshPipelineViewLayoutParams {
556            clustered_forward_buffer_binding_type,
557            visibility_ranges_buffer_binding_type,
558            environment_map_entries: environment_map::get_bind_group_layout_entries(
559                &render_device,
560                &render_adapter,
561            ),
562            irradiance_volume_entries: irradiance_volume::get_bind_group_layout_entries(
563                &render_device,
564                &render_adapter,
565            ),
566            clustered_decal_entries: decal::clustered::get_bind_group_layout_entries(
567                &render_device,
568                &render_adapter,
569            ),
570            is_oit_supported: bevy_core_pipeline::oit::resolve::is_oit_supported(
571                &render_adapter,
572                &render_device,
573                false,
574            ),
575        }),
576    };
577
578    commands.insert_resource(res);
579}
580
581impl MeshPipelineViewLayouts {
582    /// Get view bind group layout for the given key.
583    pub fn get_view_layout(&self, layout_key: MeshPipelineViewLayoutKey) -> MeshPipelineViewLayout {
584        let mut entries = layout_entries(layout_key, &self.params);
585
586        #[cfg(debug_assertions)]
587        let texture_count: usize = entries
588            .iter()
589            .flat_map(|e| {
590                e.iter()
591                    .filter(|entry| #[allow(non_exhaustive_omitted_patterns)] match entry.ty {
    BindingType::Texture { .. } => true,
    _ => false,
}matches!(entry.ty, BindingType::Texture { .. }))
592            })
593            .count();
594
595        #[cfg(debug_assertions)]
596        if texture_count > MESH_PIPELINE_VIEW_LAYOUT_SAFE_MAX_TEXTURES {
597            // Issue our own warning here because Naga's error message is a bit cryptic in this situation
598            {
    static SHOULD_FIRE: ::bevy_utils::OnceFlag =
        ::bevy_utils::OnceFlag::new();
    if SHOULD_FIRE.set() {
        {
            use ::tracing::__macro_support::Callsite as _;
            static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                {
                    static META: ::tracing::Metadata<'static> =
                        {
                            ::tracing_core::metadata::Metadata::new("event src/render/mesh_view_bindings.rs:598",
                                "bevy_pbr::render::mesh_view_bindings",
                                ::tracing::Level::WARN,
                                ::tracing_core::__macro_support::Option::Some("src/render/mesh_view_bindings.rs"),
                                ::tracing_core::__macro_support::Option::Some(598u32),
                                ::tracing_core::__macro_support::Option::Some("bevy_pbr::render::mesh_view_bindings"),
                                ::tracing_core::field::FieldSet::new(&["message"],
                                    ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                ::tracing::metadata::Kind::EVENT)
                        };
                    ::tracing::callsite::DefaultCallsite::new(&META)
                };
            let enabled =
                ::tracing::Level::WARN <=
                            ::tracing::level_filters::STATIC_MAX_LEVEL &&
                        ::tracing::Level::WARN <=
                            ::tracing::level_filters::LevelFilter::current() &&
                    {
                        let interest = __CALLSITE.interest();
                        !interest.is_never() &&
                            ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                                interest)
                    };
            if enabled {
                (|value_set: ::tracing::field::ValueSet|
                            {
                                let meta = __CALLSITE.metadata();
                                ::tracing::Event::dispatch(meta, &value_set);
                                ;
                            })({
                        #[allow(unused_imports)]
                        use ::tracing::field::{debug, display, Value};
                        __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("Too many textures in mesh pipeline view layout, this might cause us to hit `wgpu::Limits::max_sampled_textures_per_shader_stage` in some environments.")
                                                    as &dyn ::tracing::field::Value))])
                    });
            } else { ; }
        };
    }
};once!(warn!(
599                "Too many textures in mesh pipeline view layout, this might cause us \
600            to hit `wgpu::Limits::max_sampled_textures_per_shader_stage` in some environments."
601            ));
602        }
603
604        MeshPipelineViewLayout {
605            main_layout: BindGroupLayoutDescriptor {
606                label: layout_key.label().into(),
607                entries: core::mem::take(&mut entries[0]),
608            },
609            binding_array_layout: BindGroupLayoutDescriptor {
610                label: layout_key
611                    .label()
612                    .replace("mesh_view_layout:", "mesh_view_layout_binding_array:")
613                    .into(),
614                entries: core::mem::take(&mut entries[1]),
615            },
616            empty_layout: BindGroupLayoutDescriptor {
617                label: "mesh_view_layout_empty".into(),
618                entries: ::alloc::vec::Vec::new()vec![],
619            },
620        }
621    }
622}
623
624#[derive(impl bevy_ecs::component::Component for MeshViewBindGroup where
    Self: ::core::marker::Send + ::core::marker::Sync + 'static {
    const STORAGE_TYPE: bevy_ecs::component::StorageType =
        bevy_ecs::component::StorageType::Table;
    type Mutability = bevy_ecs::component::Mutable;
    fn register_required_components(_requiree:
            bevy_ecs::component::ComponentId,
        required_components:
            &mut bevy_ecs::component::RequiredComponentsRegistrator) {}
    fn clone_behavior() -> bevy_ecs::component::ComponentCloneBehavior {
        use bevy_ecs::component::{
            DefaultCloneBehaviorBase, DefaultCloneBehaviorViaClone,
        };
        (&&&bevy_ecs::component::DefaultCloneBehaviorSpecialization::<Self>::default()).default_clone_behavior()
    }
    fn relationship_accessor()
        ->
            ::core::option::Option<bevy_ecs::relationship::ComponentRelationshipAccessor<Self>> {
        ::core::option::Option::None
    }
}Component)]
625pub struct MeshViewBindGroup {
626    pub main: BindGroup,
627    pub main_offsets: ArrayVec<u32, 7>,
628    pub binding_array: BindGroup,
629    pub empty: BindGroup,
630}
631
632pub fn prepare_mesh_view_bind_groups(
633    mut commands: Commands,
634    (render_device, pipeline_cache, render_adapter): (
635        Res<RenderDevice>,
636        Res<PipelineCache>,
637        Res<RenderAdapter>,
638    ),
639    mesh_pipeline: Res<MeshPipeline>,
640    shadow_samplers: Res<ShadowSamplers>,
641    (light_meta, global_clusterable_object_meta, fog_meta, view_uniforms): (
642        Res<LightMeta>,
643        Res<GlobalClusterableObjectMeta>,
644        Res<FogMeta>,
645        Res<ViewUniforms>,
646    ),
647    views: Query<(
648        Entity,
649        Option<&ExtractedCamera>,
650        &ViewShadowBindings,
651        &ViewClusterBindings,
652        &Msaa,
653        Option<&ScreenSpaceAmbientOcclusionResources>,
654        Option<&ViewPrepassTextures>,
655        Option<&ViewTransmissionTexture>,
656        Option<&AtmosphereTextures>,
657        Option<&AtmosphereBuffer>,
658        &Tonemapping,
659        (
660            Option<&RenderViewLightProbes<EnvironmentMapLight>>,
661            Option<&RenderViewLightProbes<IrradianceVolume>>,
662        ),
663        Has<ExtractedAtmosphere>,
664        (
665            &ViewUniformOffset,
666            &ViewLightsUniformOffset,
667            &ViewLightProbesUniformOffset,
668            Option<&ViewFogUniformOffset>,
669            Option<&ViewScreenSpaceReflectionsUniformOffset>,
670            Option<&ViewContactShadowsUniformOffset>,
671            Option<&OrderIndependentTransparencySettingsOffset>,
672            Has<ScreenSpaceTransmission>,
673        ),
674    )>,
675    (images, fallback_image, fallback_image_zero): (
676        Res<RenderAssets<GpuImage>>,
677        Res<FallbackImage>,
678        Res<FallbackImageZero>,
679    ),
680    globals_buffer: Res<GlobalsBuffer>,
681    tonemapping_luts: Res<TonemappingLuts>,
682    light_probes_buffer: Res<LightProbesBuffer>,
683    visibility_ranges: Res<RenderVisibilityRanges>,
684    (ssr_buffer, contact_shadows_buffer, oit_buffers): (
685        Res<ScreenSpaceReflectionsBuffer>,
686        Res<ContactShadowsBuffer>,
687        Res<OitBuffers>,
688    ),
689    (decals_buffer, render_decals, atmosphere_sampler, blue_noise, area_light_luts, dfg_lut): (
690        Res<DecalsBuffer>,
691        Res<RenderClusteredDecals>,
692        Option<Res<AtmosphereSampler>>,
693        Res<Bluenoise>,
694        Res<AreaLightLuts>,
695        Res<DfgLut>,
696    ),
697    // TODO: Figure out how to reuse the memory. `BindGroupEntry` is non-send on wasm with atomics.
698    #[cfg(not(all(target_arch = "wasm32", target_feature = "atomics")))]
699    mut entries_cache: bevy_ecs::system::Local<Vec<BindGroupEntry>>,
700    #[cfg(not(all(target_arch = "wasm32", target_feature = "atomics")))]
701    mut entries_binding_array_cache: bevy_ecs::system::Local<Vec<BindGroupEntry>>,
702) {
703    if let (
704        Some(view_binding),
705        Some(light_binding),
706        Some(clusterable_objects_binding),
707        Some(globals),
708        Some(light_probes_binding),
709        Some(visibility_ranges_buffer),
710    ) = (
711        view_uniforms.uniforms.binding(),
712        light_meta.view_gpu_lights.binding(),
713        global_clusterable_object_meta
714            .gpu_clustered_lights
715            .binding(),
716        globals_buffer.buffer.binding(),
717        light_probes_buffer.binding(),
718        visibility_ranges.buffer().buffer(),
719    ) {
720        for (
721            entity,
722            camera,
723            shadow_bindings,
724            cluster_bindings,
725            msaa,
726            ssao_resources,
727            prepass_textures,
728            transmission_texture,
729            atmosphere_textures,
730            atmosphere_buffer,
731            tonemapping,
732            (render_view_environment_maps, render_view_irradiance_volumes),
733            has_atmosphere,
734            (
735                view_uniform_offset,
736                view_lights_offset,
737                view_light_probes_offset,
738                view_fog_offset,
739                view_ssr_offset,
740                view_contact_shadows_offset,
741                view_oit_settings_offset,
742                has_transmission,
743            ),
744        ) in &views
745        {
746            let mut entries = DynamicBindGroupEntries::new();
747            let mut entries_binding_array = DynamicBindGroupEntries::new();
748            #[cfg(not(all(target_arch = "wasm32", target_feature = "atomics")))]
749            {
750                // Take cache that has static lifetime for `DynamicBindGroupEntries`.
751                // See <https://users.rust-lang.org/t/how-to-cache-a-vectors-capacity/94478/10>.
752                entries.entries = core::mem::take(&mut *entries_cache)
753                    .into_iter()
754                    .map(|_| -> BindGroupEntry { ::core::panicking::panic("internal error: entered unreachable code")unreachable!() })
755                    .collect();
756                entries_binding_array.entries = core::mem::take(&mut *entries_binding_array_cache)
757                    .into_iter()
758                    .map(|_| -> BindGroupEntry { ::core::panicking::panic("internal error: entered unreachable code")unreachable!() })
759                    .collect();
760            }
761
762            let tonemap_in_shader =
763                camera.is_none_or(|camera| !camera.hdr) && tonemapping.is_enabled();
764            let mut layout_key = MeshPipelineViewLayoutKey::from(*msaa)
765                | MeshPipelineViewLayoutKey::from(prepass_textures);
766            let mut offsets = ArrayVec::from_iter([
767                view_uniform_offset.offset,
768                view_lights_offset.offset,
769                **view_light_probes_offset,
770            ]);
771
772            entries = entries.extend_with_indices((
773                (0, view_binding.clone()),
774                (1, light_binding.clone()),
775                (2, &shadow_bindings.point_light_depth_texture_view),
776                (3, &shadow_samplers.point_light_comparison_sampler),
777                #[cfg(feature = "experimental_pbr_pcss")]
778                (4, &shadow_samplers.point_light_linear_sampler),
779                (5, &shadow_bindings.directional_light_depth_texture_view),
780                (6, &shadow_samplers.directional_light_comparison_sampler),
781                #[cfg(feature = "experimental_pbr_pcss")]
782                (7, &shadow_samplers.directional_light_linear_sampler),
783                (8, clusterable_objects_binding.clone()),
784                (
785                    9,
786                    cluster_bindings
787                        .clusterable_object_index_lists_binding()
788                        .unwrap(),
789                ),
790                (10, cluster_bindings.offsets_and_counts_binding().unwrap()),
791                (11, globals.clone()),
792                (12, light_probes_binding.clone()),
793                (14, visibility_ranges_buffer.as_entire_binding()),
794            ));
795
796            if let Some(view_fog_offset) = view_fog_offset {
797                layout_key |= MeshPipelineViewLayoutKey::DISTANCE_FOG;
798                offsets.push(view_fog_offset.offset);
799                entries =
800                    entries.extend_with_indices(((13, fog_meta.gpu_fogs.binding().unwrap()),));
801            }
802
803            if let Some(view_ssr_offset) = view_ssr_offset {
804                layout_key |= MeshPipelineViewLayoutKey::SCREEN_SPACE_REFLECTIONS;
805                offsets.push(**view_ssr_offset);
806                entries = entries.extend_with_indices(((15, ssr_buffer.binding().unwrap()),));
807            }
808
809            if let Some(view_contact_shadows_offset) = view_contact_shadows_offset {
810                layout_key |= MeshPipelineViewLayoutKey::CONTACT_SHADOWS;
811                offsets.push(**view_contact_shadows_offset);
812                entries = entries
813                    .extend_with_indices(((16, contact_shadows_buffer.0.binding().unwrap()),));
814            }
815
816            if let Some(view_oit_settings_offset) = view_oit_settings_offset {
817                layout_key |= MeshPipelineViewLayoutKey::OIT_ENABLED;
818                offsets.push(view_oit_settings_offset.offset);
819                entries = entries.extend_with_indices((
820                    (26, oit_buffers.settings.binding().unwrap()),
821                    (27, oit_buffers.nodes_capacity.binding().unwrap()),
822                    (28, oit_buffers.nodes.binding().unwrap()),
823                    (29, oit_buffers.heads.binding().unwrap()),
824                    (30, oit_buffers.atomic_counter.binding().unwrap()),
825                ));
826            }
827
828            if has_atmosphere
829                && let Some(atmosphere_textures) = atmosphere_textures
830                && let Some(atmosphere_buffer) = atmosphere_buffer
831                && let Some(atmosphere_sampler) = atmosphere_sampler.as_ref()
832                && let Some(atmosphere_buffer_binding) = atmosphere_buffer.buffer.binding()
833            {
834                layout_key |= MeshPipelineViewLayoutKey::ATMOSPHERE;
835                entries = entries.extend_with_indices((
836                    (31, &atmosphere_textures.transmittance_lut.default_view),
837                    (32, &***atmosphere_sampler),
838                    (33, atmosphere_buffer_binding),
839                ));
840            }
841
842            if truecfg!(feature = "bluenoise_texture") {
843                layout_key |= MeshPipelineViewLayoutKey::STBN;
844                let stbn_view = &images
845                    .get(&blue_noise.texture)
846                    .expect("STBN texture is added unconditionally with at least a placeholder")
847                    .texture_view;
848                entries = entries.extend_with_indices(((34, stbn_view),));
849            }
850
851            if tonemap_in_shader {
852                layout_key |= MeshPipelineViewLayoutKey::TONEMAP_IN_SHADER;
853                let lut_bindings =
854                    get_lut_bindings(&images, &tonemapping_luts, tonemapping, &fallback_image);
855                entries = entries.extend_with_indices((
856                    (TONEMAPPING_LUT_TEXTURE_BINDING_INDEX, lut_bindings.0),
857                    (TONEMAPPING_LUT_SAMPLER_BINDING_INDEX, lut_bindings.1),
858                ));
859            }
860
861            if let Some(ssao_resources) = ssao_resources {
862                layout_key |= MeshPipelineViewLayoutKey::SCREEN_SPACE_AMBIENT_OCCLUSION;
863                let ssao_view = &ssao_resources
864                    .screen_space_ambient_occlusion_texture
865                    .default_view;
866                entries = entries.extend_with_indices(((17, ssao_view),));
867            }
868
869            if has_transmission {
870                layout_key |= MeshPipelineViewLayoutKey::VIEW_TRANSMISSION_TEXTURE;
871                let transmission_view = transmission_texture
872                    .map(|transmission| &transmission.view)
873                    .unwrap_or(&fallback_image_zero.texture_view);
874                let transmission_sampler = transmission_texture
875                    .map(|transmission| &transmission.sampler)
876                    .unwrap_or(&fallback_image_zero.sampler);
877                entries = entries
878                    .extend_with_indices(((24, transmission_view), (25, transmission_sampler)));
879            }
880
881            // When using WebGL, we can't have a multisampled texture with `TEXTURE_BINDING`
882            // See https://github.com/gfx-rs/wgpu/issues/5263
883            let prepass_bindings;
884            if truecfg!(any(feature = "webgpu", not(target_arch = "wasm32"))) || msaa.samples() == 1 {
885                prepass_bindings = prepass::get_bindings(prepass_textures);
886                for (binding, index) in prepass_bindings
887                    .iter()
888                    .map(Option::as_ref)
889                    .zip([20, 21, 22, 23])
890                    .flat_map(|(b, i)| b.map(|b| (b, i)))
891                {
892                    entries = entries.extend_with_indices(((index, binding),));
893                }
894            };
895
896            // LTC LUTs for area lights
897            if truecfg!(feature = "area_light_luts") {
898                let (ltc_view, ltc_sampler) = images
899                    .get(&area_light_luts.image)
900                    .map(|img| (&img.texture_view, &img.sampler))
901                    .unwrap_or((
902                        &fallback_image.d2_array.texture_view,
903                        &fallback_image.d2_array.sampler,
904                    ));
905                entries = entries.extend_with_indices(((35, ltc_view), (36, ltc_sampler)));
906            }
907
908            // DFG LUT
909            if truecfg!(feature = "dfg_lut") {
910                let (dfg_view, dfg_sampler) = images
911                    .get(&dfg_lut.texture)
912                    .map(|img| (&img.texture_view, &img.sampler))
913                    .unwrap_or((&fallback_image.d2.texture_view, &fallback_image.d2.sampler));
914                entries = entries.extend_with_indices(((37, dfg_view), (38, dfg_sampler)));
915            }
916
917            let environment_map_bind_group_entries =
918                render_view_environment_maps.map(|render_view_environment_maps| {
919                    layout_key |= MeshPipelineViewLayoutKey::ENVIRONMENT_MAP;
920
921                    RenderViewEnvironmentMapBindGroupEntries::get(
922                        Some(render_view_environment_maps),
923                        &images,
924                        &fallback_image,
925                        &render_device,
926                        &render_adapter,
927                    )
928                });
929            match environment_map_bind_group_entries {
930                Some(RenderViewEnvironmentMapBindGroupEntries::Single {
931                    diffuse_texture_view,
932                    specular_texture_view,
933                    sampler,
934                }) => {
935                    entries_binding_array = entries_binding_array.extend_with_indices((
936                        (0, diffuse_texture_view),
937                        (1, specular_texture_view),
938                        (2, sampler),
939                    ));
940                }
941                Some(RenderViewEnvironmentMapBindGroupEntries::Multiple {
942                    ref diffuse_texture_views,
943                    ref specular_texture_views,
944                    sampler,
945                }) => {
946                    entries_binding_array = entries_binding_array.extend_with_indices((
947                        (0, diffuse_texture_views.as_slice()),
948                        (1, specular_texture_views.as_slice()),
949                        (2, sampler),
950                    ));
951                }
952                None => {}
953            }
954
955            let irradiance_volume_bind_group_entries =
956                if render_view_irradiance_volumes.is_some() && IRRADIANCE_VOLUMES_ARE_USABLE {
957                    layout_key |= MeshPipelineViewLayoutKey::IRRADIANCE_VOLUME;
958
959                    Some(RenderViewIrradianceVolumeBindGroupEntries::get(
960                        render_view_irradiance_volumes,
961                        &images,
962                        &fallback_image,
963                        &render_device,
964                        &render_adapter,
965                    ))
966                } else {
967                    None
968                };
969
970            match irradiance_volume_bind_group_entries {
971                Some(RenderViewIrradianceVolumeBindGroupEntries::Single {
972                    texture_view,
973                    sampler,
974                }) => {
975                    entries_binding_array = entries_binding_array
976                        .extend_with_indices(((3, texture_view), (4, sampler)));
977                }
978                Some(RenderViewIrradianceVolumeBindGroupEntries::Multiple {
979                    ref texture_views,
980                    sampler,
981                }) => {
982                    entries_binding_array = entries_binding_array
983                        .extend_with_indices(((3, texture_views.as_slice()), (4, sampler)));
984                }
985                None => {}
986            }
987
988            let decal_bind_group_entries = RenderViewClusteredDecalBindGroupEntries::get(
989                &render_decals,
990                &decals_buffer,
991                &images,
992                &fallback_image,
993                &render_device,
994                &render_adapter,
995            );
996
997            // Add the decal bind group entries.
998            if let Some(ref render_view_decal_bind_group_entries) = decal_bind_group_entries {
999                entries_binding_array = entries_binding_array.extend_with_indices((
1000                    // `clustered_decals`
1001                    (
1002                        5,
1003                        render_view_decal_bind_group_entries
1004                            .decals
1005                            .as_entire_binding(),
1006                    ),
1007                    // `clustered_decal_textures`
1008                    (
1009                        6,
1010                        render_view_decal_bind_group_entries
1011                            .texture_views
1012                            .as_slice(),
1013                    ),
1014                    // `clustered_decal_sampler`
1015                    (7, render_view_decal_bind_group_entries.sampler),
1016                ));
1017            }
1018
1019            let layout = mesh_pipeline.get_view_layout(layout_key);
1020            commands.entity(entity).insert((MeshViewBindGroup {
1021                main_offsets: offsets,
1022                main: render_device.create_bind_group(
1023                    "mesh_view_bind_group",
1024                    &pipeline_cache.get_bind_group_layout(&layout.main_layout),
1025                    &entries,
1026                ),
1027                binding_array: render_device.create_bind_group(
1028                    "mesh_view_bind_group_binding_array",
1029                    &pipeline_cache.get_bind_group_layout(&layout.binding_array_layout),
1030                    &entries_binding_array,
1031                ),
1032                empty: render_device.create_bind_group(
1033                    "mesh_view_bind_group_empty",
1034                    &pipeline_cache.get_bind_group_layout(&layout.empty_layout),
1035                    &[],
1036                ),
1037            },));
1038
1039            #[cfg(not(all(target_arch = "wasm32", target_feature = "atomics")))]
1040            {
1041                entries.entries.clear();
1042                entries_binding_array.entries.clear();
1043                *entries_cache = entries
1044                    .entries
1045                    .into_iter()
1046                    .map(|_| -> BindGroupEntry<'static> { ::core::panicking::panic("internal error: entered unreachable code")unreachable!() })
1047                    .collect();
1048                *entries_binding_array_cache = entries_binding_array
1049                    .entries
1050                    .into_iter()
1051                    .map(|_| -> BindGroupEntry<'static> { ::core::panicking::panic("internal error: entered unreachable code")unreachable!() })
1052                    .collect();
1053            }
1054        }
1055    }
1056}