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 {
#[inline]
pub const fn empty() -> Self {
Self(<u32 as ::bitflags::Bits>::EMPTY)
}
#[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
}
#[inline]
pub const fn bits(&self) -> u32 { self.0 }
#[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 }
}
#[inline]
pub const fn from_bits_truncate(bits: u32) -> Self {
Self(bits & Self::all().0)
}
#[inline]
pub const fn from_bits_retain(bits: u32) -> Self { Self(bits) }
#[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
}
#[inline]
pub const fn is_empty(&self) -> bool {
self.0 == <u32 as ::bitflags::Bits>::EMPTY
}
#[inline]
pub const fn is_all(&self) -> bool {
Self::all().0 | self.0 == self.0
}
#[inline]
pub const fn intersects(&self, other: Self) -> bool {
self.0 & other.0 != <u32 as ::bitflags::Bits>::EMPTY
}
#[inline]
pub const fn contains(&self, other: Self) -> bool {
self.0 & other.0 == other.0
}
#[inline]
pub fn insert(&mut self, other: Self) {
*self = Self(self.0).union(other);
}
#[inline]
pub fn remove(&mut self, other: Self) {
*self = Self(self.0).difference(other);
}
#[inline]
pub fn toggle(&mut self, other: Self) {
*self = Self(self.0).symmetric_difference(other);
}
#[inline]
pub fn set(&mut self, other: Self, value: bool) {
if value { self.insert(other); } else { self.remove(other); }
}
#[inline]
#[must_use]
pub const fn intersection(self, other: Self) -> Self {
Self(self.0 & other.0)
}
#[inline]
#[must_use]
pub const fn union(self, other: Self) -> Self {
Self(self.0 | other.0)
}
#[inline]
#[must_use]
pub const fn difference(self, other: Self) -> Self {
Self(self.0 & !other.0)
}
#[inline]
#[must_use]
pub const fn symmetric_difference(self, other: Self) -> Self {
Self(self.0 ^ other.0)
}
#[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;
#[inline]
fn bitor(self, other: InternalBitFlags) -> Self {
self.union(other)
}
}
impl ::bitflags::__private::core::ops::BitOrAssign for
InternalBitFlags {
#[inline]
fn bitor_assign(&mut self, other: Self) { self.insert(other); }
}
impl ::bitflags::__private::core::ops::BitXor for InternalBitFlags {
type Output = Self;
#[inline]
fn bitxor(self, other: Self) -> Self {
self.symmetric_difference(other)
}
}
impl ::bitflags::__private::core::ops::BitXorAssign for
InternalBitFlags {
#[inline]
fn bitxor_assign(&mut self, other: Self) { self.toggle(other); }
}
impl ::bitflags::__private::core::ops::BitAnd for InternalBitFlags {
type Output = Self;
#[inline]
fn bitand(self, other: Self) -> Self { self.intersection(other) }
}
impl ::bitflags::__private::core::ops::BitAndAssign for
InternalBitFlags {
#[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;
#[inline]
fn sub(self, other: Self) -> Self { self.difference(other) }
}
impl ::bitflags::__private::core::ops::SubAssign for InternalBitFlags
{
#[inline]
fn sub_assign(&mut self, other: Self) { self.remove(other); }
}
impl ::bitflags::__private::core::ops::Not for InternalBitFlags {
type Output = Self;
#[inline]
fn not(self) -> Self { self.complement() }
}
impl ::bitflags::__private::core::iter::Extend<InternalBitFlags> for
InternalBitFlags {
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 {
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 {
#[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()))
}
#[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 {
#[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 {
#[inline]
pub const fn empty() -> Self { Self(InternalBitFlags::empty()) }
#[inline]
pub const fn all() -> Self { Self(InternalBitFlags::all()) }
#[inline]
pub const fn bits(&self) -> u32 { self.0.bits() }
#[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,
}
}
#[inline]
pub const fn from_bits_truncate(bits: u32) -> Self {
Self(InternalBitFlags::from_bits_truncate(bits))
}
#[inline]
pub const fn from_bits_retain(bits: u32) -> Self {
Self(InternalBitFlags::from_bits_retain(bits))
}
#[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,
}
}
#[inline]
pub const fn is_empty(&self) -> bool { self.0.is_empty() }
#[inline]
pub const fn is_all(&self) -> bool { self.0.is_all() }
#[inline]
pub const fn intersects(&self, other: Self) -> bool {
self.0.intersects(other.0)
}
#[inline]
pub const fn contains(&self, other: Self) -> bool {
self.0.contains(other.0)
}
#[inline]
pub fn insert(&mut self, other: Self) { self.0.insert(other.0) }
#[inline]
pub fn remove(&mut self, other: Self) { self.0.remove(other.0) }
#[inline]
pub fn toggle(&mut self, other: Self) { self.0.toggle(other.0) }
#[inline]
pub fn set(&mut self, other: Self, value: bool) {
self.0.set(other.0, value)
}
#[inline]
#[must_use]
pub const fn intersection(self, other: Self) -> Self {
Self(self.0.intersection(other.0))
}
#[inline]
#[must_use]
pub const fn union(self, other: Self) -> Self {
Self(self.0.union(other.0))
}
#[inline]
#[must_use]
pub const fn difference(self, other: Self) -> Self {
Self(self.0.difference(other.0))
}
#[inline]
#[must_use]
pub const fn symmetric_difference(self, other: Self) -> Self {
Self(self.0.symmetric_difference(other.0))
}
#[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;
#[inline]
fn bitor(self, other: MeshPipelineViewLayoutKey) -> Self {
self.union(other)
}
}
impl ::bitflags::__private::core::ops::BitOrAssign for
MeshPipelineViewLayoutKey {
#[inline]
fn bitor_assign(&mut self, other: Self) { self.insert(other); }
}
impl ::bitflags::__private::core::ops::BitXor for
MeshPipelineViewLayoutKey {
type Output = Self;
#[inline]
fn bitxor(self, other: Self) -> Self {
self.symmetric_difference(other)
}
}
impl ::bitflags::__private::core::ops::BitXorAssign for
MeshPipelineViewLayoutKey {
#[inline]
fn bitxor_assign(&mut self, other: Self) { self.toggle(other); }
}
impl ::bitflags::__private::core::ops::BitAnd for
MeshPipelineViewLayoutKey {
type Output = Self;
#[inline]
fn bitand(self, other: Self) -> Self { self.intersection(other) }
}
impl ::bitflags::__private::core::ops::BitAndAssign for
MeshPipelineViewLayoutKey {
#[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;
#[inline]
fn sub(self, other: Self) -> Self { self.difference(other) }
}
impl ::bitflags::__private::core::ops::SubAssign for
MeshPipelineViewLayoutKey {
#[inline]
fn sub_assign(&mut self, other: Self) { self.remove(other); }
}
impl ::bitflags::__private::core::ops::Not for
MeshPipelineViewLayoutKey {
type Output = Self;
#[inline]
fn not(self) -> Self { self.complement() }
}
impl ::bitflags::__private::core::iter::Extend<MeshPipelineViewLayoutKey>
for MeshPipelineViewLayoutKey {
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 {
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 {
#[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()))
}
#[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 #[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 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
243fn 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 (
260 0,
261 uniform_buffer::<ViewUniform>(true).visibility(ShaderStages::VERTEX_FRAGMENT),
262 ),
263 (1, uniform_buffer::<GpuLights>(true)),
265 (
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 (3, sampler(SamplerBindingType::Comparison)),
285 #[cfg(feature = "experimental_pbr_pcss")]
287 (4, sampler(SamplerBindingType::Filtering)),
288 (
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 (6, sampler(SamplerBindingType::Comparison)),
302 #[cfg(feature = "experimental_pbr_pcss")]
304 (7, sampler(SamplerBindingType::Filtering)),
305 (
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 (
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 (
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 (
342 11,
343 uniform_buffer::<GlobalsUniform>(false).visibility(ShaderStages::VERTEX_FRAGMENT),
344 ),
345 (12, uniform_buffer::<LightProbesUniform>(true)),
347 (
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 (13, uniform_buffer::<GpuFog>(true)),
364 ));
365 }
366 if layout_key.contains(MeshPipelineViewLayoutKey::SCREEN_SPACE_REFLECTIONS) {
367 entries = entries.extend_with_indices((
368 (15, uniform_buffer::<ScreenSpaceReflectionsUniform>(true)),
370 ));
371 }
372 if layout_key.contains(MeshPipelineViewLayoutKey::CONTACT_SHADOWS) {
373 entries = entries.extend_with_indices((
374 (16, uniform_buffer::<ContactShadowsUniform>(true)),
376 ));
377 }
378 if layout_key.contains(MeshPipelineViewLayoutKey::SCREEN_SPACE_AMBIENT_OCCLUSION) {
379 entries = entries.extend_with_indices((
380 (
382 17,
383 texture_2d(TextureSampleType::Float { filterable: false }),
384 ),
385 ));
386 }
387
388 if layout_key.contains(MeshPipelineViewLayoutKey::TONEMAP_IN_SHADER) {
389 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 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 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 if layout_key.contains(MeshPipelineViewLayoutKey::OIT_ENABLED) {
430 if is_oit_supported {
434 entries = entries.extend_with_indices((
435 (
436 26,
437 uniform_buffer::<OrderIndependentTransparencySettings>(true),
438 ),
439 (27, uniform_buffer::<u32>(false)),
441 (28, storage_buffer_sized(false, None)),
443 (29, storage_buffer_sized(false, None)),
445 (
447 30,
448 storage_buffer_sized(false, NonZero::<u64>::new(size_of::<u32>() as u64)),
449 ),
450 ));
451 }
452 }
453
454 if layout_key.contains(MeshPipelineViewLayoutKey::ATMOSPHERE) {
456 entries = entries.extend_with_indices((
457 (
459 31,
460 texture_2d(TextureSampleType::Float { filterable: true }),
461 ),
462 (32, sampler(SamplerBindingType::Filtering)),
463 (33, storage_buffer_read_only::<GpuAtmosphere>(false)),
465 ));
466 }
467
468 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 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 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 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 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#[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#[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 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 {
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 #[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 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 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 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 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 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 (
1002 5,
1003 render_view_decal_bind_group_entries
1004 .decals
1005 .as_entire_binding(),
1006 ),
1007 (
1009 6,
1010 render_view_decal_bind_group_entries
1011 .texture_views
1012 .as_slice(),
1013 ),
1014 (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}