Path: blob/main/crates/bevy_pbr/src/render/mesh_view_bindings.rs
6600 views
use alloc::sync::Arc;1use bevy_core_pipeline::{2core_3d::ViewTransmissionTexture,3oit::{resolve::is_oit_supported, OitBuffers, OrderIndependentTransparencySettings},4prepass::ViewPrepassTextures,5tonemapping::{6get_lut_bind_group_layout_entries, get_lut_bindings, Tonemapping, TonemappingLuts,7},8};9use bevy_derive::{Deref, DerefMut};10use bevy_ecs::{11component::Component,12entity::Entity,13query::Has,14resource::Resource,15system::{Commands, Query, Res},16world::{FromWorld, World},17};18use bevy_image::BevyDefault as _;19use bevy_light::{EnvironmentMapLight, IrradianceVolume};20use bevy_math::Vec4;21use bevy_render::{22globals::{GlobalsBuffer, GlobalsUniform},23render_asset::RenderAssets,24render_resource::{binding_types::*, *},25renderer::{RenderAdapter, RenderDevice},26texture::{FallbackImage, FallbackImageMsaa, FallbackImageZero, GpuImage},27view::{28Msaa, RenderVisibilityRanges, ViewUniform, ViewUniforms,29VISIBILITY_RANGES_STORAGE_BUFFER_COUNT,30},31};32use core::{array, num::NonZero};3334use crate::{35decal::{36self,37clustered::{38DecalsBuffer, RenderClusteredDecals, RenderViewClusteredDecalBindGroupEntries,39},40},41environment_map::{self, RenderViewEnvironmentMapBindGroupEntries},42irradiance_volume::{43self, RenderViewIrradianceVolumeBindGroupEntries, IRRADIANCE_VOLUMES_ARE_USABLE,44},45prepass, EnvironmentMapUniformBuffer, FogMeta, GlobalClusterableObjectMeta,46GpuClusterableObjects, GpuFog, GpuLights, LightMeta, LightProbesBuffer, LightProbesUniform,47MeshPipeline, MeshPipelineKey, RenderViewLightProbes, ScreenSpaceAmbientOcclusionResources,48ScreenSpaceReflectionsBuffer, ScreenSpaceReflectionsUniform, ShadowSamplers,49ViewClusterBindings, ViewShadowBindings, CLUSTERED_FORWARD_STORAGE_BUFFER_COUNT,50};5152#[cfg(all(feature = "webgl", target_arch = "wasm32", not(feature = "webgpu")))]53use bevy_render::render_resource::binding_types::texture_cube;5455#[cfg(debug_assertions)]56use {crate::MESH_PIPELINE_VIEW_LAYOUT_SAFE_MAX_TEXTURES, bevy_utils::once, tracing::warn};5758#[derive(Clone)]59pub struct MeshPipelineViewLayout {60pub main_layout: BindGroupLayout,61pub binding_array_layout: BindGroupLayout,62pub empty_layout: BindGroupLayout,6364#[cfg(debug_assertions)]65pub texture_count: usize,66}6768bitflags::bitflags! {69/// A key that uniquely identifies a [`MeshPipelineViewLayout`].70///71/// Used to generate all possible layouts for the mesh pipeline in [`generate_view_layouts`],72/// so special care must be taken to not add too many flags, as the number of possible layouts73/// will grow exponentially.74#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]75#[repr(transparent)]76pub struct MeshPipelineViewLayoutKey: u32 {77const MULTISAMPLED = 1 << 0;78const DEPTH_PREPASS = 1 << 1;79const NORMAL_PREPASS = 1 << 2;80const MOTION_VECTOR_PREPASS = 1 << 3;81const DEFERRED_PREPASS = 1 << 4;82const OIT_ENABLED = 1 << 5;83}84}8586impl MeshPipelineViewLayoutKey {87// The number of possible layouts88pub const COUNT: usize = Self::all().bits() as usize + 1;8990/// Builds a unique label for each layout based on the flags91pub fn label(&self) -> String {92use MeshPipelineViewLayoutKey as Key;9394format!(95"mesh_view_layout{}{}{}{}{}{}",96if self.contains(Key::MULTISAMPLED) {97"_multisampled"98} else {99Default::default()100},101if self.contains(Key::DEPTH_PREPASS) {102"_depth"103} else {104Default::default()105},106if self.contains(Key::NORMAL_PREPASS) {107"_normal"108} else {109Default::default()110},111if self.contains(Key::MOTION_VECTOR_PREPASS) {112"_motion"113} else {114Default::default()115},116if self.contains(Key::DEFERRED_PREPASS) {117"_deferred"118} else {119Default::default()120},121if self.contains(Key::OIT_ENABLED) {122"_oit"123} else {124Default::default()125},126)127}128}129130impl From<MeshPipelineKey> for MeshPipelineViewLayoutKey {131fn from(value: MeshPipelineKey) -> Self {132let mut result = MeshPipelineViewLayoutKey::empty();133134if value.msaa_samples() > 1 {135result |= MeshPipelineViewLayoutKey::MULTISAMPLED;136}137if value.contains(MeshPipelineKey::DEPTH_PREPASS) {138result |= MeshPipelineViewLayoutKey::DEPTH_PREPASS;139}140if value.contains(MeshPipelineKey::NORMAL_PREPASS) {141result |= MeshPipelineViewLayoutKey::NORMAL_PREPASS;142}143if value.contains(MeshPipelineKey::MOTION_VECTOR_PREPASS) {144result |= MeshPipelineViewLayoutKey::MOTION_VECTOR_PREPASS;145}146if value.contains(MeshPipelineKey::DEFERRED_PREPASS) {147result |= MeshPipelineViewLayoutKey::DEFERRED_PREPASS;148}149if value.contains(MeshPipelineKey::OIT_ENABLED) {150result |= MeshPipelineViewLayoutKey::OIT_ENABLED;151}152153result154}155}156157impl From<Msaa> for MeshPipelineViewLayoutKey {158fn from(value: Msaa) -> Self {159let mut result = MeshPipelineViewLayoutKey::empty();160161if value.samples() > 1 {162result |= MeshPipelineViewLayoutKey::MULTISAMPLED;163}164165result166}167}168169impl From<Option<&ViewPrepassTextures>> for MeshPipelineViewLayoutKey {170fn from(value: Option<&ViewPrepassTextures>) -> Self {171let mut result = MeshPipelineViewLayoutKey::empty();172173if let Some(prepass_textures) = value {174if prepass_textures.depth.is_some() {175result |= MeshPipelineViewLayoutKey::DEPTH_PREPASS;176}177if prepass_textures.normal.is_some() {178result |= MeshPipelineViewLayoutKey::NORMAL_PREPASS;179}180if prepass_textures.motion_vectors.is_some() {181result |= MeshPipelineViewLayoutKey::MOTION_VECTOR_PREPASS;182}183if prepass_textures.deferred.is_some() {184result |= MeshPipelineViewLayoutKey::DEFERRED_PREPASS;185}186}187188result189}190}191192pub(crate) fn buffer_layout(193buffer_binding_type: BufferBindingType,194has_dynamic_offset: bool,195min_binding_size: Option<NonZero<u64>>,196) -> BindGroupLayoutEntryBuilder {197match buffer_binding_type {198BufferBindingType::Uniform => uniform_buffer_sized(has_dynamic_offset, min_binding_size),199BufferBindingType::Storage { read_only } => {200if read_only {201storage_buffer_read_only_sized(has_dynamic_offset, min_binding_size)202} else {203storage_buffer_sized(has_dynamic_offset, min_binding_size)204}205}206}207}208209/// Returns the appropriate bind group layout vec based on the parameters210fn layout_entries(211clustered_forward_buffer_binding_type: BufferBindingType,212visibility_ranges_buffer_binding_type: BufferBindingType,213layout_key: MeshPipelineViewLayoutKey,214render_device: &RenderDevice,215render_adapter: &RenderAdapter,216) -> [Vec<BindGroupLayoutEntry>; 2] {217// EnvironmentMapLight218let environment_map_entries =219environment_map::get_bind_group_layout_entries(render_device, render_adapter);220221let mut entries = DynamicBindGroupLayoutEntries::new_with_indices(222ShaderStages::FRAGMENT,223(224// View225(2260,227uniform_buffer::<ViewUniform>(true).visibility(ShaderStages::VERTEX_FRAGMENT),228),229// Lights230(1, uniform_buffer::<GpuLights>(true)),231// Point Shadow Texture Cube Array232(2332,234#[cfg(all(235not(target_abi = "sim"),236any(237not(feature = "webgl"),238not(target_arch = "wasm32"),239feature = "webgpu"240)241))]242texture_cube_array(TextureSampleType::Depth),243#[cfg(any(244target_abi = "sim",245all(feature = "webgl", target_arch = "wasm32", not(feature = "webgpu"))246))]247texture_cube(TextureSampleType::Depth),248),249// Point Shadow Texture Array Comparison Sampler250(3, sampler(SamplerBindingType::Comparison)),251// Point Shadow Texture Array Linear Sampler252#[cfg(feature = "experimental_pbr_pcss")]253(4, sampler(SamplerBindingType::Filtering)),254// Directional Shadow Texture Array255(2565,257#[cfg(any(258not(feature = "webgl"),259not(target_arch = "wasm32"),260feature = "webgpu"261))]262texture_2d_array(TextureSampleType::Depth),263#[cfg(all(feature = "webgl", target_arch = "wasm32", not(feature = "webgpu")))]264texture_2d(TextureSampleType::Depth),265),266// Directional Shadow Texture Array Comparison Sampler267(6, sampler(SamplerBindingType::Comparison)),268// Directional Shadow Texture Array Linear Sampler269#[cfg(feature = "experimental_pbr_pcss")]270(7, sampler(SamplerBindingType::Filtering)),271// PointLights272(2738,274buffer_layout(275clustered_forward_buffer_binding_type,276false,277Some(GpuClusterableObjects::min_size(278clustered_forward_buffer_binding_type,279)),280),281),282// ClusteredLightIndexLists283(2849,285buffer_layout(286clustered_forward_buffer_binding_type,287false,288Some(289ViewClusterBindings::min_size_clusterable_object_index_lists(290clustered_forward_buffer_binding_type,291),292),293),294),295// ClusterOffsetsAndCounts296(29710,298buffer_layout(299clustered_forward_buffer_binding_type,300false,301Some(ViewClusterBindings::min_size_cluster_offsets_and_counts(302clustered_forward_buffer_binding_type,303)),304),305),306// Globals307(30811,309uniform_buffer::<GlobalsUniform>(false).visibility(ShaderStages::VERTEX_FRAGMENT),310),311// Fog312(12, uniform_buffer::<GpuFog>(true)),313// Light probes314(13, uniform_buffer::<LightProbesUniform>(true)),315// Visibility ranges316(31714,318buffer_layout(319visibility_ranges_buffer_binding_type,320false,321Some(Vec4::min_size()),322)323.visibility(ShaderStages::VERTEX),324),325// Screen space reflection settings326(15, uniform_buffer::<ScreenSpaceReflectionsUniform>(true)),327// Screen space ambient occlusion texture328(32916,330texture_2d(TextureSampleType::Float { filterable: false }),331),332(17, environment_map_entries[3]),333),334);335336// Tonemapping337let tonemapping_lut_entries = get_lut_bind_group_layout_entries();338entries = entries.extend_with_indices((339(18, tonemapping_lut_entries[0]),340(19, tonemapping_lut_entries[1]),341));342343// Prepass344if cfg!(any(not(feature = "webgl"), not(target_arch = "wasm32")))345|| (cfg!(all(feature = "webgl", target_arch = "wasm32"))346&& !layout_key.contains(MeshPipelineViewLayoutKey::MULTISAMPLED))347{348for (entry, binding) in prepass::get_bind_group_layout_entries(layout_key)349.iter()350.zip([20, 21, 22, 23])351{352if let Some(entry) = entry {353entries = entries.extend_with_indices(((binding as u32, *entry),));354}355}356}357358// View Transmission Texture359entries = entries.extend_with_indices((360(36124,362texture_2d(TextureSampleType::Float { filterable: true }),363),364(25, sampler(SamplerBindingType::Filtering)),365));366367// OIT368if layout_key.contains(MeshPipelineViewLayoutKey::OIT_ENABLED) {369// Check if we can use OIT. This is a hack to avoid errors on webgl --370// the OIT plugin will warn the user that OIT is not supported on their371// platform, so we don't need to do it here.372if is_oit_supported(render_adapter, render_device, false) {373entries = entries.extend_with_indices((374// oit_layers375(26, storage_buffer_sized(false, None)),376// oit_layer_ids,377(27, storage_buffer_sized(false, None)),378// oit_layer_count379(38028,381uniform_buffer::<OrderIndependentTransparencySettings>(true),382),383));384}385}386387let mut binding_array_entries = DynamicBindGroupLayoutEntries::new(ShaderStages::FRAGMENT);388binding_array_entries = binding_array_entries.extend_with_indices((389(0, environment_map_entries[0]),390(1, environment_map_entries[1]),391(2, environment_map_entries[2]),392));393394// Irradiance volumes395if IRRADIANCE_VOLUMES_ARE_USABLE {396let irradiance_volume_entries =397irradiance_volume::get_bind_group_layout_entries(render_device, render_adapter);398binding_array_entries = binding_array_entries.extend_with_indices((399(3, irradiance_volume_entries[0]),400(4, irradiance_volume_entries[1]),401));402}403404// Clustered decals405if let Some(clustered_decal_entries) =406decal::clustered::get_bind_group_layout_entries(render_device, render_adapter)407{408binding_array_entries = binding_array_entries.extend_with_indices((409(5, clustered_decal_entries[0]),410(6, clustered_decal_entries[1]),411(7, clustered_decal_entries[2]),412));413}414415[entries.to_vec(), binding_array_entries.to_vec()]416}417418/// Stores the view layouts for every combination of pipeline keys.419///420/// This is wrapped in an [`Arc`] so that it can be efficiently cloned and421/// placed inside specializable pipeline types.422#[derive(Resource, Clone, Deref, DerefMut)]423pub struct MeshPipelineViewLayouts(424pub Arc<[MeshPipelineViewLayout; MeshPipelineViewLayoutKey::COUNT]>,425);426427impl FromWorld for MeshPipelineViewLayouts {428fn from_world(world: &mut World) -> Self {429// Generates all possible view layouts for the mesh pipeline, based on all combinations of430// [`MeshPipelineViewLayoutKey`] flags.431432let render_device = world.resource::<RenderDevice>();433let render_adapter = world.resource::<RenderAdapter>();434435let clustered_forward_buffer_binding_type = render_device436.get_supported_read_only_binding_type(CLUSTERED_FORWARD_STORAGE_BUFFER_COUNT);437let visibility_ranges_buffer_binding_type = render_device438.get_supported_read_only_binding_type(VISIBILITY_RANGES_STORAGE_BUFFER_COUNT);439440Self(Arc::new(array::from_fn(|i| {441let key = MeshPipelineViewLayoutKey::from_bits_truncate(i as u32);442let entries = layout_entries(443clustered_forward_buffer_binding_type,444visibility_ranges_buffer_binding_type,445key,446render_device,447render_adapter,448);449#[cfg(debug_assertions)]450let texture_count: usize = entries451.iter()452.flat_map(|e| {453e.iter()454.filter(|entry| matches!(entry.ty, BindingType::Texture { .. }))455})456.count();457458MeshPipelineViewLayout {459main_layout: render_device460.create_bind_group_layout(key.label().as_str(), &entries[0]),461binding_array_layout: render_device.create_bind_group_layout(462format!("{}_binding_array", key.label()).as_str(),463&entries[1],464),465empty_layout: render_device466.create_bind_group_layout(format!("{}_empty", key.label()).as_str(), &[]),467#[cfg(debug_assertions)]468texture_count,469}470})))471}472}473474impl MeshPipelineViewLayouts {475pub fn get_view_layout(476&self,477layout_key: MeshPipelineViewLayoutKey,478) -> &MeshPipelineViewLayout {479let index = layout_key.bits() as usize;480let layout = &self[index];481482#[cfg(debug_assertions)]483if layout.texture_count > MESH_PIPELINE_VIEW_LAYOUT_SAFE_MAX_TEXTURES {484// Issue our own warning here because Naga's error message is a bit cryptic in this situation485once!(warn!("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."));486}487488layout489}490}491492/// Generates all possible view layouts for the mesh pipeline, based on all combinations of493/// [`MeshPipelineViewLayoutKey`] flags.494pub fn generate_view_layouts(495render_device: &RenderDevice,496render_adapter: &RenderAdapter,497clustered_forward_buffer_binding_type: BufferBindingType,498visibility_ranges_buffer_binding_type: BufferBindingType,499) -> [MeshPipelineViewLayout; MeshPipelineViewLayoutKey::COUNT] {500array::from_fn(|i| {501let key = MeshPipelineViewLayoutKey::from_bits_truncate(i as u32);502let entries = layout_entries(503clustered_forward_buffer_binding_type,504visibility_ranges_buffer_binding_type,505key,506render_device,507render_adapter,508);509510#[cfg(debug_assertions)]511let texture_count: usize = entries512.iter()513.flat_map(|e| {514e.iter()515.filter(|entry| matches!(entry.ty, BindingType::Texture { .. }))516})517.count();518519MeshPipelineViewLayout {520main_layout: render_device.create_bind_group_layout(key.label().as_str(), &entries[0]),521binding_array_layout: render_device.create_bind_group_layout(522format!("{}_binding_array", key.label()).as_str(),523&entries[1],524),525empty_layout: render_device526.create_bind_group_layout(format!("{}_empty", key.label()).as_str(), &[]),527#[cfg(debug_assertions)]528texture_count,529}530})531}532533#[derive(Component)]534pub struct MeshViewBindGroup {535pub main: BindGroup,536pub binding_array: BindGroup,537pub empty: BindGroup,538}539540pub fn prepare_mesh_view_bind_groups(541mut commands: Commands,542(render_device, render_adapter): (Res<RenderDevice>, Res<RenderAdapter>),543mesh_pipeline: Res<MeshPipeline>,544shadow_samplers: Res<ShadowSamplers>,545(light_meta, global_light_meta): (Res<LightMeta>, Res<GlobalClusterableObjectMeta>),546fog_meta: Res<FogMeta>,547(view_uniforms, environment_map_uniform): (Res<ViewUniforms>, Res<EnvironmentMapUniformBuffer>),548views: Query<(549Entity,550&ViewShadowBindings,551&ViewClusterBindings,552&Msaa,553Option<&ScreenSpaceAmbientOcclusionResources>,554Option<&ViewPrepassTextures>,555Option<&ViewTransmissionTexture>,556&Tonemapping,557Option<&RenderViewLightProbes<EnvironmentMapLight>>,558Option<&RenderViewLightProbes<IrradianceVolume>>,559Has<OrderIndependentTransparencySettings>,560)>,561(images, mut fallback_images, fallback_image, fallback_image_zero): (562Res<RenderAssets<GpuImage>>,563FallbackImageMsaa,564Res<FallbackImage>,565Res<FallbackImageZero>,566),567globals_buffer: Res<GlobalsBuffer>,568tonemapping_luts: Res<TonemappingLuts>,569light_probes_buffer: Res<LightProbesBuffer>,570visibility_ranges: Res<RenderVisibilityRanges>,571ssr_buffer: Res<ScreenSpaceReflectionsBuffer>,572oit_buffers: Res<OitBuffers>,573(decals_buffer, render_decals): (Res<DecalsBuffer>, Res<RenderClusteredDecals>),574) {575if let (576Some(view_binding),577Some(light_binding),578Some(clusterable_objects_binding),579Some(globals),580Some(fog_binding),581Some(light_probes_binding),582Some(visibility_ranges_buffer),583Some(ssr_binding),584Some(environment_map_binding),585) = (586view_uniforms.uniforms.binding(),587light_meta.view_gpu_lights.binding(),588global_light_meta.gpu_clusterable_objects.binding(),589globals_buffer.buffer.binding(),590fog_meta.gpu_fogs.binding(),591light_probes_buffer.binding(),592visibility_ranges.buffer().buffer(),593ssr_buffer.binding(),594environment_map_uniform.binding(),595) {596for (597entity,598shadow_bindings,599cluster_bindings,600msaa,601ssao_resources,602prepass_textures,603transmission_texture,604tonemapping,605render_view_environment_maps,606render_view_irradiance_volumes,607has_oit,608) in &views609{610let fallback_ssao = fallback_images611.image_for_samplecount(1, TextureFormat::bevy_default())612.texture_view613.clone();614let ssao_view = ssao_resources615.map(|t| &t.screen_space_ambient_occlusion_texture.default_view)616.unwrap_or(&fallback_ssao);617618let mut layout_key = MeshPipelineViewLayoutKey::from(*msaa)619| MeshPipelineViewLayoutKey::from(prepass_textures);620if has_oit {621layout_key |= MeshPipelineViewLayoutKey::OIT_ENABLED;622}623624let layout = mesh_pipeline.get_view_layout(layout_key);625626let mut entries = DynamicBindGroupEntries::new_with_indices((627(0, view_binding.clone()),628(1, light_binding.clone()),629(2, &shadow_bindings.point_light_depth_texture_view),630(3, &shadow_samplers.point_light_comparison_sampler),631#[cfg(feature = "experimental_pbr_pcss")]632(4, &shadow_samplers.point_light_linear_sampler),633(5, &shadow_bindings.directional_light_depth_texture_view),634(6, &shadow_samplers.directional_light_comparison_sampler),635#[cfg(feature = "experimental_pbr_pcss")]636(7, &shadow_samplers.directional_light_linear_sampler),637(8, clusterable_objects_binding.clone()),638(6399,640cluster_bindings641.clusterable_object_index_lists_binding()642.unwrap(),643),644(10, cluster_bindings.offsets_and_counts_binding().unwrap()),645(11, globals.clone()),646(12, fog_binding.clone()),647(13, light_probes_binding.clone()),648(14, visibility_ranges_buffer.as_entire_binding()),649(15, ssr_binding.clone()),650(16, ssao_view),651));652653entries = entries.extend_with_indices(((17, environment_map_binding.clone()),));654655let lut_bindings =656get_lut_bindings(&images, &tonemapping_luts, tonemapping, &fallback_image);657entries = entries.extend_with_indices(((18, lut_bindings.0), (19, lut_bindings.1)));658659// When using WebGL, we can't have a depth texture with multisampling660let prepass_bindings;661if cfg!(any(not(feature = "webgl"), not(target_arch = "wasm32"))) || msaa.samples() == 1662{663prepass_bindings = prepass::get_bindings(prepass_textures);664for (binding, index) in prepass_bindings665.iter()666.map(Option::as_ref)667.zip([20, 21, 22, 23])668.flat_map(|(b, i)| b.map(|b| (b, i)))669{670entries = entries.extend_with_indices(((index, binding),));671}672};673674let transmission_view = transmission_texture675.map(|transmission| &transmission.view)676.unwrap_or(&fallback_image_zero.texture_view);677678let transmission_sampler = transmission_texture679.map(|transmission| &transmission.sampler)680.unwrap_or(&fallback_image_zero.sampler);681682entries =683entries.extend_with_indices(((24, transmission_view), (25, transmission_sampler)));684685if has_oit686&& let (687Some(oit_layers_binding),688Some(oit_layer_ids_binding),689Some(oit_settings_binding),690) = (691oit_buffers.layers.binding(),692oit_buffers.layer_ids.binding(),693oit_buffers.settings.binding(),694)695{696entries = entries.extend_with_indices((697(26, oit_layers_binding.clone()),698(27, oit_layer_ids_binding.clone()),699(28, oit_settings_binding.clone()),700));701}702703let mut entries_binding_array = DynamicBindGroupEntries::new();704705let environment_map_bind_group_entries = RenderViewEnvironmentMapBindGroupEntries::get(706render_view_environment_maps,707&images,708&fallback_image,709&render_device,710&render_adapter,711);712match environment_map_bind_group_entries {713RenderViewEnvironmentMapBindGroupEntries::Single {714diffuse_texture_view,715specular_texture_view,716sampler,717} => {718entries_binding_array = entries_binding_array.extend_with_indices((719(0, diffuse_texture_view),720(1, specular_texture_view),721(2, sampler),722));723}724RenderViewEnvironmentMapBindGroupEntries::Multiple {725ref diffuse_texture_views,726ref specular_texture_views,727sampler,728} => {729entries_binding_array = entries_binding_array.extend_with_indices((730(0, diffuse_texture_views.as_slice()),731(1, specular_texture_views.as_slice()),732(2, sampler),733));734}735}736737let irradiance_volume_bind_group_entries = if IRRADIANCE_VOLUMES_ARE_USABLE {738Some(RenderViewIrradianceVolumeBindGroupEntries::get(739render_view_irradiance_volumes,740&images,741&fallback_image,742&render_device,743&render_adapter,744))745} else {746None747};748749match irradiance_volume_bind_group_entries {750Some(RenderViewIrradianceVolumeBindGroupEntries::Single {751texture_view,752sampler,753}) => {754entries_binding_array = entries_binding_array755.extend_with_indices(((3, texture_view), (4, sampler)));756}757Some(RenderViewIrradianceVolumeBindGroupEntries::Multiple {758ref texture_views,759sampler,760}) => {761entries_binding_array = entries_binding_array762.extend_with_indices(((3, texture_views.as_slice()), (4, sampler)));763}764None => {}765}766767let decal_bind_group_entries = RenderViewClusteredDecalBindGroupEntries::get(768&render_decals,769&decals_buffer,770&images,771&fallback_image,772&render_device,773&render_adapter,774);775776// Add the decal bind group entries.777if let Some(ref render_view_decal_bind_group_entries) = decal_bind_group_entries {778entries_binding_array = entries_binding_array.extend_with_indices((779// `clustered_decals`780(7815,782render_view_decal_bind_group_entries783.decals784.as_entire_binding(),785),786// `clustered_decal_textures`787(7886,789render_view_decal_bind_group_entries790.texture_views791.as_slice(),792),793// `clustered_decal_sampler`794(7, render_view_decal_bind_group_entries.sampler),795));796}797798commands.entity(entity).insert(MeshViewBindGroup {799main: render_device.create_bind_group(800"mesh_view_bind_group",801&layout.main_layout,802&entries,803),804binding_array: render_device.create_bind_group(805"mesh_view_bind_group_binding_array",806&layout.binding_array_layout,807&entries_binding_array,808),809empty: render_device.create_bind_group(810"mesh_view_bind_group_empty",811&layout.empty_layout,812&[],813),814});815}816}817}818819820