diff --git a/crates/bevy_core_pipeline/src/blit/mod.rs b/crates/bevy_core_pipeline/src/blit/mod.rs index b6698838f4a54..9a9777a43f212 100644 --- a/crates/bevy_core_pipeline/src/blit/mod.rs +++ b/crates/bevy_core_pipeline/src/blit/mod.rs @@ -1,7 +1,14 @@ use bevy_app::{App, Plugin}; use bevy_asset::{load_internal_asset, Handle}; use bevy_ecs::prelude::*; -use bevy_render::{render_resource::*, renderer::RenderDevice, RenderApp}; +use bevy_render::{ + render_resource::{ + binding_types::{sampler, texture_2d}, + *, + }, + renderer::RenderDevice, + RenderApp, +}; use crate::fullscreen_vertex_shader::fullscreen_shader_vertex_state; @@ -36,28 +43,16 @@ impl FromWorld for BlitPipeline { fn from_world(render_world: &mut World) -> Self { let render_device = render_world.resource::(); - let texture_bind_group = - render_device.create_bind_group_layout(&BindGroupLayoutDescriptor { - label: Some("blit_bind_group_layout"), - entries: &[ - BindGroupLayoutEntry { - binding: 0, - visibility: ShaderStages::FRAGMENT, - ty: BindingType::Texture { - sample_type: TextureSampleType::Float { filterable: false }, - view_dimension: TextureViewDimension::D2, - multisampled: false, - }, - count: None, - }, - BindGroupLayoutEntry { - binding: 1, - visibility: ShaderStages::FRAGMENT, - ty: BindingType::Sampler(SamplerBindingType::NonFiltering), - count: None, - }, - ], - }); + let texture_bind_group = render_device.create_bind_group_layout( + "blit_bind_group_layout", + &BindGroupLayoutEntries::sequential( + ShaderStages::FRAGMENT, + ( + texture_2d(TextureSampleType::Float { filterable: false }), + sampler(SamplerBindingType::NonFiltering), + ), + ), + ); let sampler = render_device.create_sampler(&SamplerDescriptor::default()); diff --git a/crates/bevy_core_pipeline/src/bloom/downsampling_pipeline.rs b/crates/bevy_core_pipeline/src/bloom/downsampling_pipeline.rs index 747f4ee4c87d4..736ebeaf24288 100644 --- a/crates/bevy_core_pipeline/src/bloom/downsampling_pipeline.rs +++ b/crates/bevy_core_pipeline/src/bloom/downsampling_pipeline.rs @@ -6,7 +6,13 @@ use bevy_ecs::{ world::{FromWorld, World}, }; use bevy_math::Vec4; -use bevy_render::{render_resource::*, renderer::RenderDevice}; +use bevy_render::{ + render_resource::{ + binding_types::{sampler, texture_2d, uniform_buffer}, + *, + }, + renderer::RenderDevice, +}; #[derive(Component)] pub struct BloomDownsamplingPipelineIds { @@ -41,44 +47,21 @@ impl FromWorld for BloomDownsamplingPipeline { fn from_world(world: &mut World) -> Self { let render_device = world.resource::(); - // Input texture binding - let texture = BindGroupLayoutEntry { - binding: 0, - ty: BindingType::Texture { - sample_type: TextureSampleType::Float { filterable: true }, - view_dimension: TextureViewDimension::D2, - multisampled: false, - }, - visibility: ShaderStages::FRAGMENT, - count: None, - }; - - // Sampler binding - let sampler = BindGroupLayoutEntry { - binding: 1, - ty: BindingType::Sampler(SamplerBindingType::Filtering), - visibility: ShaderStages::FRAGMENT, - count: None, - }; - - // Downsampling settings binding - let settings = BindGroupLayoutEntry { - binding: 2, - ty: BindingType::Buffer { - ty: BufferBindingType::Uniform, - has_dynamic_offset: true, - min_binding_size: Some(BloomUniforms::min_size()), - }, - visibility: ShaderStages::FRAGMENT, - count: None, - }; - // Bind group layout - let bind_group_layout = - render_device.create_bind_group_layout(&BindGroupLayoutDescriptor { - label: Some("bloom_downsampling_bind_group_layout_with_settings"), - entries: &[texture, sampler, settings], - }); + let bind_group_layout = render_device.create_bind_group_layout( + "bloom_downsampling_bind_group_layout_with_settings", + &BindGroupLayoutEntries::sequential( + ShaderStages::FRAGMENT, + ( + // Input texture binding + texture_2d(TextureSampleType::Float { filterable: true }), + // Sampler binding + sampler(SamplerBindingType::Filtering), + // Downsampling settings binding + uniform_buffer::(true), + ), + ), + ); // Sampler let sampler = render_device.create_sampler(&SamplerDescriptor { diff --git a/crates/bevy_core_pipeline/src/bloom/upsampling_pipeline.rs b/crates/bevy_core_pipeline/src/bloom/upsampling_pipeline.rs index 996ccce08343a..161c251e36d4d 100644 --- a/crates/bevy_core_pipeline/src/bloom/upsampling_pipeline.rs +++ b/crates/bevy_core_pipeline/src/bloom/upsampling_pipeline.rs @@ -8,7 +8,14 @@ use bevy_ecs::{ system::{Commands, Query, Res, ResMut, Resource}, world::{FromWorld, World}, }; -use bevy_render::{render_resource::*, renderer::RenderDevice, view::ViewTarget}; +use bevy_render::{ + render_resource::{ + binding_types::{sampler, texture_2d, uniform_buffer}, + *, + }, + renderer::RenderDevice, + view::ViewTarget, +}; #[derive(Component)] pub struct UpsamplingPipelineIds { @@ -31,41 +38,20 @@ impl FromWorld for BloomUpsamplingPipeline { fn from_world(world: &mut World) -> Self { let render_device = world.resource::(); - let bind_group_layout = - render_device.create_bind_group_layout(&BindGroupLayoutDescriptor { - label: Some("bloom_upsampling_bind_group_layout"), - entries: &[ + let bind_group_layout = render_device.create_bind_group_layout( + "bloom_upsampling_bind_group_layout", + &BindGroupLayoutEntries::sequential( + ShaderStages::FRAGMENT, + ( // Input texture - BindGroupLayoutEntry { - binding: 0, - ty: BindingType::Texture { - sample_type: TextureSampleType::Float { filterable: true }, - view_dimension: TextureViewDimension::D2, - multisampled: false, - }, - visibility: ShaderStages::FRAGMENT, - count: None, - }, + texture_2d(TextureSampleType::Float { filterable: true }), // Sampler - BindGroupLayoutEntry { - binding: 1, - ty: BindingType::Sampler(SamplerBindingType::Filtering), - visibility: ShaderStages::FRAGMENT, - count: None, - }, + sampler(SamplerBindingType::Filtering), // BloomUniforms - BindGroupLayoutEntry { - binding: 2, - ty: BindingType::Buffer { - ty: BufferBindingType::Uniform, - has_dynamic_offset: true, - min_binding_size: Some(BloomUniforms::min_size()), - }, - visibility: ShaderStages::FRAGMENT, - count: None, - }, - ], - }); + uniform_buffer::(true), + ), + ), + ); BloomUpsamplingPipeline { bind_group_layout } } diff --git a/crates/bevy_core_pipeline/src/contrast_adaptive_sharpening/mod.rs b/crates/bevy_core_pipeline/src/contrast_adaptive_sharpening/mod.rs index 89879938e8a8b..7efa3f5028cc7 100644 --- a/crates/bevy_core_pipeline/src/contrast_adaptive_sharpening/mod.rs +++ b/crates/bevy_core_pipeline/src/contrast_adaptive_sharpening/mod.rs @@ -11,7 +11,10 @@ use bevy_render::{ extract_component::{ExtractComponent, ExtractComponentPlugin, UniformComponentPlugin}, prelude::Camera, render_graph::RenderGraphApp, - render_resource::*, + render_resource::{ + binding_types::{sampler, texture_2d, uniform_buffer}, + *, + }, renderer::RenderDevice, texture::BevyDefault, view::{ExtractedView, ViewTarget}, @@ -169,39 +172,18 @@ pub struct CASPipeline { impl FromWorld for CASPipeline { fn from_world(render_world: &mut World) -> Self { let render_device = render_world.resource::(); - let texture_bind_group = - render_device.create_bind_group_layout(&BindGroupLayoutDescriptor { - label: Some("sharpening_texture_bind_group_layout"), - entries: &[ - BindGroupLayoutEntry { - binding: 0, - visibility: ShaderStages::FRAGMENT, - ty: BindingType::Texture { - sample_type: TextureSampleType::Float { filterable: true }, - view_dimension: TextureViewDimension::D2, - multisampled: false, - }, - count: None, - }, - BindGroupLayoutEntry { - binding: 1, - visibility: ShaderStages::FRAGMENT, - ty: BindingType::Sampler(SamplerBindingType::Filtering), - count: None, - }, + let texture_bind_group = render_device.create_bind_group_layout( + "sharpening_texture_bind_group_layout", + &BindGroupLayoutEntries::sequential( + ShaderStages::FRAGMENT, + ( + texture_2d(TextureSampleType::Float { filterable: true }), + sampler(SamplerBindingType::Filtering), // CAS Settings - BindGroupLayoutEntry { - binding: 2, - ty: BindingType::Buffer { - ty: BufferBindingType::Uniform, - has_dynamic_offset: true, - min_binding_size: Some(CASUniform::min_size()), - }, - visibility: ShaderStages::FRAGMENT, - count: None, - }, - ], - }); + uniform_buffer::(true), + ), + ), + ); let sampler = render_device.create_sampler(&SamplerDescriptor::default()); diff --git a/crates/bevy_core_pipeline/src/deferred/copy_lighting_id.rs b/crates/bevy_core_pipeline/src/deferred/copy_lighting_id.rs index c60306286900a..988d529d09c44 100644 --- a/crates/bevy_core_pipeline/src/deferred/copy_lighting_id.rs +++ b/crates/bevy_core_pipeline/src/deferred/copy_lighting_id.rs @@ -8,7 +8,7 @@ use bevy_ecs::prelude::*; use bevy_math::UVec2; use bevy_render::{ camera::ExtractedCamera, - render_resource::*, + render_resource::{binding_types::texture_2d, *}, renderer::RenderDevice, texture::{CachedTexture, TextureCache}, view::ViewTarget, @@ -128,19 +128,13 @@ impl FromWorld for CopyDeferredLightingIdPipeline { fn from_world(world: &mut World) -> Self { let render_device = world.resource::(); - let layout = render_device.create_bind_group_layout(&BindGroupLayoutDescriptor { - label: Some("copy_deferred_lighting_id_bind_group_layout"), - entries: &[BindGroupLayoutEntry { - binding: 0, - visibility: ShaderStages::FRAGMENT, - ty: BindingType::Texture { - sample_type: TextureSampleType::Uint, - view_dimension: TextureViewDimension::D2, - multisampled: false, - }, - count: None, - }], - }); + let layout = render_device.create_bind_group_layout( + "copy_deferred_lighting_id_bind_group_layout", + &BindGroupLayoutEntries::single( + ShaderStages::FRAGMENT, + texture_2d(TextureSampleType::Uint), + ), + ); let pipeline_id = world diff --git a/crates/bevy_core_pipeline/src/fxaa/mod.rs b/crates/bevy_core_pipeline/src/fxaa/mod.rs index df37eaa1a8e76..a0ccc00fbad1c 100644 --- a/crates/bevy_core_pipeline/src/fxaa/mod.rs +++ b/crates/bevy_core_pipeline/src/fxaa/mod.rs @@ -13,7 +13,10 @@ use bevy_render::{ prelude::Camera, render_graph::RenderGraphApp, render_graph::ViewNodeRunner, - render_resource::*, + render_resource::{ + binding_types::{sampler, texture_2d}, + *, + }, renderer::RenderDevice, texture::BevyDefault, view::{ExtractedView, ViewTarget}, @@ -131,27 +134,16 @@ impl FromWorld for FxaaPipeline { fn from_world(render_world: &mut World) -> Self { let texture_bind_group = render_world .resource::() - .create_bind_group_layout(&BindGroupLayoutDescriptor { - label: Some("fxaa_texture_bind_group_layout"), - entries: &[ - BindGroupLayoutEntry { - binding: 0, - visibility: ShaderStages::FRAGMENT, - ty: BindingType::Texture { - sample_type: TextureSampleType::Float { filterable: true }, - view_dimension: TextureViewDimension::D2, - multisampled: false, - }, - count: None, - }, - BindGroupLayoutEntry { - binding: 1, - visibility: ShaderStages::FRAGMENT, - ty: BindingType::Sampler(SamplerBindingType::Filtering), - count: None, - }, - ], - }); + .create_bind_group_layout( + "fxaa_texture_bind_group_layout", + &BindGroupLayoutEntries::sequential( + ShaderStages::FRAGMENT, + ( + texture_2d(TextureSampleType::Float { filterable: true }), + sampler(SamplerBindingType::Filtering), + ), + ), + ); FxaaPipeline { texture_bind_group } } diff --git a/crates/bevy_core_pipeline/src/skybox/mod.rs b/crates/bevy_core_pipeline/src/skybox/mod.rs index 11caa03afd8aa..cfb7d788e0ced 100644 --- a/crates/bevy_core_pipeline/src/skybox/mod.rs +++ b/crates/bevy_core_pipeline/src/skybox/mod.rs @@ -10,13 +10,13 @@ use bevy_render::{ extract_component::{ExtractComponent, ExtractComponentPlugin}, render_asset::RenderAssets, render_resource::{ - BindGroup, BindGroupEntries, BindGroupLayout, BindGroupLayoutDescriptor, - BindGroupLayoutEntry, BindingType, BufferBindingType, CachedRenderPipelineId, - ColorTargetState, ColorWrites, CompareFunction, DepthBiasState, DepthStencilState, - FragmentState, MultisampleState, PipelineCache, PrimitiveState, RenderPipelineDescriptor, - SamplerBindingType, Shader, ShaderStages, ShaderType, SpecializedRenderPipeline, - SpecializedRenderPipelines, StencilFaceState, StencilState, TextureFormat, - TextureSampleType, TextureViewDimension, VertexState, + binding_types::{sampler, texture_cube, uniform_buffer}, + BindGroup, BindGroupEntries, BindGroupLayout, BindGroupLayoutEntries, + CachedRenderPipelineId, ColorTargetState, ColorWrites, CompareFunction, DepthBiasState, + DepthStencilState, FragmentState, MultisampleState, PipelineCache, PrimitiveState, + RenderPipelineDescriptor, SamplerBindingType, Shader, ShaderStages, + SpecializedRenderPipeline, SpecializedRenderPipelines, StencilFaceState, StencilState, + TextureFormat, TextureSampleType, VertexState, }, renderer::RenderDevice, texture::{BevyDefault, Image}, @@ -80,41 +80,19 @@ struct SkyboxPipeline { impl SkyboxPipeline { fn new(render_device: &RenderDevice) -> Self { - let bind_group_layout_descriptor = BindGroupLayoutDescriptor { - label: Some("skybox_bind_group_layout"), - entries: &[ - BindGroupLayoutEntry { - binding: 0, - visibility: ShaderStages::FRAGMENT, - ty: BindingType::Texture { - sample_type: TextureSampleType::Float { filterable: true }, - view_dimension: TextureViewDimension::Cube, - multisampled: false, - }, - count: None, - }, - BindGroupLayoutEntry { - binding: 1, - visibility: ShaderStages::FRAGMENT, - ty: BindingType::Sampler(SamplerBindingType::Filtering), - count: None, - }, - BindGroupLayoutEntry { - binding: 2, - visibility: ShaderStages::VERTEX_FRAGMENT, - ty: BindingType::Buffer { - ty: BufferBindingType::Uniform, - has_dynamic_offset: true, - min_binding_size: Some(ViewUniform::min_size()), - }, - count: None, - }, - ], - }; - Self { - bind_group_layout: render_device - .create_bind_group_layout(&bind_group_layout_descriptor), + bind_group_layout: render_device.create_bind_group_layout( + "skybox_bind_group_layout", + &BindGroupLayoutEntries::sequential( + ShaderStages::FRAGMENT, + ( + texture_cube(TextureSampleType::Float { filterable: true }), + sampler(SamplerBindingType::Filtering), + uniform_buffer::(true) + .visibility(ShaderStages::VERTEX_FRAGMENT), + ), + ), + ), } } } diff --git a/crates/bevy_core_pipeline/src/taa/mod.rs b/crates/bevy_core_pipeline/src/taa/mod.rs index de4069c9abe7d..dd0ecfdbdd63b 100644 --- a/crates/bevy_core_pipeline/src/taa/mod.rs +++ b/crates/bevy_core_pipeline/src/taa/mod.rs @@ -21,13 +21,13 @@ use bevy_render::{ prelude::{Camera, Projection}, render_graph::{NodeRunError, RenderGraphApp, RenderGraphContext, ViewNode, ViewNodeRunner}, render_resource::{ - BindGroupEntries, BindGroupLayout, BindGroupLayoutDescriptor, BindGroupLayoutEntry, - BindingType, CachedRenderPipelineId, ColorTargetState, ColorWrites, Extent3d, FilterMode, - FragmentState, MultisampleState, Operations, PipelineCache, PrimitiveState, - RenderPassColorAttachment, RenderPassDescriptor, RenderPipelineDescriptor, Sampler, - SamplerBindingType, SamplerDescriptor, Shader, ShaderStages, SpecializedRenderPipeline, - SpecializedRenderPipelines, TextureDescriptor, TextureDimension, TextureFormat, - TextureSampleType, TextureUsages, TextureViewDimension, + binding_types::{sampler, texture_2d, texture_depth_2d}, + BindGroupEntries, BindGroupLayout, BindGroupLayoutEntries, CachedRenderPipelineId, + ColorTargetState, ColorWrites, Extent3d, FilterMode, FragmentState, MultisampleState, + Operations, PipelineCache, PrimitiveState, RenderPassColorAttachment, RenderPassDescriptor, + RenderPipelineDescriptor, Sampler, SamplerBindingType, SamplerDescriptor, Shader, + ShaderStages, SpecializedRenderPipeline, SpecializedRenderPipelines, TextureDescriptor, + TextureDimension, TextureFormat, TextureSampleType, TextureUsages, }, renderer::{RenderContext, RenderDevice}, texture::{BevyDefault, CachedTexture, TextureCache}, @@ -266,70 +266,26 @@ impl FromWorld for TaaPipeline { ..SamplerDescriptor::default() }); - let taa_bind_group_layout = - render_device.create_bind_group_layout(&BindGroupLayoutDescriptor { - label: Some("taa_bind_group_layout"), - entries: &[ + let taa_bind_group_layout = render_device.create_bind_group_layout( + "taa_bind_group_layout", + &BindGroupLayoutEntries::sequential( + ShaderStages::FRAGMENT, + ( // View target (read) - BindGroupLayoutEntry { - binding: 0, - visibility: ShaderStages::FRAGMENT, - ty: BindingType::Texture { - sample_type: TextureSampleType::Float { filterable: true }, - view_dimension: TextureViewDimension::D2, - multisampled: false, - }, - count: None, - }, + texture_2d(TextureSampleType::Float { filterable: true }), // TAA History (read) - BindGroupLayoutEntry { - binding: 1, - visibility: ShaderStages::FRAGMENT, - ty: BindingType::Texture { - sample_type: TextureSampleType::Float { filterable: true }, - view_dimension: TextureViewDimension::D2, - multisampled: false, - }, - count: None, - }, + texture_2d(TextureSampleType::Float { filterable: true }), // Motion Vectors - BindGroupLayoutEntry { - binding: 2, - visibility: ShaderStages::FRAGMENT, - ty: BindingType::Texture { - sample_type: TextureSampleType::Float { filterable: true }, - view_dimension: TextureViewDimension::D2, - multisampled: false, - }, - count: None, - }, + texture_2d(TextureSampleType::Float { filterable: true }), // Depth - BindGroupLayoutEntry { - binding: 3, - visibility: ShaderStages::FRAGMENT, - ty: BindingType::Texture { - sample_type: TextureSampleType::Depth, - view_dimension: TextureViewDimension::D2, - multisampled: false, - }, - count: None, - }, + texture_depth_2d(), // Nearest sampler - BindGroupLayoutEntry { - binding: 4, - visibility: ShaderStages::FRAGMENT, - ty: BindingType::Sampler(SamplerBindingType::NonFiltering), - count: None, - }, + sampler(SamplerBindingType::NonFiltering), // Linear sampler - BindGroupLayoutEntry { - binding: 5, - visibility: ShaderStages::FRAGMENT, - ty: BindingType::Sampler(SamplerBindingType::Filtering), - count: None, - }, - ], - }); + sampler(SamplerBindingType::Filtering), + ), + ), + ); TaaPipeline { taa_bind_group_layout, diff --git a/crates/bevy_core_pipeline/src/tonemapping/mod.rs b/crates/bevy_core_pipeline/src/tonemapping/mod.rs index bb4dec7f3bc49..87167fd8db585 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,42 +251,24 @@ 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)), + ( + 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::() - .create_bind_group_layout(&BindGroupLayoutDescriptor { - label: Some("tonemapping_hdr_texture_bind_group_layout"), - entries: &entries, - }); + .create_bind_group_layout("tonemapping_hdr_texture_bind_group_layout", &entries); TonemappingPipeline { texture_bind_group: tonemap_texture_bind_group, @@ -345,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_gizmos/src/lib.rs b/crates/bevy_gizmos/src/lib.rs index d0df228449116..2b8a3df7d2e0a 100644 --- a/crates/bevy_gizmos/src/lib.rs +++ b/crates/bevy_gizmos/src/lib.rs @@ -54,10 +54,9 @@ use bevy_render::{ render_asset::{PrepareAssetError, RenderAsset, RenderAssetPlugin, RenderAssets}, render_phase::{PhaseItem, RenderCommand, RenderCommandResult, TrackedRenderPass}, render_resource::{ - BindGroup, BindGroupEntries, BindGroupLayout, BindGroupLayoutDescriptor, - BindGroupLayoutEntry, BindingType, Buffer, BufferBindingType, BufferInitDescriptor, - BufferUsages, Shader, ShaderStages, ShaderType, VertexAttribute, VertexBufferLayout, - VertexFormat, VertexStepMode, + binding_types::uniform_buffer, BindGroup, BindGroupEntries, BindGroupLayout, + BindGroupLayoutEntries, Buffer, BufferInitDescriptor, BufferUsages, Shader, ShaderStages, + ShaderType, VertexAttribute, VertexBufferLayout, VertexFormat, VertexStepMode, }, renderer::RenderDevice, view::RenderLayers, @@ -120,19 +119,13 @@ impl Plugin for GizmoPlugin { }; let render_device = render_app.world.resource::(); - let layout = render_device.create_bind_group_layout(&BindGroupLayoutDescriptor { - entries: &[BindGroupLayoutEntry { - binding: 0, - visibility: ShaderStages::VERTEX, - ty: BindingType::Buffer { - ty: BufferBindingType::Uniform, - has_dynamic_offset: true, - min_binding_size: Some(LineGizmoUniform::min_size()), - }, - count: None, - }], - label: Some("LineGizmoUniform layout"), - }); + let layout = render_device.create_bind_group_layout( + "LineGizmoUniform layout", + &BindGroupLayoutEntries::single( + ShaderStages::VERTEX, + uniform_buffer::(true), + ), + ); render_app.insert_resource(LineGizmoUniformBindgroupLayout { layout }); } diff --git a/crates/bevy_pbr/src/deferred/mod.rs b/crates/bevy_pbr/src/deferred/mod.rs index f679f638d42ac..5de8f327f8d72 100644 --- a/crates/bevy_pbr/src/deferred/mod.rs +++ b/crates/bevy_pbr/src/deferred/mod.rs @@ -18,7 +18,9 @@ use bevy_render::{ }, render_asset::RenderAssets, render_graph::{NodeRunError, RenderGraphContext, ViewNode, ViewNodeRunner}, - render_resource::{self, Operations, PipelineCache, RenderPassDescriptor}, + render_resource::{ + binding_types::uniform_buffer, Operations, PipelineCache, RenderPassDescriptor, + }, renderer::{RenderContext, RenderDevice}, texture::Image, view::{ViewTarget, ViewUniformOffset}, @@ -376,19 +378,13 @@ impl SpecializedRenderPipeline for DeferredLightingLayout { impl FromWorld for DeferredLightingLayout { fn from_world(world: &mut World) -> Self { let render_device = world.resource::(); - let layout = render_device.create_bind_group_layout(&BindGroupLayoutDescriptor { - label: Some("deferred_lighting_layout"), - entries: &[BindGroupLayoutEntry { - binding: 0, - visibility: ShaderStages::VERTEX_FRAGMENT, - ty: BindingType::Buffer { - ty: render_resource::BufferBindingType::Uniform, - has_dynamic_offset: false, - min_binding_size: Some(PbrDeferredLightingDepthId::min_size()), - }, - count: None, - }], - }); + let layout = render_device.create_bind_group_layout( + "deferred_lighting_layout", + &BindGroupLayoutEntries::single( + ShaderStages::VERTEX_FRAGMENT, + uniform_buffer::(false), + ), + ); Self { mesh_pipeline: world.resource::().clone(), bind_group_layout_1: layout, diff --git a/crates/bevy_pbr/src/environment_map/mod.rs b/crates/bevy_pbr/src/environment_map/mod.rs index 9e8a1d517585f..823f264a17923 100644 --- a/crates/bevy_pbr/src/environment_map/mod.rs +++ b/crates/bevy_pbr/src/environment_map/mod.rs @@ -6,7 +6,10 @@ use bevy_reflect::Reflect; use bevy_render::{ extract_component::{ExtractComponent, ExtractComponentPlugin}, render_asset::RenderAssets, - render_resource::*, + render_resource::{ + binding_types::{sampler, texture_cube}, + *, + }, texture::{FallbackImageCubemap, Image}, }; @@ -79,33 +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] { [ - BindGroupLayoutEntry { - binding: bindings[0], - visibility: ShaderStages::FRAGMENT, - ty: BindingType::Texture { - sample_type: TextureSampleType::Float { filterable: true }, - view_dimension: TextureViewDimension::Cube, - multisampled: false, - }, - count: None, - }, - BindGroupLayoutEntry { - binding: bindings[1], - visibility: ShaderStages::FRAGMENT, - ty: BindingType::Texture { - sample_type: TextureSampleType::Float { filterable: true }, - view_dimension: TextureViewDimension::Cube, - multisampled: false, - }, - count: None, - }, - BindGroupLayoutEntry { - binding: bindings[2], - visibility: ShaderStages::FRAGMENT, - ty: BindingType::Sampler(SamplerBindingType::Filtering), - count: None, - }, + texture_cube(TextureSampleType::Float { filterable: true }), + texture_cube(TextureSampleType::Float { filterable: true }), + sampler(SamplerBindingType::Filtering), ] } diff --git a/crates/bevy_pbr/src/prepass/mod.rs b/crates/bevy_pbr/src/prepass/mod.rs index 6f2dfed69e12d..67ed3b8362b13 100644 --- a/crates/bevy_pbr/src/prepass/mod.rs +++ b/crates/bevy_pbr/src/prepass/mod.rs @@ -1,5 +1,6 @@ mod prepass_bindings; +use bevy_render::render_resource::binding_types::uniform_buffer; pub use prepass_bindings::*; use bevy_app::{Plugin, PreUpdate}; @@ -229,74 +230,33 @@ impl FromWorld for PrepassPipeline { let render_device = world.resource::(); let asset_server = world.resource::(); - let view_layout_motion_vectors = - render_device.create_bind_group_layout(&BindGroupLayoutDescriptor { - entries: &[ + let view_layout_motion_vectors = render_device.create_bind_group_layout( + "prepass_view_layout_motion_vectors", + &BindGroupLayoutEntries::sequential( + ShaderStages::VERTEX_FRAGMENT, + ( // View - BindGroupLayoutEntry { - binding: 0, - visibility: ShaderStages::VERTEX | ShaderStages::FRAGMENT, - ty: BindingType::Buffer { - ty: BufferBindingType::Uniform, - has_dynamic_offset: true, - min_binding_size: Some(ViewUniform::min_size()), - }, - count: None, - }, + uniform_buffer::(true), // Globals - BindGroupLayoutEntry { - binding: 1, - visibility: ShaderStages::VERTEX_FRAGMENT, - ty: BindingType::Buffer { - ty: BufferBindingType::Uniform, - has_dynamic_offset: false, - min_binding_size: Some(GlobalsUniform::min_size()), - }, - count: None, - }, + uniform_buffer::(false), // PreviousViewProjection - BindGroupLayoutEntry { - binding: 2, - visibility: ShaderStages::VERTEX | ShaderStages::FRAGMENT, - ty: BindingType::Buffer { - ty: BufferBindingType::Uniform, - has_dynamic_offset: true, - min_binding_size: Some(PreviousViewProjection::min_size()), - }, - count: None, - }, - ], - label: Some("prepass_view_layout_motion_vectors"), - }); + uniform_buffer::(true), + ), + ), + ); - let view_layout_no_motion_vectors = - render_device.create_bind_group_layout(&BindGroupLayoutDescriptor { - entries: &[ + let view_layout_no_motion_vectors = render_device.create_bind_group_layout( + "prepass_view_layout_no_motion_vectors", + &BindGroupLayoutEntries::sequential( + ShaderStages::VERTEX_FRAGMENT, + ( // View - BindGroupLayoutEntry { - binding: 0, - visibility: ShaderStages::VERTEX | ShaderStages::FRAGMENT, - ty: BindingType::Buffer { - ty: BufferBindingType::Uniform, - has_dynamic_offset: true, - min_binding_size: Some(ViewUniform::min_size()), - }, - count: None, - }, + uniform_buffer::(true), // Globals - BindGroupLayoutEntry { - binding: 1, - visibility: ShaderStages::VERTEX_FRAGMENT, - ty: BindingType::Buffer { - ty: BufferBindingType::Uniform, - has_dynamic_offset: false, - min_binding_size: Some(GlobalsUniform::min_size()), - }, - count: None, - }, - ], - label: Some("prepass_view_layout_no_motion_vectors"), - }); + uniform_buffer::(false), + ), + ), + ); let mesh_pipeline = world.resource::(); diff --git a/crates/bevy_pbr/src/prepass/prepass_bindings.rs b/crates/bevy_pbr/src/prepass/prepass_bindings.rs index b72ddd1e318cd..52ea02c1f5d20 100644 --- a/crates/bevy_pbr/src/prepass/prepass_bindings.rs +++ b/crates/bevy_pbr/src/prepass/prepass_bindings.rs @@ -1,7 +1,10 @@ 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_depth_2d, texture_depth_2d_multisampled, + }, + BindGroupLayoutEntryBuilder, TextureAspect, TextureSampleType, TextureView, + TextureViewDescriptor, }; use bevy_utils::default; use smallvec::SmallVec; @@ -9,25 +12,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 +32,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 +43,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 +54,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(TextureSampleType::Uint), ); } diff --git a/crates/bevy_pbr/src/render/mesh_bindings.rs b/crates/bevy_pbr/src/render/mesh_bindings.rs index df935e1805c8a..f273da7bcb245 100644 --- a/crates/bevy_pbr/src/render/mesh_bindings.rs +++ b/crates/bevy_pbr/src/render/mesh_bindings.rs @@ -17,50 +17,28 @@ mod layout_entry { use crate::MeshUniform; use bevy_render::{ render_resource::{ - BindGroupLayoutEntry, BindingType, BufferBindingType, BufferSize, GpuArrayBuffer, - ShaderStages, TextureSampleType, TextureViewDimension, + binding_types::{texture_3d, uniform_buffer_sized}, + BindGroupLayoutEntryBuilder, BufferSize, GpuArrayBuffer, ShaderStages, + TextureSampleType, }, renderer::RenderDevice, }; - fn buffer(binding: u32, size: u64, visibility: ShaderStages) -> BindGroupLayoutEntry { - BindGroupLayoutEntry { - binding, - visibility, - count: None, - ty: BindingType::Buffer { - ty: BufferBindingType::Uniform, - has_dynamic_offset: true, - min_binding_size: BufferSize::new(size), - }, - } - } - pub(super) fn model(render_device: &RenderDevice, binding: u32) -> BindGroupLayoutEntry { - GpuArrayBuffer::::binding_layout( - binding, - ShaderStages::VERTEX_FRAGMENT, - render_device, - ) + pub(super) fn model(render_device: &RenderDevice) -> BindGroupLayoutEntryBuilder { + GpuArrayBuffer::::binding_layout(render_device) + .visibility(ShaderStages::VERTEX_FRAGMENT) } - pub(super) fn skinning(binding: u32) -> BindGroupLayoutEntry { - buffer(binding, JOINT_BUFFER_SIZE as u64, ShaderStages::VERTEX) + pub(super) fn skinning() -> BindGroupLayoutEntryBuilder { + uniform_buffer_sized(true, BufferSize::new(JOINT_BUFFER_SIZE as u64)) } - pub(super) fn weights(binding: u32) -> BindGroupLayoutEntry { - buffer(binding, MORPH_BUFFER_SIZE as u64, ShaderStages::VERTEX) + pub(super) fn weights() -> BindGroupLayoutEntryBuilder { + uniform_buffer_sized(true, BufferSize::new(MORPH_BUFFER_SIZE as u64)) } - pub(super) fn targets(binding: u32) -> BindGroupLayoutEntry { - BindGroupLayoutEntry { - binding, - visibility: ShaderStages::VERTEX, - ty: BindingType::Texture { - view_dimension: TextureViewDimension::D3, - sample_type: TextureSampleType::Float { filterable: false }, - multisampled: false, - }, - count: None, - } + pub(super) fn targets() -> BindGroupLayoutEntryBuilder { + texture_3d(TextureSampleType::Float { filterable: false }) } } + /// Individual [`BindGroupEntry`] /// for bind groups. mod entry { @@ -133,40 +111,52 @@ impl MeshLayouts { // ---------- create individual BindGroupLayouts ---------- fn model_only_layout(render_device: &RenderDevice) -> BindGroupLayout { - render_device.create_bind_group_layout(&BindGroupLayoutDescriptor { - entries: &[layout_entry::model(render_device, 0)], - label: Some("mesh_layout"), - }) + render_device.create_bind_group_layout( + "mesh_layout", + &BindGroupLayoutEntries::single( + ShaderStages::empty(), + layout_entry::model(render_device), + ), + ) } fn skinned_layout(render_device: &RenderDevice) -> BindGroupLayout { - render_device.create_bind_group_layout(&BindGroupLayoutDescriptor { - entries: &[ - layout_entry::model(render_device, 0), - layout_entry::skinning(1), - ], - label: Some("skinned_mesh_layout"), - }) + render_device.create_bind_group_layout( + "skinned_mesh_layout", + &BindGroupLayoutEntries::with_indices( + ShaderStages::VERTEX, + ( + (0, layout_entry::model(render_device)), + (1, layout_entry::skinning()), + ), + ), + ) } fn morphed_layout(render_device: &RenderDevice) -> BindGroupLayout { - render_device.create_bind_group_layout(&BindGroupLayoutDescriptor { - entries: &[ - layout_entry::model(render_device, 0), - layout_entry::weights(2), - layout_entry::targets(3), - ], - label: Some("morphed_mesh_layout"), - }) + render_device.create_bind_group_layout( + "morphed_mesh_layout", + &BindGroupLayoutEntries::with_indices( + ShaderStages::VERTEX, + ( + (0, layout_entry::model(render_device)), + (2, layout_entry::weights()), + (3, layout_entry::targets()), + ), + ), + ) } fn morphed_skinned_layout(render_device: &RenderDevice) -> BindGroupLayout { - render_device.create_bind_group_layout(&BindGroupLayoutDescriptor { - entries: &[ - layout_entry::model(render_device, 0), - layout_entry::skinning(1), - layout_entry::weights(2), - layout_entry::targets(3), - ], - label: Some("morphed_skinned_mesh_layout"), - }) + render_device.create_bind_group_layout( + "morphed_skinned_mesh_layout", + &BindGroupLayoutEntries::with_indices( + ShaderStages::VERTEX, + ( + (0, layout_entry::model(render_device)), + (1, layout_entry::skinning()), + (2, layout_entry::weights()), + (3, layout_entry::targets()), + ), + ), + ) } // ---------- BindGroup methods ---------- diff --git a/crates/bevy_pbr/src/render/mesh_view_bindings.rs b/crates/bevy_pbr/src/render/mesh_view_bindings.rs index 853c253209a68..cbd0e982a460e 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,15 +16,24 @@ use bevy_render::{ globals::{GlobalsBuffer, GlobalsUniform}, render_asset::RenderAssets, render_resource::{ - BindGroup, BindGroupLayout, BindGroupLayoutDescriptor, BindGroupLayoutEntry, BindingType, - BufferBindingType, DynamicBindGroupEntries, SamplerBindingType, ShaderStages, ShaderType, - TextureFormat, TextureSampleType, TextureViewDimension, + binding_types::{ + sampler, storage_buffer_read_only_sized, storage_buffer_sized, texture_2d, + uniform_buffer, uniform_buffer_sized, + }, + BindGroup, BindGroupLayout, BindGroupLayoutEntry, BindGroupLayoutEntryBuilder, BindingType, + BufferBindingType, DynamicBindGroupEntries, DynamicBindGroupLayoutEntries, + SamplerBindingType, ShaderStages, TextureFormat, TextureSampleType, }, renderer::RenderDevice, texture::{BevyDefault, FallbackImageCubemap, FallbackImageMsaa, FallbackImageZero, Image}, view::{Msaa, ViewUniform, ViewUniforms}, }; +#[cfg(all(feature = "webgl", target_arch = "wasm32"))] +use bevy_render::render_resource::binding_types::texture_cube; +#[cfg(any(not(feature = "webgl"), not(target_arch = "wasm32")))] +use bevy_render::render_resource::binding_types::{texture_2d_array, texture_cube_array}; + use crate::{ environment_map, prepass, EnvironmentMapLight, FogMeta, GlobalLightMeta, GpuFog, GpuLights, GpuPointLights, LightMeta, MeshPipeline, MeshPipelineKey, ScreenSpaceAmbientOcclusionTextures, @@ -144,190 +153,141 @@ 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_sized(has_dynamic_offset, min_binding_size), + BufferBindingType::Storage { read_only } => { + if read_only { + storage_buffer_read_only_sized(has_dynamic_offset, min_binding_size) + } else { + storage_buffer_sized(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 - BindGroupLayoutEntry { - binding: 0, - visibility: ShaderStages::VERTEX | ShaderStages::FRAGMENT, - ty: BindingType::Buffer { - ty: BufferBindingType::Uniform, - has_dynamic_offset: true, - min_binding_size: Some(ViewUniform::min_size()), - }, - count: None, - }, - // Lights - BindGroupLayoutEntry { - binding: 1, - visibility: ShaderStages::FRAGMENT, - ty: BindingType::Buffer { - ty: BufferBindingType::Uniform, - has_dynamic_offset: true, - min_binding_size: Some(GpuLights::min_size()), - }, - count: None, - }, - // 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).visibility(ShaderStages::VERTEX_FRAGMENT), + ), + // Lights + (1, uniform_buffer::(true)), + // 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 - BindGroupLayoutEntry { - binding: 3, - visibility: ShaderStages::FRAGMENT, - ty: BindingType::Sampler(SamplerBindingType::Comparison), - count: None, - }, - // 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 - BindGroupLayoutEntry { - binding: 5, - visibility: ShaderStages::FRAGMENT, - ty: BindingType::Sampler(SamplerBindingType::Comparison), - count: None, - }, - // 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 - BindGroupLayoutEntry { - binding: 9, - visibility: ShaderStages::VERTEX_FRAGMENT, - ty: BindingType::Buffer { - ty: BufferBindingType::Uniform, - has_dynamic_offset: false, - min_binding_size: Some(GlobalsUniform::min_size()), - }, - count: None, - }, - // Fog - BindGroupLayoutEntry { - binding: 10, - visibility: ShaderStages::FRAGMENT, - ty: BindingType::Buffer { - ty: BufferBindingType::Uniform, - has_dynamic_offset: true, - min_binding_size: Some(GpuFog::min_size()), - }, - count: None, - }, - // Screen space ambient occlusion texture - BindGroupLayoutEntry { - binding: 11, - visibility: ShaderStages::FRAGMENT, - ty: BindingType::Texture { - multisampled: false, - sample_type: TextureSampleType::Float { filterable: false }, - view_dimension: TextureViewDimension::D2, - }, - count: None, - }, - ]; + false, + Some(ViewClusterBindings::min_size_cluster_offsets_and_counts( + clustered_forward_buffer_binding_type, + )), + ), + ), + // Globals + (9, uniform_buffer::(false)), + // Fog + (10, uniform_buffer::(true)), + // 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 @@ -347,10 +307,8 @@ pub fn generate_view_layouts( .count(); MeshPipelineViewLayout { - bind_group_layout: render_device.create_bind_group_layout(&BindGroupLayoutDescriptor { - label: Some(key.label().as_str()), - entries: &entries, - }), + bind_group_layout: render_device + .create_bind_group_layout(key.label().as_str(), &entries), #[cfg(debug_assertions)] texture_count, } diff --git a/crates/bevy_pbr/src/ssao/mod.rs b/crates/bevy_pbr/src/ssao/mod.rs index 62a7d4e5a4a6a..14f1a05355385 100644 --- a/crates/bevy_pbr/src/ssao/mod.rs +++ b/crates/bevy_pbr/src/ssao/mod.rs @@ -20,7 +20,12 @@ use bevy_render::{ globals::{GlobalsBuffer, GlobalsUniform}, prelude::Camera, render_graph::{NodeRunError, RenderGraphApp, RenderGraphContext, ViewNode, ViewNodeRunner}, - render_resource::*, + render_resource::{ + binding_types::{ + sampler, texture_2d, texture_depth_2d, texture_storage_2d, uniform_buffer, + }, + *, + }, renderer::{RenderAdapter, RenderContext, RenderDevice, RenderQueue}, texture::{CachedTexture, TextureCache}, view::{Msaa, ViewUniform, ViewUniformOffset, ViewUniforms}, @@ -345,176 +350,58 @@ impl FromWorld for SsaoPipelines { ..Default::default() }); - let common_bind_group_layout = - render_device.create_bind_group_layout(&BindGroupLayoutDescriptor { - label: Some("ssao_common_bind_group_layout"), - entries: &[ - BindGroupLayoutEntry { - binding: 0, - visibility: ShaderStages::COMPUTE, - ty: BindingType::Sampler(SamplerBindingType::NonFiltering), - count: None, - }, - BindGroupLayoutEntry { - binding: 1, - visibility: ShaderStages::COMPUTE, - ty: BindingType::Buffer { - ty: BufferBindingType::Uniform, - has_dynamic_offset: true, - min_binding_size: Some(ViewUniform::min_size()), - }, - count: None, - }, - ], - }); + let common_bind_group_layout = render_device.create_bind_group_layout( + "ssao_common_bind_group_layout", + &BindGroupLayoutEntries::sequential( + ShaderStages::COMPUTE, + ( + sampler(SamplerBindingType::NonFiltering), + uniform_buffer::(true), + ), + ), + ); - let mip_texture_entry = BindGroupLayoutEntry { - binding: 1, - visibility: ShaderStages::COMPUTE, - ty: BindingType::StorageTexture { - access: StorageTextureAccess::WriteOnly, - format: TextureFormat::R16Float, - view_dimension: TextureViewDimension::D2, - }, - count: None, - }; - let preprocess_depth_bind_group_layout = - render_device.create_bind_group_layout(&BindGroupLayoutDescriptor { - label: Some("ssao_preprocess_depth_bind_group_layout"), - entries: &[ - BindGroupLayoutEntry { - binding: 0, - visibility: ShaderStages::COMPUTE, - ty: BindingType::Texture { - sample_type: TextureSampleType::Depth, - view_dimension: TextureViewDimension::D2, - multisampled: false, - }, - count: None, - }, - mip_texture_entry, - BindGroupLayoutEntry { - binding: 2, - ..mip_texture_entry - }, - BindGroupLayoutEntry { - binding: 3, - ..mip_texture_entry - }, - BindGroupLayoutEntry { - binding: 4, - ..mip_texture_entry - }, - BindGroupLayoutEntry { - binding: 5, - ..mip_texture_entry - }, - ], - }); + let preprocess_depth_bind_group_layout = render_device.create_bind_group_layout( + "ssao_preprocess_depth_bind_group_layout", + &BindGroupLayoutEntries::sequential( + ShaderStages::COMPUTE, + ( + texture_depth_2d(), + texture_storage_2d(TextureFormat::R16Float, StorageTextureAccess::WriteOnly), + texture_storage_2d(TextureFormat::R16Float, StorageTextureAccess::WriteOnly), + texture_storage_2d(TextureFormat::R16Float, StorageTextureAccess::WriteOnly), + texture_storage_2d(TextureFormat::R16Float, StorageTextureAccess::WriteOnly), + texture_storage_2d(TextureFormat::R16Float, StorageTextureAccess::WriteOnly), + ), + ), + ); - let gtao_bind_group_layout = - render_device.create_bind_group_layout(&BindGroupLayoutDescriptor { - label: Some("ssao_gtao_bind_group_layout"), - entries: &[ - BindGroupLayoutEntry { - binding: 0, - visibility: ShaderStages::COMPUTE, - ty: BindingType::Texture { - sample_type: TextureSampleType::Float { filterable: false }, - view_dimension: TextureViewDimension::D2, - multisampled: false, - }, - count: None, - }, - BindGroupLayoutEntry { - binding: 1, - visibility: ShaderStages::COMPUTE, - ty: BindingType::Texture { - sample_type: TextureSampleType::Float { filterable: false }, - view_dimension: TextureViewDimension::D2, - multisampled: false, - }, - count: None, - }, - BindGroupLayoutEntry { - binding: 2, - visibility: ShaderStages::COMPUTE, - ty: BindingType::Texture { - sample_type: TextureSampleType::Uint, - view_dimension: TextureViewDimension::D2, - multisampled: false, - }, - count: None, - }, - BindGroupLayoutEntry { - binding: 3, - visibility: ShaderStages::COMPUTE, - ty: BindingType::StorageTexture { - access: StorageTextureAccess::WriteOnly, - format: TextureFormat::R16Float, - view_dimension: TextureViewDimension::D2, - }, - count: None, - }, - BindGroupLayoutEntry { - binding: 4, - visibility: ShaderStages::COMPUTE, - ty: BindingType::StorageTexture { - access: StorageTextureAccess::WriteOnly, - format: TextureFormat::R32Uint, - view_dimension: TextureViewDimension::D2, - }, - count: None, - }, - BindGroupLayoutEntry { - binding: 5, - visibility: ShaderStages::COMPUTE, - ty: BindingType::Buffer { - ty: BufferBindingType::Uniform, - has_dynamic_offset: false, - min_binding_size: Some(GlobalsUniform::min_size()), - }, - count: None, - }, - ], - }); + let gtao_bind_group_layout = render_device.create_bind_group_layout( + "ssao_gtao_bind_group_layout", + &BindGroupLayoutEntries::sequential( + ShaderStages::COMPUTE, + ( + texture_2d(TextureSampleType::Float { filterable: false }), + texture_2d(TextureSampleType::Float { filterable: false }), + texture_2d(TextureSampleType::Uint), + texture_storage_2d(TextureFormat::R16Float, StorageTextureAccess::WriteOnly), + texture_storage_2d(TextureFormat::R32Uint, StorageTextureAccess::WriteOnly), + uniform_buffer::(false), + ), + ), + ); - let spatial_denoise_bind_group_layout = - render_device.create_bind_group_layout(&BindGroupLayoutDescriptor { - label: Some("ssao_spatial_denoise_bind_group_layout"), - entries: &[ - BindGroupLayoutEntry { - binding: 0, - visibility: ShaderStages::COMPUTE, - ty: BindingType::Texture { - sample_type: TextureSampleType::Float { filterable: false }, - view_dimension: TextureViewDimension::D2, - multisampled: false, - }, - count: None, - }, - BindGroupLayoutEntry { - binding: 1, - visibility: ShaderStages::COMPUTE, - ty: BindingType::Texture { - sample_type: TextureSampleType::Uint, - view_dimension: TextureViewDimension::D2, - multisampled: false, - }, - count: None, - }, - BindGroupLayoutEntry { - binding: 2, - visibility: ShaderStages::COMPUTE, - ty: BindingType::StorageTexture { - access: StorageTextureAccess::WriteOnly, - format: TextureFormat::R16Float, - view_dimension: TextureViewDimension::D2, - }, - count: None, - }, - ], - }); + let spatial_denoise_bind_group_layout = render_device.create_bind_group_layout( + "ssao_spatial_denoise_bind_group_layout", + &BindGroupLayoutEntries::sequential( + ShaderStages::COMPUTE, + ( + texture_2d(TextureSampleType::Float { filterable: false }), + texture_2d(TextureSampleType::Uint), + texture_storage_2d(TextureFormat::R16Float, StorageTextureAccess::WriteOnly), + ), + ), + ); let preprocess_depth_pipeline = pipeline_cache.queue_compute_pipeline(ComputePipelineDescriptor { diff --git a/crates/bevy_render/src/render_resource/bind_group.rs b/crates/bevy_render/src/render_resource/bind_group.rs index b2907c64fd661..22ab55fd1292f 100644 --- a/crates/bevy_render/src/render_resource/bind_group.rs +++ b/crates/bevy_render/src/render_resource/bind_group.rs @@ -10,7 +10,7 @@ pub use bevy_render_macros::AsBindGroup; use bevy_utils::thiserror::Error; use encase::ShaderType; use std::ops::Deref; -use wgpu::{BindGroupEntry, BindGroupLayoutDescriptor, BindGroupLayoutEntry, BindingResource}; +use wgpu::{BindGroupEntry, BindGroupLayoutEntry, BindingResource}; define_atomic_id!(BindGroupId); render_resource_wrapper!(ErasedBindGroup, wgpu::BindGroup); @@ -313,10 +313,10 @@ pub trait AsBindGroup { where Self: Sized, { - render_device.create_bind_group_layout(&BindGroupLayoutDescriptor { - label: Self::label(), - entries: &Self::bind_group_layout_entries(render_device), - }) + render_device.create_bind_group_layout( + Self::label(), + &Self::bind_group_layout_entries(render_device), + ) } /// Returns a vec of bind group layout entries 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 new file mode 100644 index 0000000000000..ad251696571bf --- /dev/null +++ b/crates/bevy_render/src/render_resource/bind_group_layout_entries.rs @@ -0,0 +1,546 @@ +use bevy_utils::all_tuples_with_size; +use std::num::NonZeroU32; +use wgpu::{BindGroupLayoutEntry, BindingType, ShaderStages}; + +/// Helper for constructing bind group layouts. +/// +/// Allows constructing the layout's entries as: +/// ```ignore +/// let layout = render_device.create_bind_group_layout( +/// "my_bind_group_layout", +/// &BindGroupLayoutEntries::with_indices( +/// // The layout entries will only be visible in the fragment stage +/// ShaderStages::FRAGMENT, +/// ( +/// // Screen texture +/// (2, tepxture_2d(TextureSampleType::Float { filterable: true })), +/// // Sampler +/// (3, sampler(SamplerBindingType::Filtering)), +/// ), +/// ), +/// ); +/// ``` +/// +/// instead of +/// +/// ```ignore +/// let layout = render_device.create_bind_group_layout( +/// "my_bind_group_layout", +/// &[ +/// // Screen texture +/// BindGroupLayoutEntry { +/// binding: 2, +/// visibility: ShaderStages::FRAGMENT, +/// ty: BindingType::Texture { +/// sample_type: TextureSampleType::Float { filterable: true }, +/// view_dimension: TextureViewDimension::D2, +/// multisampled: false, +/// }, +/// count: None, +/// }, +/// // Sampler +/// BindGroupLayoutEntry { +/// binding: 3, +/// visibility: ShaderStages::FRAGMENT, +/// ty: BindingType::Sampler(SamplerBindingType::Filtering), +/// count: None, +/// }, +/// ], +/// ); +/// ``` +/// +/// or +/// +/// ```ignore +/// render_device.create_bind_group_layout( +/// "my_bind_group_layout", +/// &BindGroupLayoutEntries::sequential( +/// ShaderStages::FRAGMENT, +/// ( +/// // Screen texture +/// texture_2d(TextureSampleType::Float { filterable: true }), +/// // Sampler +/// sampler(SamplerBindingType::Filtering), +/// ), +/// ), +/// ); +/// ``` +/// +/// instead of +/// +/// ```ignore +/// let layout = render_device.create_bind_group_layout( +/// "my_bind_group_layout", +/// &[ +/// // Screen texture +/// BindGroupLayoutEntry { +/// binding: 0, +/// visibility: ShaderStages::FRAGMENT, +/// ty: BindingType::Texture { +/// sample_type: TextureSampleType::Float { filterable: true }, +/// view_dimension: TextureViewDimension::D2, +/// multisampled: false, +/// }, +/// count: None, +/// }, +/// // Sampler +/// BindGroupLayoutEntry { +/// binding: 1, +/// visibility: ShaderStages::FRAGMENT, +/// ty: BindingType::Sampler(SamplerBindingType::Filtering), +/// count: None, +/// }, +/// ], +/// ); +/// ``` +/// +/// or +/// +/// ```ignore +/// render_device.create_bind_group_layout( +/// "my_bind_group_layout", +/// &BindGroupLayoutEntries::single( +/// ShaderStages::FRAGMENT, +/// texture_2d(TextureSampleType::Float { filterable: true }), +/// ), +/// ); +/// ``` +/// +/// instead of +/// +/// ```ignore +/// let layout = render_device.create_bind_group_layout( +/// "my_bind_group_layout", +/// &[ +/// BindGroupLayoutEntry { +/// binding: 0, +/// visibility: ShaderStages::FRAGMENT, +/// ty: BindingType::Texture { +/// sample_type: TextureSampleType::Float { filterable: true }, +/// view_dimension: TextureViewDimension::D2, +/// multisampled: false, +/// }, +/// count: None, +/// }, +/// ], +/// ); +/// ``` + +#[derive(Clone, Copy)] +pub struct BindGroupLayoutEntryBuilder { + ty: BindingType, + visibility: Option, + count: Option, +} + +impl BindGroupLayoutEntryBuilder { + pub fn visibility(mut self, visibility: ShaderStages) -> Self { + self.visibility = Some(visibility); + self + } + + pub fn count(mut self, count: NonZeroU32) -> Self { + self.count = Some(count); + self + } + + pub fn build( + &self, + binding: u32, + default_visibility: ShaderStages, + ) -> wgpu::BindGroupLayoutEntry { + wgpu::BindGroupLayoutEntry { + binding, + ty: self.ty, + visibility: self.visibility.unwrap_or(default_visibility), + count: self.count, + } + } +} + +pub struct BindGroupLayoutEntries { + entries: [wgpu::BindGroupLayoutEntry; N], +} + +impl BindGroupLayoutEntries { + #[inline] + pub fn sequential( + default_visibility: ShaderStages, + entries_ext: impl IntoBindGroupLayoutEntryBuilderArray, + ) -> Self { + let mut i = 0; + Self { + entries: entries_ext.into_array().map(|entry| { + let binding = i; + i += 1; + entry.build(binding, default_visibility) + }), + } + } + + #[inline] + pub fn with_indices( + default_visibility: ShaderStages, + indexed_entries: impl IntoIndexedBindGroupLayoutEntryBuilderArray, + ) -> Self { + Self { + entries: indexed_entries + .into_array() + .map(|(binding, entry)| entry.build(binding, default_visibility)), + } + } +} + +impl BindGroupLayoutEntries<1> { + pub fn single( + visibility: ShaderStages, + resource: impl IntoBindGroupLayoutEntryBuilder, + ) -> [BindGroupLayoutEntry; 1] { + [resource + .into_bind_group_layout_entry_builder() + .build(0, visibility)] + } +} + +impl std::ops::Deref for BindGroupLayoutEntries { + type Target = [wgpu::BindGroupLayoutEntry]; + fn deref(&self) -> &[wgpu::BindGroupLayoutEntry] { + &self.entries + } +} + +pub trait IntoBindGroupLayoutEntryBuilder { + fn into_bind_group_layout_entry_builder(self) -> BindGroupLayoutEntryBuilder; +} + +impl IntoBindGroupLayoutEntryBuilder for BindingType { + fn into_bind_group_layout_entry_builder(self) -> BindGroupLayoutEntryBuilder { + BindGroupLayoutEntryBuilder { + ty: self, + visibility: None, + count: None, + } + } +} + +impl IntoBindGroupLayoutEntryBuilder for wgpu::BindGroupLayoutEntry { + fn into_bind_group_layout_entry_builder(self) -> BindGroupLayoutEntryBuilder { + if self.binding != u32::MAX { + bevy_log::warn!("The BindGroupLayoutEntries api ignores the binding index when converting a raw wgpu::BindGroupLayoutEntry. You can ignore this warning by setting it to u32::MAX."); + } + BindGroupLayoutEntryBuilder { + ty: self.ty, + visibility: Some(self.visibility), + count: self.count, + } + } +} + +impl IntoBindGroupLayoutEntryBuilder for BindGroupLayoutEntryBuilder { + fn into_bind_group_layout_entry_builder(self) -> BindGroupLayoutEntryBuilder { + self + } +} + +pub trait IntoBindGroupLayoutEntryBuilderArray { + fn into_array(self) -> [BindGroupLayoutEntryBuilder; N]; +} +macro_rules! impl_to_binding_type_slice { + ($N: expr, $(($T: ident, $I: ident)),*) => { + impl<$($T: IntoBindGroupLayoutEntryBuilder),*> IntoBindGroupLayoutEntryBuilderArray<$N> for ($($T,)*) { + #[inline] + fn into_array(self) -> [BindGroupLayoutEntryBuilder; $N] { + let ($($I,)*) = self; + [$($I.into_bind_group_layout_entry_builder(), )*] + } + } + } +} +all_tuples_with_size!(impl_to_binding_type_slice, 1, 32, T, s); + +pub trait IntoIndexedBindGroupLayoutEntryBuilderArray { + fn into_array(self) -> [(u32, BindGroupLayoutEntryBuilder); N]; +} +macro_rules! impl_to_indexed_binding_type_slice { + ($N: expr, $(($T: ident, $S: ident, $I: ident)),*) => { + impl<$($T: IntoBindGroupLayoutEntryBuilder),*> IntoIndexedBindGroupLayoutEntryBuilderArray<$N> for ($((u32, $T),)*) { + #[inline] + fn into_array(self) -> [(u32, BindGroupLayoutEntryBuilder); $N] { + let ($(($S, $I),)*) = self; + [$(($S, $I.into_bind_group_layout_entry_builder())), *] + } + } + } +} +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, +} + +impl DynamicBindGroupLayoutEntries { + pub fn sequential( + default_visibility: ShaderStages, + entries: impl IntoBindGroupLayoutEntryBuilderArray, + ) -> Self { + Self { + default_visibility, + entries: entries + .into_array() + .into_iter() + .enumerate() + .map(|(ix, resource)| resource.build(ix as u32, default_visibility)) + .collect(), + } + } + + pub fn extend_sequential( + mut self, + entries: impl IntoBindGroupLayoutEntryBuilderArray, + ) -> Self { + let start = self.entries.last().unwrap().binding + 1; + self.entries.extend( + entries + .into_array() + .into_iter() + .enumerate() + .map(|(ix, resource)| resource.build(start + ix as u32, self.default_visibility)), + ); + self + } + + pub fn new_with_indices( + default_visibility: ShaderStages, + entries: impl IntoIndexedBindGroupLayoutEntryBuilderArray, + ) -> Self { + Self { + default_visibility, + entries: entries + .into_array() + .into_iter() + .map(|(binding, resource)| resource.build(binding, default_visibility)) + .collect(), + } + } + + pub fn extend_with_indices( + mut self, + entries: impl IntoIndexedBindGroupLayoutEntryBuilderArray, + ) -> Self { + self.entries.extend( + entries + .into_array() + .into_iter() + .map(|(binding, resource)| resource.build(binding, self.default_visibility)), + ); + self + } +} + +impl std::ops::Deref for DynamicBindGroupLayoutEntries { + type Target = [BindGroupLayoutEntry]; + + fn deref(&self) -> &[BindGroupLayoutEntry] { + &self.entries + } +} + +pub mod binding_types { + use crate::render_resource::{ + BufferBindingType, SamplerBindingType, TextureSampleType, TextureViewDimension, + }; + use encase::ShaderType; + use std::num::NonZeroU64; + use wgpu::{BindingType, StorageTextureAccess, TextureFormat}; + + use super::*; + + pub fn storage_buffer(has_dynamic_offset: bool) -> BindGroupLayoutEntryBuilder { + storage_buffer_sized(has_dynamic_offset, Some(T::min_size())) + } + + pub fn storage_buffer_sized( + has_dynamic_offset: bool, + min_binding_size: Option, + ) -> BindGroupLayoutEntryBuilder { + BindingType::Buffer { + ty: BufferBindingType::Storage { read_only: false }, + has_dynamic_offset, + min_binding_size, + } + .into_bind_group_layout_entry_builder() + } + + pub fn storage_buffer_read_only( + has_dynamic_offset: bool, + ) -> BindGroupLayoutEntryBuilder { + storage_buffer_read_only_sized(has_dynamic_offset, Some(T::min_size())) + } + + pub fn storage_buffer_read_only_sized( + has_dynamic_offset: bool, + min_binding_size: Option, + ) -> BindGroupLayoutEntryBuilder { + BindingType::Buffer { + ty: BufferBindingType::Storage { read_only: true }, + has_dynamic_offset, + min_binding_size, + } + .into_bind_group_layout_entry_builder() + } + + pub fn uniform_buffer(has_dynamic_offset: bool) -> BindGroupLayoutEntryBuilder { + uniform_buffer_sized(has_dynamic_offset, Some(T::min_size())) + } + + pub fn uniform_buffer_sized( + has_dynamic_offset: bool, + min_binding_size: Option, + ) -> BindGroupLayoutEntryBuilder { + BindingType::Buffer { + ty: BufferBindingType::Uniform, + has_dynamic_offset, + min_binding_size, + } + .into_bind_group_layout_entry_builder() + } + + pub fn texture_2d(sample_type: TextureSampleType) -> BindGroupLayoutEntryBuilder { + BindingType::Texture { + sample_type, + view_dimension: TextureViewDimension::D2, + multisampled: false, + } + .into_bind_group_layout_entry_builder() + } + + pub fn texture_2d_multisampled(sample_type: TextureSampleType) -> BindGroupLayoutEntryBuilder { + BindingType::Texture { + sample_type, + view_dimension: TextureViewDimension::D2, + multisampled: true, + } + .into_bind_group_layout_entry_builder() + } + + pub fn texture_2d_array(sample_type: TextureSampleType) -> BindGroupLayoutEntryBuilder { + BindingType::Texture { + sample_type, + view_dimension: TextureViewDimension::D2Array, + multisampled: false, + } + .into_bind_group_layout_entry_builder() + } + + pub fn texture_2d_array_multisampled( + sample_type: TextureSampleType, + ) -> BindGroupLayoutEntryBuilder { + BindingType::Texture { + sample_type, + view_dimension: TextureViewDimension::D2Array, + multisampled: true, + } + .into_bind_group_layout_entry_builder() + } + + pub fn texture_depth_2d() -> BindGroupLayoutEntryBuilder { + texture_2d(TextureSampleType::Depth).into_bind_group_layout_entry_builder() + } + + pub fn texture_depth_2d_multisampled() -> BindGroupLayoutEntryBuilder { + texture_2d_multisampled(TextureSampleType::Depth).into_bind_group_layout_entry_builder() + } + + pub fn texture_cube(sample_type: TextureSampleType) -> BindGroupLayoutEntryBuilder { + BindingType::Texture { + sample_type, + view_dimension: TextureViewDimension::Cube, + multisampled: false, + } + .into_bind_group_layout_entry_builder() + } + + pub fn texture_cube_multisampled( + sample_type: TextureSampleType, + ) -> BindGroupLayoutEntryBuilder { + BindingType::Texture { + sample_type, + view_dimension: TextureViewDimension::Cube, + multisampled: true, + } + .into_bind_group_layout_entry_builder() + } + + pub fn texture_cube_array(sample_type: TextureSampleType) -> BindGroupLayoutEntryBuilder { + BindingType::Texture { + sample_type, + view_dimension: TextureViewDimension::CubeArray, + multisampled: false, + } + .into_bind_group_layout_entry_builder() + } + + pub fn texture_cube_array_multisampled( + sample_type: TextureSampleType, + ) -> BindGroupLayoutEntryBuilder { + BindingType::Texture { + sample_type, + view_dimension: TextureViewDimension::CubeArray, + multisampled: true, + } + .into_bind_group_layout_entry_builder() + } + + pub fn texture_3d(sample_type: TextureSampleType) -> BindGroupLayoutEntryBuilder { + BindingType::Texture { + sample_type, + view_dimension: TextureViewDimension::D3, + multisampled: false, + } + .into_bind_group_layout_entry_builder() + } + + pub fn texture_3d_multisampled(sample_type: TextureSampleType) -> BindGroupLayoutEntryBuilder { + BindingType::Texture { + sample_type, + view_dimension: TextureViewDimension::D3, + multisampled: true, + } + .into_bind_group_layout_entry_builder() + } + + pub fn sampler(sampler_binding_type: SamplerBindingType) -> BindGroupLayoutEntryBuilder { + BindingType::Sampler(sampler_binding_type).into_bind_group_layout_entry_builder() + } + + pub fn texture_storage_2d( + format: TextureFormat, + access: StorageTextureAccess, + ) -> BindGroupLayoutEntryBuilder { + BindingType::StorageTexture { + access, + format, + view_dimension: TextureViewDimension::D2, + } + .into_bind_group_layout_entry_builder() + } + + pub fn texture_storage_2d_array( + format: TextureFormat, + access: StorageTextureAccess, + ) -> BindGroupLayoutEntryBuilder { + BindingType::StorageTexture { + access, + format, + view_dimension: TextureViewDimension::D2Array, + } + .into_bind_group_layout_entry_builder() + } +} diff --git a/crates/bevy_render/src/render_resource/gpu_array_buffer.rs b/crates/bevy_render/src/render_resource/gpu_array_buffer.rs index a7147e367bec6..6c8103be04c30 100644 --- a/crates/bevy_render/src/render_resource/gpu_array_buffer.rs +++ b/crates/bevy_render/src/render_resource/gpu_array_buffer.rs @@ -1,4 +1,7 @@ -use super::StorageBuffer; +use super::{ + binding_types::{storage_buffer_read_only, uniform_buffer_sized}, + BindGroupLayoutEntryBuilder, StorageBuffer, +}; use crate::{ render_resource::batched_uniform_buffer::BatchedUniformBuffer, renderer::{RenderDevice, RenderQueue}, @@ -7,7 +10,7 @@ use bevy_ecs::{prelude::Component, system::Resource}; use bevy_utils::nonmax::NonMaxU32; use encase::{private::WriteInto, ShaderSize, ShaderType}; use std::{marker::PhantomData, mem}; -use wgpu::{BindGroupLayoutEntry, BindingResource, BindingType, BufferBindingType, ShaderStages}; +use wgpu::BindingResource; /// Trait for types able to go in a [`GpuArrayBuffer`]. pub trait GpuArrayBufferable: ShaderType + ShaderSize + WriteInto + Clone {} @@ -74,30 +77,16 @@ impl GpuArrayBuffer { } } - pub fn binding_layout( - binding: u32, - visibility: ShaderStages, - device: &RenderDevice, - ) -> BindGroupLayoutEntry { - BindGroupLayoutEntry { - binding, - visibility, - ty: if device.limits().max_storage_buffers_per_shader_stage == 0 { - BindingType::Buffer { - ty: BufferBindingType::Uniform, - has_dynamic_offset: true, - // BatchedUniformBuffer uses a MaxCapacityArray that is runtime-sized, so we use - // None here and let wgpu figure out the size. - min_binding_size: None, - } - } else { - BindingType::Buffer { - ty: BufferBindingType::Storage { read_only: true }, - has_dynamic_offset: false, - min_binding_size: Some(T::min_size()), - } - }, - count: None, + pub fn binding_layout(device: &RenderDevice) -> BindGroupLayoutEntryBuilder { + if device.limits().max_storage_buffers_per_shader_stage == 0 { + uniform_buffer_sized( + true, + // BatchedUniformBuffer uses a MaxCapacityArray that is runtime-sized, so we use + // None here and let wgpu figure out the size. + None, + ) + } else { + storage_buffer_read_only::(false) } } diff --git a/crates/bevy_render/src/render_resource/mod.rs b/crates/bevy_render/src/render_resource/mod.rs index 3ed787f257d65..12f2614d453fb 100644 --- a/crates/bevy_render/src/render_resource/mod.rs +++ b/crates/bevy_render/src/render_resource/mod.rs @@ -2,6 +2,7 @@ mod batched_uniform_buffer; mod bind_group; mod bind_group_entries; mod bind_group_layout; +mod bind_group_layout_entries; mod buffer; mod buffer_vec; mod gpu_array_buffer; @@ -17,6 +18,7 @@ mod uniform_buffer; pub use bind_group::*; pub use bind_group_entries::*; pub use bind_group_layout::*; +pub use bind_group_layout_entries::*; pub use buffer::*; pub use buffer_vec::*; pub use gpu_array_buffer::*; diff --git a/crates/bevy_render/src/renderer/render_device.rs b/crates/bevy_render/src/renderer/render_device.rs index 6a126df8aa41e..55be54b496354 100644 --- a/crates/bevy_render/src/renderer/render_device.rs +++ b/crates/bevy_render/src/renderer/render_device.rs @@ -4,7 +4,8 @@ use crate::render_resource::{ }; use bevy_ecs::system::Resource; use wgpu::{ - util::DeviceExt, BindGroupDescriptor, BindGroupEntry, BufferAsyncError, BufferBindingType, + util::DeviceExt, BindGroupDescriptor, BindGroupEntry, BindGroupLayoutDescriptor, + BindGroupLayoutEntry, BufferAsyncError, BufferBindingType, }; use super::RenderQueue; @@ -100,11 +101,18 @@ impl RenderDevice { /// Creates a [`BindGroupLayout`](wgpu::BindGroupLayout). #[inline] - pub fn create_bind_group_layout( + pub fn create_bind_group_layout<'a>( &self, - desc: &wgpu::BindGroupLayoutDescriptor, + label: impl Into>, + entries: &'a [BindGroupLayoutEntry], ) -> BindGroupLayout { - BindGroupLayout::from(self.device.create_bind_group_layout(desc)) + BindGroupLayout::from( + self.device + .create_bind_group_layout(&BindGroupLayoutDescriptor { + label: label.into(), + entries, + }), + ) } /// Creates a [`PipelineLayout`](wgpu::PipelineLayout). diff --git a/crates/bevy_render/src/view/window/screenshot.rs b/crates/bevy_render/src/view/window/screenshot.rs index db3a034744be0..c219c3f243492 100644 --- a/crates/bevy_render/src/view/window/screenshot.rs +++ b/crates/bevy_render/src/view/window/screenshot.rs @@ -15,9 +15,9 @@ use wgpu::{ use crate::{ prelude::{Image, Shader}, render_resource::{ - BindGroup, BindGroupLayout, Buffer, CachedRenderPipelineId, FragmentState, PipelineCache, - RenderPipelineDescriptor, SpecializedRenderPipeline, SpecializedRenderPipelines, Texture, - VertexState, + binding_types::texture_2d, BindGroup, BindGroupLayout, BindGroupLayoutEntries, Buffer, + CachedRenderPipelineId, FragmentState, PipelineCache, RenderPipelineDescriptor, + SpecializedRenderPipeline, SpecializedRenderPipelines, Texture, VertexState, }, renderer::RenderDevice, texture::TextureFormatPixelInfo, @@ -201,19 +201,13 @@ impl FromWorld for ScreenshotToScreenPipeline { fn from_world(render_world: &mut World) -> Self { let device = render_world.resource::(); - let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { - label: Some("screenshot-to-screen-bgl"), - entries: &[wgpu::BindGroupLayoutEntry { - binding: 0, - visibility: wgpu::ShaderStages::FRAGMENT, - ty: wgpu::BindingType::Texture { - sample_type: wgpu::TextureSampleType::Float { filterable: false }, - view_dimension: wgpu::TextureViewDimension::D2, - multisampled: false, - }, - count: None, - }], - }); + let bind_group_layout = device.create_bind_group_layout( + "screenshot-to-screen-bgl", + &BindGroupLayoutEntries::single( + wgpu::ShaderStages::FRAGMENT, + texture_2d(wgpu::TextureSampleType::Float { filterable: false }), + ), + ); Self { bind_group_layout } } diff --git a/crates/bevy_sprite/src/mesh2d/mesh.rs b/crates/bevy_sprite/src/mesh2d/mesh.rs index 9a63de7d2eaaf..1d7f8b11ba31a 100644 --- a/crates/bevy_sprite/src/mesh2d/mesh.rs +++ b/crates/bevy_sprite/src/mesh2d/mesh.rs @@ -19,7 +19,7 @@ use bevy_render::{ mesh::{GpuBufferInfo, Mesh, MeshVertexBufferLayout}, render_asset::RenderAssets, render_phase::{PhaseItem, RenderCommand, RenderCommandResult, TrackedRenderPass}, - render_resource::*, + render_resource::{binding_types::uniform_buffer, *}, renderer::{RenderDevice, RenderQueue}, texture::{ BevyDefault, DefaultImageSampler, GpuImage, Image, ImageSampler, TextureFormatPixelInfo, @@ -256,41 +256,25 @@ impl FromWorld for Mesh2dPipeline { )> = SystemState::new(world); let (render_device, render_queue, default_sampler) = system_state.get_mut(world); let render_device = render_device.into_inner(); - let view_layout = render_device.create_bind_group_layout(&BindGroupLayoutDescriptor { - entries: &[ - // View - BindGroupLayoutEntry { - binding: 0, - visibility: ShaderStages::VERTEX | 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::VERTEX_FRAGMENT, - ty: BindingType::Buffer { - ty: BufferBindingType::Uniform, - has_dynamic_offset: false, - min_binding_size: Some(GlobalsUniform::min_size()), - }, - count: None, - }, - ], - label: Some("mesh2d_view_layout"), - }); + let view_layout = render_device.create_bind_group_layout( + "mesh2d_view_layout", + &BindGroupLayoutEntries::sequential( + ShaderStages::VERTEX_FRAGMENT, + ( + // View + uniform_buffer::(true), + uniform_buffer::(false), + ), + ), + ); - let mesh_layout = render_device.create_bind_group_layout(&BindGroupLayoutDescriptor { - entries: &[GpuArrayBuffer::::binding_layout( - 0, + let mesh_layout = render_device.create_bind_group_layout( + "mesh2d_layout", + &BindGroupLayoutEntries::single( ShaderStages::VERTEX_FRAGMENT, - render_device, - )], - label: Some("mesh2d_layout"), - }); + GpuArrayBuffer::::binding_layout(render_device), + ), + ); // A 1x1x1 'all 1.0' texture to use as a dummy texture to use in place of optional StandardMaterial textures let dummy_white_gpu_image = { let image = Image::default(); diff --git a/crates/bevy_sprite/src/render/mod.rs b/crates/bevy_sprite/src/render/mod.rs index 54048bfd448be..bc1b91a0e5ff4 100644 --- a/crates/bevy_sprite/src/render/mod.rs +++ b/crates/bevy_sprite/src/render/mod.rs @@ -21,7 +21,10 @@ use bevy_render::{ DrawFunctions, PhaseItem, RenderCommand, RenderCommandResult, RenderPhase, SetItemPipeline, TrackedRenderPass, }, - render_resource::{BindGroupEntries, *}, + render_resource::{ + binding_types::{sampler, texture_2d, uniform_buffer}, + BindGroupEntries, *, + }, renderer::{RenderDevice, RenderQueue}, texture::{ BevyDefault, DefaultImageSampler, GpuImage, Image, ImageSampler, TextureFormatPixelInfo, @@ -53,41 +56,24 @@ impl FromWorld for SpritePipeline { )> = SystemState::new(world); let (render_device, default_sampler, render_queue) = system_state.get_mut(world); - let view_layout = render_device.create_bind_group_layout(&BindGroupLayoutDescriptor { - entries: &[BindGroupLayoutEntry { - binding: 0, - visibility: ShaderStages::VERTEX | ShaderStages::FRAGMENT, - ty: BindingType::Buffer { - ty: BufferBindingType::Uniform, - has_dynamic_offset: true, - min_binding_size: Some(ViewUniform::min_size()), - }, - count: None, - }], - label: Some("sprite_view_layout"), - }); - - let material_layout = render_device.create_bind_group_layout(&BindGroupLayoutDescriptor { - entries: &[ - BindGroupLayoutEntry { - binding: 0, - visibility: ShaderStages::FRAGMENT, - ty: BindingType::Texture { - multisampled: false, - sample_type: TextureSampleType::Float { filterable: true }, - view_dimension: TextureViewDimension::D2, - }, - count: None, - }, - BindGroupLayoutEntry { - binding: 1, - visibility: ShaderStages::FRAGMENT, - ty: BindingType::Sampler(SamplerBindingType::Filtering), - count: None, - }, - ], - label: Some("sprite_material_layout"), - }); + let view_layout = render_device.create_bind_group_layout( + "sprite_view_layout", + &BindGroupLayoutEntries::single( + ShaderStages::VERTEX_FRAGMENT, + uniform_buffer::(true), + ), + ); + + let material_layout = render_device.create_bind_group_layout( + "sprite_material_layout", + &BindGroupLayoutEntries::sequential( + ShaderStages::FRAGMENT, + ( + texture_2d(TextureSampleType::Float { filterable: true }), + sampler(SamplerBindingType::Filtering), + ), + ), + ); let dummy_white_gpu_image = { let image = Image::default(); let texture = render_device.create_texture(&image.texture_descriptor); diff --git a/crates/bevy_ui/src/render/pipeline.rs b/crates/bevy_ui/src/render/pipeline.rs index eaef41dbf4e90..6dad2b104c3bb 100644 --- a/crates/bevy_ui/src/render/pipeline.rs +++ b/crates/bevy_ui/src/render/pipeline.rs @@ -1,6 +1,9 @@ use bevy_ecs::prelude::*; use bevy_render::{ - render_resource::*, + render_resource::{ + binding_types::{sampler, texture_2d, uniform_buffer}, + *, + }, renderer::RenderDevice, texture::BevyDefault, view::{ViewTarget, ViewUniform}, @@ -16,41 +19,24 @@ impl FromWorld for UiPipeline { fn from_world(world: &mut World) -> Self { let render_device = world.resource::(); - let view_layout = render_device.create_bind_group_layout(&BindGroupLayoutDescriptor { - entries: &[BindGroupLayoutEntry { - binding: 0, - visibility: ShaderStages::VERTEX | ShaderStages::FRAGMENT, - ty: BindingType::Buffer { - ty: BufferBindingType::Uniform, - has_dynamic_offset: true, - min_binding_size: Some(ViewUniform::min_size()), - }, - count: None, - }], - label: Some("ui_view_layout"), - }); + let view_layout = render_device.create_bind_group_layout( + "ui_view_layout", + &BindGroupLayoutEntries::single( + ShaderStages::VERTEX_FRAGMENT, + uniform_buffer::(true), + ), + ); - let image_layout = render_device.create_bind_group_layout(&BindGroupLayoutDescriptor { - entries: &[ - BindGroupLayoutEntry { - binding: 0, - visibility: ShaderStages::FRAGMENT, - ty: BindingType::Texture { - multisampled: false, - sample_type: TextureSampleType::Float { filterable: true }, - view_dimension: TextureViewDimension::D2, - }, - count: None, - }, - BindGroupLayoutEntry { - binding: 1, - visibility: ShaderStages::FRAGMENT, - ty: BindingType::Sampler(SamplerBindingType::Filtering), - count: None, - }, - ], - label: Some("ui_image_layout"), - }); + let image_layout = render_device.create_bind_group_layout( + "ui_image_layout", + &BindGroupLayoutEntries::sequential( + ShaderStages::FRAGMENT, + ( + texture_2d(TextureSampleType::Float { filterable: true }), + sampler(SamplerBindingType::Filtering), + ), + ), + ); UiPipeline { view_layout, diff --git a/crates/bevy_ui/src/render/ui_material_pipeline.rs b/crates/bevy_ui/src/render/ui_material_pipeline.rs index 83ef5ef592c77..a535877485471 100644 --- a/crates/bevy_ui/src/render/ui_material_pipeline.rs +++ b/crates/bevy_ui/src/render/ui_material_pipeline.rs @@ -17,7 +17,7 @@ use bevy_render::{ extract_component::ExtractComponentPlugin, render_asset::RenderAssets, render_phase::*, - render_resource::*, + render_resource::{binding_types::uniform_buffer, *}, renderer::{RenderDevice, RenderQueue}, texture::{BevyDefault, FallbackImage, Image}, view::*, @@ -223,19 +223,13 @@ impl FromWorld for UiMaterialPipeline { let render_device = world.resource::(); let ui_layout = M::bind_group_layout(render_device); - let view_layout = render_device.create_bind_group_layout(&BindGroupLayoutDescriptor { - entries: &[BindGroupLayoutEntry { - binding: 0, - visibility: ShaderStages::VERTEX | ShaderStages::FRAGMENT, - ty: BindingType::Buffer { - ty: BufferBindingType::Uniform, - has_dynamic_offset: true, - min_binding_size: Some(ViewUniform::min_size()), - }, - count: None, - }], - label: Some("ui_view_layout"), - }); + let view_layout = render_device.create_bind_group_layout( + "ui_view_layout", + &BindGroupLayoutEntries::single( + ShaderStages::VERTEX_FRAGMENT, + uniform_buffer::(true), + ), + ); UiMaterialPipeline { ui_layout, view_layout, diff --git a/examples/shader/compute_shader_game_of_life.rs b/examples/shader/compute_shader_game_of_life.rs index 2f8a269e592b8..81afe9b662288 100644 --- a/examples/shader/compute_shader_game_of_life.rs +++ b/examples/shader/compute_shader_game_of_life.rs @@ -9,7 +9,7 @@ use bevy::{ extract_resource::{ExtractResource, ExtractResourcePlugin}, render_asset::RenderAssets, render_graph::{self, RenderGraph}, - render_resource::*, + render_resource::{binding_types::texture_storage_2d, *}, renderer::{RenderContext, RenderDevice}, Render, RenderApp, RenderSet, }, @@ -124,22 +124,13 @@ pub struct GameOfLifePipeline { impl FromWorld for GameOfLifePipeline { fn from_world(world: &mut World) -> Self { - let texture_bind_group_layout = - world - .resource::() - .create_bind_group_layout(&BindGroupLayoutDescriptor { - label: None, - entries: &[BindGroupLayoutEntry { - binding: 0, - visibility: ShaderStages::COMPUTE, - ty: BindingType::StorageTexture { - access: StorageTextureAccess::ReadWrite, - format: TextureFormat::Rgba8Unorm, - view_dimension: TextureViewDimension::D2, - }, - count: None, - }], - }); + let texture_bind_group_layout = world.resource::().create_bind_group_layout( + None, + &BindGroupLayoutEntries::single( + ShaderStages::COMPUTE, + texture_storage_2d(TextureFormat::Rgba8Unorm, StorageTextureAccess::ReadWrite), + ), + ); let shader = world .resource::() .load("shaders/game_of_life.wgsl"); diff --git a/examples/shader/post_processing.rs b/examples/shader/post_processing.rs index 39a6c46530b54..9e10f04a81067 100644 --- a/examples/shader/post_processing.rs +++ b/examples/shader/post_processing.rs @@ -20,12 +20,8 @@ use bevy::{ NodeRunError, RenderGraphApp, RenderGraphContext, ViewNode, ViewNodeRunner, }, render_resource::{ - BindGroupEntries, BindGroupLayout, BindGroupLayoutDescriptor, BindGroupLayoutEntry, - BindingType, CachedRenderPipelineId, ColorTargetState, ColorWrites, FragmentState, - MultisampleState, Operations, PipelineCache, PrimitiveState, RenderPassColorAttachment, - RenderPassDescriptor, RenderPipelineDescriptor, Sampler, SamplerBindingType, - SamplerDescriptor, ShaderStages, ShaderType, TextureFormat, TextureSampleType, - TextureViewDimension, + binding_types::{sampler, texture_2d, uniform_buffer}, + *, }, renderer::{RenderContext, RenderDevice}, texture::BevyDefault, @@ -230,40 +226,21 @@ impl FromWorld for PostProcessPipeline { let render_device = world.resource::(); // We need to define the bind group layout used for our pipeline - let layout = render_device.create_bind_group_layout(&BindGroupLayoutDescriptor { - label: Some("post_process_bind_group_layout"), - entries: &[ - // The screen texture - BindGroupLayoutEntry { - binding: 0, - visibility: ShaderStages::FRAGMENT, - ty: BindingType::Texture { - sample_type: TextureSampleType::Float { filterable: true }, - view_dimension: TextureViewDimension::D2, - multisampled: false, - }, - count: None, - }, - // The sampler that will be used to sample the screen texture - BindGroupLayoutEntry { - binding: 1, - visibility: ShaderStages::FRAGMENT, - ty: BindingType::Sampler(SamplerBindingType::Filtering), - count: None, - }, - // The settings uniform that will control the effect - BindGroupLayoutEntry { - binding: 2, - visibility: ShaderStages::FRAGMENT, - ty: BindingType::Buffer { - ty: bevy::render::render_resource::BufferBindingType::Uniform, - has_dynamic_offset: false, - min_binding_size: Some(PostProcessSettings::min_size()), - }, - count: None, - }, - ], - }); + let layout = render_device.create_bind_group_layout( + "post_process_bind_group_layout", + &BindGroupLayoutEntries::sequential( + // The layout entries will only be visible in the fragment stage + ShaderStages::FRAGMENT, + ( + // The screen texture + texture_2d(TextureSampleType::Float { filterable: true }), + // The sampler that will be used to sample the screen texture + sampler(SamplerBindingType::Filtering), + // The settings uniform that will control the effect + uniform_buffer::(false), + ), + ), + ); // We can create the sampler here since it won't change at runtime and doesn't depend on the view let sampler = render_device.create_sampler(&SamplerDescriptor::default());