diff --git a/crates/bevy_core_pipeline/src/tonemapping/mod.rs b/crates/bevy_core_pipeline/src/tonemapping/mod.rs index d5c452ffe8c51..b9f30dfb0bd5f 100644 --- a/crates/bevy_core_pipeline/src/tonemapping/mod.rs +++ b/crates/bevy_core_pipeline/src/tonemapping/mod.rs @@ -7,6 +7,9 @@ use bevy_render::camera::Camera; use bevy_render::extract_component::{ExtractComponent, ExtractComponentPlugin}; use bevy_render::extract_resource::{ExtractResource, ExtractResourcePlugin}; use bevy_render::render_asset::RenderAssets; +use bevy_render::render_resource::binding_types::{ + sampler, texture_2d, texture_3d, uniform_buffer, +}; use bevy_render::renderer::RenderDevice; use bevy_render::texture::{CompressedImageFormats, Image, ImageSampler, ImageType}; use bevy_render::view::{ViewTarget, ViewUniform}; @@ -248,35 +251,20 @@ impl SpecializedRenderPipeline for TonemappingPipeline { impl FromWorld for TonemappingPipeline { fn from_world(render_world: &mut World) -> Self { - let mut entries = vec![ - BindGroupLayoutEntry { - binding: 0, - visibility: ShaderStages::FRAGMENT, - ty: BindingType::Buffer { - ty: BufferBindingType::Uniform, - has_dynamic_offset: true, - min_binding_size: Some(ViewUniform::min_size()), - }, - count: None, - }, - BindGroupLayoutEntry { - binding: 1, - visibility: ShaderStages::FRAGMENT, - ty: BindingType::Texture { - sample_type: TextureSampleType::Float { filterable: false }, - view_dimension: TextureViewDimension::D2, - multisampled: false, - }, - count: None, - }, - BindGroupLayoutEntry { - binding: 2, - visibility: ShaderStages::FRAGMENT, - ty: BindingType::Sampler(SamplerBindingType::NonFiltering), - count: None, - }, - ]; - entries.extend(get_lut_bind_group_layout_entries([3, 4])); + let mut entries = DynamicBindGroupLayoutEntries::new_with_indices( + ShaderStages::FRAGMENT, + ( + (0, uniform_buffer(true, Some(ViewUniform::min_size()))), + ( + 1, + texture_2d(TextureSampleType::Float { filterable: false }), + ), + (2, sampler(SamplerBindingType::NonFiltering)), + ), + ); + let lut_layout_entries = get_lut_bind_group_layout_entries(); + entries = + entries.extend_with_indices(((3, lut_layout_entries[0]), (4, lut_layout_entries[1]))); let tonemap_texture_bind_group = render_world .resource::() @@ -342,24 +330,10 @@ pub fn get_lut_bindings<'a>( (&lut_image.texture_view, &lut_image.sampler) } -pub fn get_lut_bind_group_layout_entries(bindings: [u32; 2]) -> [BindGroupLayoutEntry; 2] { +pub fn get_lut_bind_group_layout_entries() -> [BindGroupLayoutEntryBuilder; 2] { [ - BindGroupLayoutEntry { - binding: bindings[0], - visibility: ShaderStages::FRAGMENT, - ty: BindingType::Texture { - sample_type: TextureSampleType::Float { filterable: true }, - view_dimension: TextureViewDimension::D3, - multisampled: false, - }, - count: None, - }, - BindGroupLayoutEntry { - binding: bindings[1], - visibility: ShaderStages::FRAGMENT, - ty: BindingType::Sampler(SamplerBindingType::Filtering), - count: None, - }, + texture_3d(TextureSampleType::Float { filterable: true }), + sampler(SamplerBindingType::Filtering), ] } diff --git a/crates/bevy_pbr/src/environment_map/mod.rs b/crates/bevy_pbr/src/environment_map/mod.rs index bff3599345c12..823f264a17923 100644 --- a/crates/bevy_pbr/src/environment_map/mod.rs +++ b/crates/bevy_pbr/src/environment_map/mod.rs @@ -82,12 +82,10 @@ pub fn get_bindings<'a>( (diffuse_map, specular_map, &fallback_image_cubemap.sampler) } -pub fn get_bind_group_layout_entries(bindings: [u32; 3]) -> [BindGroupLayoutEntry; 3] { +pub fn get_bind_group_layout_entries() -> [BindGroupLayoutEntryBuilder; 3] { [ - texture_cube(TextureSampleType::Float { filterable: true }) - .build(bindings[0], ShaderStages::FRAGMENT), - texture_cube(TextureSampleType::Float { filterable: true }) - .build(bindings[1], ShaderStages::FRAGMENT), - sampler(SamplerBindingType::Filtering).build(bindings[2], ShaderStages::FRAGMENT), + texture_cube(TextureSampleType::Float { filterable: true }), + texture_cube(TextureSampleType::Float { filterable: true }), + sampler(SamplerBindingType::Filtering), ] } diff --git a/crates/bevy_pbr/src/prepass/prepass_bindings.rs b/crates/bevy_pbr/src/prepass/prepass_bindings.rs index b72ddd1e318cd..c01514879226c 100644 --- a/crates/bevy_pbr/src/prepass/prepass_bindings.rs +++ b/crates/bevy_pbr/src/prepass/prepass_bindings.rs @@ -1,7 +1,11 @@ use bevy_core_pipeline::prepass::ViewPrepassTextures; use bevy_render::render_resource::{ - BindGroupLayoutEntry, BindingType, ShaderStages, TextureAspect, TextureSampleType, TextureView, - TextureViewDescriptor, TextureViewDimension, + binding_types::{ + texture_2d, texture_2d_multisampled, texture_2d_u32, texture_depth_2d, + texture_depth_2d_multisampled, + }, + BindGroupLayoutEntryBuilder, TextureAspect, TextureSampleType, TextureView, + TextureViewDescriptor, }; use bevy_utils::default; use smallvec::SmallVec; @@ -9,25 +13,19 @@ use smallvec::SmallVec; use crate::MeshPipelineViewLayoutKey; pub fn get_bind_group_layout_entries( - bindings: [u32; 4], layout_key: MeshPipelineViewLayoutKey, -) -> SmallVec<[BindGroupLayoutEntry; 4]> { - let mut result = SmallVec::<[BindGroupLayoutEntry; 4]>::new(); +) -> SmallVec<[BindGroupLayoutEntryBuilder; 4]> { + let mut result = SmallVec::<[BindGroupLayoutEntryBuilder; 4]>::new(); let multisampled = layout_key.contains(MeshPipelineViewLayoutKey::MULTISAMPLED); if layout_key.contains(MeshPipelineViewLayoutKey::DEPTH_PREPASS) { result.push( // Depth texture - BindGroupLayoutEntry { - binding: bindings[0], - visibility: ShaderStages::FRAGMENT, - ty: BindingType::Texture { - multisampled, - sample_type: TextureSampleType::Depth, - view_dimension: TextureViewDimension::D2, - }, - count: None, + if multisampled { + texture_depth_2d_multisampled() + } else { + texture_depth_2d() }, ); } @@ -35,15 +33,10 @@ pub fn get_bind_group_layout_entries( if layout_key.contains(MeshPipelineViewLayoutKey::NORMAL_PREPASS) { result.push( // Normal texture - BindGroupLayoutEntry { - binding: bindings[1], - visibility: ShaderStages::FRAGMENT, - ty: BindingType::Texture { - multisampled, - sample_type: TextureSampleType::Float { filterable: false }, - view_dimension: TextureViewDimension::D2, - }, - count: None, + if multisampled { + texture_2d_multisampled(TextureSampleType::Float { filterable: false }) + } else { + texture_2d(TextureSampleType::Float { filterable: false }) }, ); } @@ -51,15 +44,10 @@ pub fn get_bind_group_layout_entries( if layout_key.contains(MeshPipelineViewLayoutKey::MOTION_VECTOR_PREPASS) { result.push( // Motion Vectors texture - BindGroupLayoutEntry { - binding: bindings[2], - visibility: ShaderStages::FRAGMENT, - ty: BindingType::Texture { - multisampled, - sample_type: TextureSampleType::Float { filterable: false }, - view_dimension: TextureViewDimension::D2, - }, - count: None, + if multisampled { + texture_2d_multisampled(TextureSampleType::Float { filterable: false }) + } else { + texture_2d(TextureSampleType::Float { filterable: false }) }, ); } @@ -67,16 +55,7 @@ pub fn get_bind_group_layout_entries( if layout_key.contains(MeshPipelineViewLayoutKey::DEFERRED_PREPASS) { result.push( // Deferred texture - BindGroupLayoutEntry { - binding: bindings[3], - visibility: ShaderStages::FRAGMENT, - ty: BindingType::Texture { - multisampled: false, - sample_type: TextureSampleType::Uint, - view_dimension: TextureViewDimension::D2, - }, - count: None, - }, + texture_2d_u32(), ); } diff --git a/crates/bevy_pbr/src/render/mesh_view_bindings.rs b/crates/bevy_pbr/src/render/mesh_view_bindings.rs index 76dfe1a69460c..456695ec8a23a 100644 --- a/crates/bevy_pbr/src/render/mesh_view_bindings.rs +++ b/crates/bevy_pbr/src/render/mesh_view_bindings.rs @@ -1,4 +1,4 @@ -use std::array; +use std::{array, num::NonZeroU64}; use bevy_core_pipeline::{ core_3d::ViewTransmissionTexture, @@ -16,10 +16,13 @@ use bevy_render::{ globals::{GlobalsBuffer, GlobalsUniform}, render_asset::RenderAssets, render_resource::{ - binding_types::{sampler, texture_2d, uniform_buffer}, - BindGroup, BindGroupLayout, BindGroupLayoutEntry, BindingType, BufferBindingType, - DynamicBindGroupEntries, SamplerBindingType, ShaderStages, ShaderType, TextureFormat, - TextureSampleType, TextureViewDimension, + binding_types::{ + sampler, storage_buffer, storage_buffer_read_only, texture_2d, texture_2d_array, + texture_cube_array, uniform_buffer, + }, + BindGroup, BindGroupLayout, BindGroupLayoutEntry, BindGroupLayoutEntryBuilder, BindingType, + BufferBindingType, DynamicBindGroupEntries, DynamicBindGroupLayoutEntries, + SamplerBindingType, ShaderStages, ShaderType, TextureFormat, TextureSampleType, }, renderer::RenderDevice, texture::{BevyDefault, FallbackImageCubemap, FallbackImageMsaa, FallbackImageZero, Image}, @@ -145,137 +148,142 @@ impl From> for MeshPipelineViewLayoutKey { } } +fn buffer_layout( + buffer_binding_type: BufferBindingType, + has_dynamic_offset: bool, + min_binding_size: Option, +) -> BindGroupLayoutEntryBuilder { + match buffer_binding_type { + BufferBindingType::Uniform => uniform_buffer(has_dynamic_offset, min_binding_size), + BufferBindingType::Storage { read_only } => { + if read_only { + storage_buffer_read_only(has_dynamic_offset, min_binding_size) + } else { + storage_buffer(has_dynamic_offset, min_binding_size) + } + } + } +} + /// Returns the appropriate bind group layout vec based on the parameters fn layout_entries( clustered_forward_buffer_binding_type: BufferBindingType, layout_key: MeshPipelineViewLayoutKey, ) -> Vec { - let mut entries = vec![ - // View - uniform_buffer(true, Some(ViewUniform::min_size())).build(0, ShaderStages::VERTEX_FRAGMENT), - // Lights - uniform_buffer(true, Some(GpuLights::min_size())).build(1, ShaderStages::FRAGMENT), - // Point Shadow Texture Cube Array - BindGroupLayoutEntry { - binding: 2, - visibility: ShaderStages::FRAGMENT, - ty: BindingType::Texture { - multisampled: false, - sample_type: TextureSampleType::Depth, + let mut entries = DynamicBindGroupLayoutEntries::new_with_indices( + ShaderStages::FRAGMENT, + ( + // View + ( + 0, + uniform_buffer(true, Some(ViewUniform::min_size())) + .visibility(ShaderStages::VERTEX_FRAGMENT), + ), + // Lights + (1, uniform_buffer(true, Some(GpuLights::min_size()))), + // Point Shadow Texture Cube Array + ( + 2, #[cfg(any(not(feature = "webgl"), not(target_arch = "wasm32")))] - view_dimension: TextureViewDimension::CubeArray, + texture_cube_array(TextureSampleType::Depth), #[cfg(all(feature = "webgl", target_arch = "wasm32"))] - view_dimension: TextureViewDimension::Cube, - }, - count: None, - }, - // Point Shadow Texture Array Sampler - sampler(SamplerBindingType::Comparison).build(3, ShaderStages::FRAGMENT), - // Directional Shadow Texture Array - BindGroupLayoutEntry { - binding: 4, - visibility: ShaderStages::FRAGMENT, - ty: BindingType::Texture { - multisampled: false, - sample_type: TextureSampleType::Depth, + texture_cube(TextureSampleType::Depth), + ), + // Point Shadow Texture Array Sampler + (3, sampler(SamplerBindingType::Comparison)), + // Directional Shadow Texture Array + ( + 4, #[cfg(any(not(feature = "webgl"), not(target_arch = "wasm32")))] - view_dimension: TextureViewDimension::D2Array, + texture_2d_array(TextureSampleType::Depth), #[cfg(all(feature = "webgl", target_arch = "wasm32"))] - view_dimension: TextureViewDimension::D2, - }, - count: None, - }, - // Directional Shadow Texture Array Sampler - sampler(SamplerBindingType::Comparison).build(5, ShaderStages::FRAGMENT), - // PointLights - BindGroupLayoutEntry { - binding: 6, - visibility: ShaderStages::FRAGMENT, - ty: BindingType::Buffer { - ty: clustered_forward_buffer_binding_type, - has_dynamic_offset: false, - min_binding_size: Some(GpuPointLights::min_size( + texture_2d(TextureSampleType::Depth), + ), + // Directional Shadow Texture Array Sampler + (5, sampler(SamplerBindingType::Comparison)), + // PointLights + ( + 6, + buffer_layout( clustered_forward_buffer_binding_type, - )), - }, - count: None, - }, - // ClusteredLightIndexLists - BindGroupLayoutEntry { - binding: 7, - visibility: ShaderStages::FRAGMENT, - ty: BindingType::Buffer { - ty: clustered_forward_buffer_binding_type, - has_dynamic_offset: false, - min_binding_size: Some(ViewClusterBindings::min_size_cluster_light_index_lists( + false, + Some(GpuPointLights::min_size( + clustered_forward_buffer_binding_type, + )), + ), + ), + // ClusteredLightIndexLists + ( + 7, + buffer_layout( clustered_forward_buffer_binding_type, - )), - }, - count: None, - }, - // ClusterOffsetsAndCounts - BindGroupLayoutEntry { - binding: 8, - visibility: ShaderStages::FRAGMENT, - ty: BindingType::Buffer { - ty: clustered_forward_buffer_binding_type, - has_dynamic_offset: false, - min_binding_size: Some(ViewClusterBindings::min_size_cluster_offsets_and_counts( + false, + Some(ViewClusterBindings::min_size_cluster_light_index_lists( + clustered_forward_buffer_binding_type, + )), + ), + ), + // ClusterOffsetsAndCounts + ( + 8, + buffer_layout( clustered_forward_buffer_binding_type, - )), - }, - count: None, - }, - // Globals - uniform_buffer(false, Some(GlobalsUniform::min_size())) - .build(9, ShaderStages::VERTEX_FRAGMENT), - // Fog - uniform_buffer(true, Some(GpuFog::min_size())).build(10, ShaderStages::FRAGMENT), - // Screen space ambient occlusion texture - texture_2d(TextureSampleType::Float { filterable: false }) - .build(11, ShaderStages::FRAGMENT), - ]; + false, + Some(ViewClusterBindings::min_size_cluster_offsets_and_counts( + clustered_forward_buffer_binding_type, + )), + ), + ), + // Globals + (9, uniform_buffer(false, Some(GlobalsUniform::min_size()))), + // Fog + (10, uniform_buffer(true, Some(GpuFog::min_size()))), + // Screen space ambient occlusion texture + ( + 11, + texture_2d(TextureSampleType::Float { filterable: false }), + ), + ), + ); // EnvironmentMapLight - let environment_map_entries = environment_map::get_bind_group_layout_entries([12, 13, 14]); - entries.extend_from_slice(&environment_map_entries); + let environment_map_entries = environment_map::get_bind_group_layout_entries(); + entries = entries.extend_with_indices(( + (12, environment_map_entries[0]), + (13, environment_map_entries[1]), + (14, environment_map_entries[2]), + )); // Tonemapping - let tonemapping_lut_entries = get_lut_bind_group_layout_entries([15, 16]); - entries.extend_from_slice(&tonemapping_lut_entries); + let tonemapping_lut_entries = get_lut_bind_group_layout_entries(); + entries = entries.extend_with_indices(( + (15, tonemapping_lut_entries[0]), + (16, tonemapping_lut_entries[1]), + )); // Prepass if cfg!(any(not(feature = "webgl"), not(target_arch = "wasm32"))) || (cfg!(all(feature = "webgl", target_arch = "wasm32")) && !layout_key.contains(MeshPipelineViewLayoutKey::MULTISAMPLED)) { - entries.extend_from_slice(&prepass::get_bind_group_layout_entries( - [17, 18, 19, 20], - layout_key, - )); + for (entry, binding) in prepass::get_bind_group_layout_entries(layout_key) + .iter() + .zip([17, 18, 19, 20]) + { + entries = entries.extend_with_indices(((binding as u32, *entry),)); + } } // View Transmission Texture - entries.extend_from_slice(&[ - BindGroupLayoutEntry { - binding: 21, - visibility: ShaderStages::FRAGMENT, - ty: BindingType::Texture { - sample_type: TextureSampleType::Float { filterable: true }, - multisampled: false, - view_dimension: TextureViewDimension::D2, - }, - count: None, - }, - BindGroupLayoutEntry { - binding: 22, - visibility: ShaderStages::FRAGMENT, - ty: BindingType::Sampler(SamplerBindingType::Filtering), - count: None, - }, - ]); - - entries + entries = entries.extend_with_indices(( + ( + 21, + texture_2d(TextureSampleType::Float { filterable: true }), + ), + (22, sampler(SamplerBindingType::Filtering)), + )); + + (&entries).to_vec() } /// Generates all possible view layouts for the mesh pipeline, based on all combinations of diff --git a/crates/bevy_render/src/render_resource/bind_group_layout_entries.rs b/crates/bevy_render/src/render_resource/bind_group_layout_entries.rs index 819da3b8d601a..528234500ef4b 100644 --- a/crates/bevy_render/src/render_resource/bind_group_layout_entries.rs +++ b/crates/bevy_render/src/render_resource/bind_group_layout_entries.rs @@ -276,6 +276,12 @@ macro_rules! impl_to_indexed_binding_type_slice { } all_tuples_with_size!(impl_to_indexed_binding_type_slice, 1, 32, T, n, s); +impl IntoBindGroupLayoutEntryBuilderArray for [BindGroupLayoutEntry; N] { + fn into_array(self) -> [BindGroupLayoutEntryBuilder; N] { + self.map(|x| x.into_bind_group_layout_entry_builder()) + } +} + pub struct DynamicBindGroupLayoutEntries { default_visibility: ShaderStages, entries: Vec,