diff --git a/crates/bevy_core_pipeline/src/bloom/mod.rs b/crates/bevy_core_pipeline/src/bloom/mod.rs index e54c1640ed56b..adc8fa632726a 100644 --- a/crates/bevy_core_pipeline/src/bloom/mod.rs +++ b/crates/bevy_core_pipeline/src/bloom/mod.rs @@ -437,7 +437,7 @@ impl FromWorld for BloomPipelines { let downsampling_prefilter_pipeline = pipeline_cache.queue_render_pipeline(RenderPipelineDescriptor { label: Some("bloom_downsampling_prefilter_pipeline".into()), - layout: Some(vec![downsampling_bind_group_layout.clone()]), + layout: vec![downsampling_bind_group_layout.clone()], vertex: fullscreen_shader_vertex_state(), fragment: Some(FragmentState { shader: BLOOM_SHADER_HANDLE.typed::(), @@ -452,12 +452,13 @@ impl FromWorld for BloomPipelines { primitive: PrimitiveState::default(), depth_stencil: None, multisample: MultisampleState::default(), + push_constant_ranges: Vec::new(), }); let downsampling_pipeline = pipeline_cache.queue_render_pipeline(RenderPipelineDescriptor { label: Some("bloom_downsampling_pipeline".into()), - layout: Some(vec![downsampling_bind_group_layout.clone()]), + layout: vec![downsampling_bind_group_layout.clone()], vertex: fullscreen_shader_vertex_state(), fragment: Some(FragmentState { shader: BLOOM_SHADER_HANDLE.typed::(), @@ -472,11 +473,12 @@ impl FromWorld for BloomPipelines { primitive: PrimitiveState::default(), depth_stencil: None, multisample: MultisampleState::default(), + push_constant_ranges: Vec::new(), }); let upsampling_pipeline = pipeline_cache.queue_render_pipeline(RenderPipelineDescriptor { label: Some("bloom_upsampling_pipeline".into()), - layout: Some(vec![upsampling_bind_group_layout.clone()]), + layout: vec![upsampling_bind_group_layout.clone()], vertex: fullscreen_shader_vertex_state(), fragment: Some(FragmentState { shader: BLOOM_SHADER_HANDLE.typed::(), @@ -491,12 +493,13 @@ impl FromWorld for BloomPipelines { primitive: PrimitiveState::default(), depth_stencil: None, multisample: MultisampleState::default(), + push_constant_ranges: Vec::new(), }); let upsampling_final_pipeline = pipeline_cache.queue_render_pipeline(RenderPipelineDescriptor { label: Some("bloom_upsampling_final_pipeline".into()), - layout: Some(vec![downsampling_bind_group_layout.clone()]), + layout: vec![downsampling_bind_group_layout.clone()], vertex: fullscreen_shader_vertex_state(), fragment: Some(FragmentState { shader: BLOOM_SHADER_HANDLE.typed::(), @@ -518,6 +521,7 @@ impl FromWorld for BloomPipelines { primitive: PrimitiveState::default(), depth_stencil: None, multisample: MultisampleState::default(), + push_constant_ranges: Vec::new(), }); BloomPipelines { diff --git a/crates/bevy_core_pipeline/src/fxaa/mod.rs b/crates/bevy_core_pipeline/src/fxaa/mod.rs index ae768d730e6e1..0892299f24fc8 100644 --- a/crates/bevy_core_pipeline/src/fxaa/mod.rs +++ b/crates/bevy_core_pipeline/src/fxaa/mod.rs @@ -194,7 +194,7 @@ impl SpecializedRenderPipeline for FxaaPipeline { fn specialize(&self, key: Self::Key) -> RenderPipelineDescriptor { RenderPipelineDescriptor { label: Some("fxaa".into()), - layout: Some(vec![self.texture_bind_group.clone()]), + layout: vec![self.texture_bind_group.clone()], vertex: fullscreen_shader_vertex_state(), fragment: Some(FragmentState { shader: FXAA_SHADER_HANDLE.typed(), @@ -212,6 +212,7 @@ impl SpecializedRenderPipeline for FxaaPipeline { primitive: PrimitiveState::default(), depth_stencil: None, multisample: MultisampleState::default(), + push_constant_ranges: Vec::new(), } } } diff --git a/crates/bevy_core_pipeline/src/tonemapping/mod.rs b/crates/bevy_core_pipeline/src/tonemapping/mod.rs index bf136f978c2e3..104ff928d130d 100644 --- a/crates/bevy_core_pipeline/src/tonemapping/mod.rs +++ b/crates/bevy_core_pipeline/src/tonemapping/mod.rs @@ -69,7 +69,7 @@ impl SpecializedRenderPipeline for TonemappingPipeline { } RenderPipelineDescriptor { label: Some("tonemapping pipeline".into()), - layout: Some(vec![self.texture_bind_group.clone()]), + layout: vec![self.texture_bind_group.clone()], vertex: fullscreen_shader_vertex_state(), fragment: Some(FragmentState { shader: TONEMAPPING_SHADER_HANDLE.typed(), @@ -84,6 +84,7 @@ impl SpecializedRenderPipeline for TonemappingPipeline { primitive: PrimitiveState::default(), depth_stencil: None, multisample: MultisampleState::default(), + push_constant_ranges: Vec::new(), } } } diff --git a/crates/bevy_core_pipeline/src/upscaling/mod.rs b/crates/bevy_core_pipeline/src/upscaling/mod.rs index b16dacab09c60..c91b5d4664052 100644 --- a/crates/bevy_core_pipeline/src/upscaling/mod.rs +++ b/crates/bevy_core_pipeline/src/upscaling/mod.rs @@ -88,7 +88,7 @@ impl SpecializedRenderPipeline for UpscalingPipeline { fn specialize(&self, key: Self::Key) -> RenderPipelineDescriptor { RenderPipelineDescriptor { label: Some("upscaling pipeline".into()), - layout: Some(vec![self.texture_bind_group.clone()]), + layout: vec![self.texture_bind_group.clone()], vertex: fullscreen_shader_vertex_state(), fragment: Some(FragmentState { shader: UPSCALING_SHADER_HANDLE.typed(), @@ -103,6 +103,7 @@ impl SpecializedRenderPipeline for UpscalingPipeline { primitive: PrimitiveState::default(), depth_stencil: None, multisample: MultisampleState::default(), + push_constant_ranges: Vec::new(), } } } diff --git a/crates/bevy_pbr/src/material.rs b/crates/bevy_pbr/src/material.rs index c6214a7f595a2..82eaac06a8326 100644 --- a/crates/bevy_pbr/src/material.rs +++ b/crates/bevy_pbr/src/material.rs @@ -291,10 +291,7 @@ where descriptor.fragment.as_mut().unwrap().shader = fragment_shader.clone(); } - // MeshPipeline::specialize's current implementation guarantees that the returned - // specialized descriptor has a populated layout - let descriptor_layout = descriptor.layout.as_mut().unwrap(); - descriptor_layout.insert(1, self.material_layout.clone()); + descriptor.layout.insert(1, self.material_layout.clone()); M::specialize(self, &mut descriptor, layout, key)?; Ok(descriptor) diff --git a/crates/bevy_pbr/src/prepass/mod.rs b/crates/bevy_pbr/src/prepass/mod.rs index 222266cda5ec9..4f2d3545b6d72 100644 --- a/crates/bevy_pbr/src/prepass/mod.rs +++ b/crates/bevy_pbr/src/prepass/mod.rs @@ -285,7 +285,7 @@ where buffers: vec![vertex_buffer_layout], }, fragment, - layout: Some(bind_group_layout), + layout: bind_group_layout, primitive: PrimitiveState { topology: key.mesh_key.primitive_topology(), strip_index_format: None, @@ -316,6 +316,7 @@ where mask: !0, alpha_to_coverage_enabled: false, }, + push_constant_ranges: Vec::new(), label: Some("prepass_pipeline".into()), }; diff --git a/crates/bevy_pbr/src/render/light.rs b/crates/bevy_pbr/src/render/light.rs index 545e09e6014ff..440011ac4a0bf 100644 --- a/crates/bevy_pbr/src/render/light.rs +++ b/crates/bevy_pbr/src/render/light.rs @@ -372,7 +372,7 @@ impl SpecializedMeshPipeline for ShadowPipeline { buffers: vec![vertex_buffer_layout], }, fragment: None, - layout: Some(bind_group_layout), + layout: bind_group_layout, primitive: PrimitiveState { topology: key.primitive_topology(), strip_index_format: None, @@ -400,6 +400,7 @@ impl SpecializedMeshPipeline for ShadowPipeline { }), multisample: MultisampleState::default(), label: Some("shadow_pipeline".into()), + push_constant_ranges: Vec::new(), }) } } diff --git a/crates/bevy_pbr/src/render/mesh.rs b/crates/bevy_pbr/src/render/mesh.rs index e69477df7e87c..34350740d58cc 100644 --- a/crates/bevy_pbr/src/render/mesh.rs +++ b/crates/bevy_pbr/src/render/mesh.rs @@ -776,7 +776,8 @@ impl SpecializedMeshPipeline for MeshPipeline { write_mask: ColorWrites::ALL, })], }), - layout: Some(bind_group_layout), + layout: bind_group_layout, + push_constant_ranges: Vec::new(), primitive: PrimitiveState { front_face: FrontFace::Ccw, cull_mode: Some(Face::Back), diff --git a/crates/bevy_render/src/render_resource/mod.rs b/crates/bevy_render/src/render_resource/mod.rs index 33a010ff502d1..91440cf55c276 100644 --- a/crates/bevy_render/src/render_resource/mod.rs +++ b/crates/bevy_render/src/render_resource/mod.rs @@ -35,14 +35,14 @@ pub use wgpu::{ FrontFace, ImageCopyBuffer, ImageCopyBufferBase, ImageCopyTexture, ImageCopyTextureBase, ImageDataLayout, ImageSubresourceRange, IndexFormat, Limits as WgpuLimits, LoadOp, MapMode, MultisampleState, Operations, Origin3d, PipelineLayout, PipelineLayoutDescriptor, PolygonMode, - PrimitiveState, PrimitiveTopology, RenderPassColorAttachment, RenderPassDepthStencilAttachment, - RenderPassDescriptor, RenderPipelineDescriptor as RawRenderPipelineDescriptor, - SamplerBindingType, SamplerDescriptor, ShaderModule, ShaderModuleDescriptor, ShaderSource, - ShaderStages, StencilFaceState, StencilOperation, StencilState, StorageTextureAccess, - TextureAspect, TextureDescriptor, TextureDimension, TextureFormat, TextureSampleType, - TextureUsages, TextureViewDescriptor, TextureViewDimension, VertexAttribute, - VertexBufferLayout as RawVertexBufferLayout, VertexFormat, VertexState as RawVertexState, - VertexStepMode, + PrimitiveState, PrimitiveTopology, PushConstantRange, RenderPassColorAttachment, + RenderPassDepthStencilAttachment, RenderPassDescriptor, + RenderPipelineDescriptor as RawRenderPipelineDescriptor, SamplerBindingType, SamplerDescriptor, + ShaderModule, ShaderModuleDescriptor, ShaderSource, ShaderStages, StencilFaceState, + StencilOperation, StencilState, StorageTextureAccess, TextureAspect, TextureDescriptor, + TextureDimension, TextureFormat, TextureSampleType, TextureUsages, TextureViewDescriptor, + TextureViewDimension, VertexAttribute, VertexBufferLayout as RawVertexBufferLayout, + VertexFormat, VertexState as RawVertexState, VertexStepMode, }; pub mod encase { diff --git a/crates/bevy_render/src/render_resource/pipeline.rs b/crates/bevy_render/src/render_resource/pipeline.rs index edd3d8f6d67cb..8eafdaf2892a9 100644 --- a/crates/bevy_render/src/render_resource/pipeline.rs +++ b/crates/bevy_render/src/render_resource/pipeline.rs @@ -7,7 +7,7 @@ use bevy_asset::Handle; use std::{borrow::Cow, ops::Deref}; use wgpu::{ BufferAddress, ColorTargetState, DepthStencilState, MultisampleState, PrimitiveState, - VertexAttribute, VertexFormat, VertexStepMode, + PushConstantRange, VertexAttribute, VertexFormat, VertexStepMode, }; define_atomic_id!(RenderPipelineId); @@ -93,7 +93,10 @@ pub struct RenderPipelineDescriptor { /// Debug label of the pipeline. This will show up in graphics debuggers for easy identification. pub label: Option>, /// The layout of bind groups for this pipeline. - pub layout: Option>, + pub layout: Vec, + /// The push constant ranges for this pipeline. + /// Supply an empty vector if the pipeline doesn't use push constants. + pub push_constant_ranges: Vec, /// The compiled vertex stage, its entry point, and the input buffers layout. pub vertex: VertexState, /// The properties of the pipeline at the primitive assembly and rasterization level. @@ -174,7 +177,8 @@ pub struct FragmentState { #[derive(Clone, Debug)] pub struct ComputePipelineDescriptor { pub label: Option>, - pub layout: Option>, + pub layout: Vec, + pub push_constant_ranges: Vec, /// The compiled shader module for this stage. pub shader: Handle, pub shader_defs: Vec, diff --git a/crates/bevy_render/src/render_resource/pipeline_cache.rs b/crates/bevy_render/src/render_resource/pipeline_cache.rs index a7ff531ccdab4..2dfe94913c1bb 100644 --- a/crates/bevy_render/src/render_resource/pipeline_cache.rs +++ b/crates/bevy_render/src/render_resource/pipeline_cache.rs @@ -20,7 +20,9 @@ use bevy_utils::{ use parking_lot::Mutex; use std::{hash::Hash, iter::FusedIterator, mem, ops::Deref}; use thiserror::Error; -use wgpu::{PipelineLayoutDescriptor, VertexBufferLayout as RawVertexBufferLayout}; +use wgpu::{ + PipelineLayoutDescriptor, PushConstantRange, VertexBufferLayout as RawVertexBufferLayout, +}; use crate::render_resource::resource_macros::*; @@ -298,9 +300,10 @@ impl ShaderCache { } } +type LayoutCacheKey = (Vec, Vec); #[derive(Default)] struct LayoutCache { - layouts: HashMap, ErasedPipelineLayout>, + layouts: HashMap, } impl LayoutCache { @@ -308,20 +311,24 @@ impl LayoutCache { &mut self, render_device: &RenderDevice, bind_group_layouts: &[BindGroupLayout], + push_constant_ranges: Vec, ) -> &wgpu::PipelineLayout { - let key = bind_group_layouts.iter().map(|l| l.id()).collect(); - self.layouts.entry(key).or_insert_with(|| { - let bind_group_layouts = bind_group_layouts - .iter() - .map(|l| l.value()) - .collect::>(); - ErasedPipelineLayout::new(render_device.create_pipeline_layout( - &PipelineLayoutDescriptor { - bind_group_layouts: &bind_group_layouts, - ..default() - }, - )) - }) + let bind_group_ids = bind_group_layouts.iter().map(|l| l.id()).collect(); + self.layouts + .entry((bind_group_ids, push_constant_ranges)) + .or_insert_with_key(|(_, push_constant_ranges)| { + let bind_group_layouts = bind_group_layouts + .iter() + .map(|l| l.value()) + .collect::>(); + ErasedPipelineLayout::new(render_device.create_pipeline_layout( + &PipelineLayoutDescriptor { + bind_group_layouts: &bind_group_layouts, + push_constant_ranges, + ..default() + }, + )) + }) } } @@ -561,10 +568,14 @@ impl PipelineCache { }) .collect::>(); - let layout = if let Some(layout) = &descriptor.layout { - Some(self.layout_cache.get(&self.device, layout)) - } else { + let layout = if descriptor.layout.is_empty() && descriptor.push_constant_ranges.is_empty() { None + } else { + Some(self.layout_cache.get( + &self.device, + &descriptor.layout, + descriptor.push_constant_ranges.to_vec(), + )) }; let descriptor = RawRenderPipelineDescriptor { @@ -610,10 +621,14 @@ impl PipelineCache { } }; - let layout = if let Some(layout) = &descriptor.layout { - Some(self.layout_cache.get(&self.device, layout)) - } else { + let layout = if descriptor.layout.is_empty() && descriptor.push_constant_ranges.is_empty() { None + } else { + Some(self.layout_cache.get( + &self.device, + &descriptor.layout, + descriptor.push_constant_ranges.to_vec(), + )) }; let descriptor = RawComputePipelineDescriptor { diff --git a/crates/bevy_sprite/src/mesh2d/material.rs b/crates/bevy_sprite/src/mesh2d/material.rs index a48a72a8305ec..1ae7252a17884 100644 --- a/crates/bevy_sprite/src/mesh2d/material.rs +++ b/crates/bevy_sprite/src/mesh2d/material.rs @@ -248,11 +248,11 @@ where if let Some(fragment_shader) = &self.fragment_shader { descriptor.fragment.as_mut().unwrap().shader = fragment_shader.clone(); } - descriptor.layout = Some(vec![ + descriptor.layout = vec![ self.mesh2d_pipeline.view_layout.clone(), self.material2d_layout.clone(), self.mesh2d_pipeline.mesh_layout.clone(), - ]); + ]; M::specialize(&mut descriptor, layout, key)?; Ok(descriptor) diff --git a/crates/bevy_sprite/src/mesh2d/mesh.rs b/crates/bevy_sprite/src/mesh2d/mesh.rs index bac4c9e937dc9..c46ef1d883669 100644 --- a/crates/bevy_sprite/src/mesh2d/mesh.rs +++ b/crates/bevy_sprite/src/mesh2d/mesh.rs @@ -409,7 +409,8 @@ impl SpecializedMeshPipeline for Mesh2dPipeline { write_mask: ColorWrites::ALL, })], }), - layout: Some(vec![self.view_layout.clone(), self.mesh_layout.clone()]), + layout: vec![self.view_layout.clone(), self.mesh_layout.clone()], + push_constant_ranges: Vec::new(), primitive: PrimitiveState { front_face: FrontFace::Ccw, cull_mode: None, diff --git a/crates/bevy_sprite/src/render/mod.rs b/crates/bevy_sprite/src/render/mod.rs index 74bcde4bcc1e4..301ab2376c552 100644 --- a/crates/bevy_sprite/src/render/mod.rs +++ b/crates/bevy_sprite/src/render/mod.rs @@ -246,7 +246,7 @@ impl SpecializedRenderPipeline for SpritePipeline { write_mask: ColorWrites::ALL, })], }), - layout: Some(vec![self.view_layout.clone(), self.material_layout.clone()]), + layout: vec![self.view_layout.clone(), self.material_layout.clone()], primitive: PrimitiveState { front_face: FrontFace::Ccw, cull_mode: None, @@ -263,6 +263,7 @@ impl SpecializedRenderPipeline for SpritePipeline { alpha_to_coverage_enabled: false, }, label: Some("sprite_pipeline".into()), + push_constant_ranges: Vec::new(), } } } diff --git a/crates/bevy_ui/src/render/pipeline.rs b/crates/bevy_ui/src/render/pipeline.rs index 1a86d577ab417..84cc74d11ebd7 100644 --- a/crates/bevy_ui/src/render/pipeline.rs +++ b/crates/bevy_ui/src/render/pipeline.rs @@ -102,7 +102,8 @@ impl SpecializedRenderPipeline for UiPipeline { write_mask: ColorWrites::ALL, })], }), - layout: Some(vec![self.view_layout.clone(), self.image_layout.clone()]), + layout: vec![self.view_layout.clone(), self.image_layout.clone()], + push_constant_ranges: Vec::new(), primitive: PrimitiveState { front_face: FrontFace::Ccw, cull_mode: None, diff --git a/examples/2d/mesh2d_manual.rs b/examples/2d/mesh2d_manual.rs index ad13cfd3a9a4a..9abf564e4f887 100644 --- a/examples/2d/mesh2d_manual.rs +++ b/examples/2d/mesh2d_manual.rs @@ -172,12 +172,13 @@ impl SpecializedRenderPipeline for ColoredMesh2dPipeline { })], }), // Use the two standard uniforms for 2d meshes - layout: Some(vec![ + layout: vec![ // Bind group 0 is the view uniform self.mesh2d_pipeline.view_layout.clone(), // Bind group 1 is the mesh uniform self.mesh2d_pipeline.mesh_layout.clone(), - ]), + ], + push_constant_ranges: Vec::new(), primitive: PrimitiveState { front_face: FrontFace::Ccw, cull_mode: Some(Face::Back), diff --git a/examples/shader/compute_shader_game_of_life.rs b/examples/shader/compute_shader_game_of_life.rs index 7e94820028604..736e0b3f11e59 100644 --- a/examples/shader/compute_shader_game_of_life.rs +++ b/examples/shader/compute_shader_game_of_life.rs @@ -141,14 +141,16 @@ impl FromWorld for GameOfLifePipeline { let pipeline_cache = world.resource::(); let init_pipeline = pipeline_cache.queue_compute_pipeline(ComputePipelineDescriptor { label: None, - layout: Some(vec![texture_bind_group_layout.clone()]), + layout: vec![texture_bind_group_layout.clone()], + push_constant_ranges: Vec::new(), shader: shader.clone(), shader_defs: vec![], entry_point: Cow::from("init"), }); let update_pipeline = pipeline_cache.queue_compute_pipeline(ComputePipelineDescriptor { label: None, - layout: Some(vec![texture_bind_group_layout.clone()]), + layout: vec![texture_bind_group_layout.clone()], + push_constant_ranges: Vec::new(), shader, shader_defs: vec![], entry_point: Cow::from("update"),