mirror of
https://github.com/bevyengine/bevy
synced 2024-11-25 14:10:19 +00:00
Add push contant config to layout (#7681)
# Objective Allow for creating pipelines that use push constants. To be able to use push constants. Fixes #4825 As of right now, trying to call `RenderPass::set_push_constants` will trigger the following error: ``` thread 'main' panicked at 'wgpu error: Validation Error Caused by: In a RenderPass note: encoder = `<CommandBuffer-(0, 59, Vulkan)>` In a set_push_constant command provided push constant is for stage(s) VERTEX | FRAGMENT | VERTEX_FRAGMENT, however the pipeline layout has no push constant range for the stage(s) VERTEX | FRAGMENT | VERTEX_FRAGMENT ``` ## Solution Add a field push_constant_ranges to` RenderPipelineDescriptor` and `ComputePipelineDescriptor`. This PR supersedes #4908 which now contains merge conflicts due to significant changes to `bevy_render`. Meanwhile, this PR also made the `layout` field of `RenderPipelineDescriptor` and `ComputePipelineDescriptor` non-optional. If the user do not need to specify the bind group layouts, they can simply supply an empty vector here. No need for it to be optional. --- ## Changelog - Add a field push_constant_ranges to RenderPipelineDescriptor and ComputePipelineDescriptor - Made the `layout` field of RenderPipelineDescriptor and ComputePipelineDescriptor non-optional. ## Migration Guide - Add push_constant_ranges: Vec::new() to every `RenderPipelineDescriptor` and `ComputePipelineDescriptor` - Unwrap the optional values on the `layout` field of `RenderPipelineDescriptor` and `ComputePipelineDescriptor`. If the descriptor has no layout, supply an empty vector. Co-authored-by: Zhixing Zhang <me@neoto.xin>
This commit is contained in:
parent
c5d2d1a5ff
commit
16feb9acb7
17 changed files with 87 additions and 55 deletions
|
@ -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::<Shader>(),
|
||||
|
@ -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::<Shader>(),
|
||||
|
@ -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::<Shader>(),
|
||||
|
@ -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::<Shader>(),
|
||||
|
@ -518,6 +521,7 @@ impl FromWorld for BloomPipelines {
|
|||
primitive: PrimitiveState::default(),
|
||||
depth_stencil: None,
|
||||
multisample: MultisampleState::default(),
|
||||
push_constant_ranges: Vec::new(),
|
||||
});
|
||||
|
||||
BloomPipelines {
|
||||
|
|
|
@ -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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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()),
|
||||
};
|
||||
|
||||
|
|
|
@ -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(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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<Cow<'static, str>>,
|
||||
/// The layout of bind groups for this pipeline.
|
||||
pub layout: Option<Vec<BindGroupLayout>>,
|
||||
pub layout: Vec<BindGroupLayout>,
|
||||
/// The push constant ranges for this pipeline.
|
||||
/// Supply an empty vector if the pipeline doesn't use push constants.
|
||||
pub push_constant_ranges: Vec<PushConstantRange>,
|
||||
/// 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<Cow<'static, str>>,
|
||||
pub layout: Option<Vec<BindGroupLayout>>,
|
||||
pub layout: Vec<BindGroupLayout>,
|
||||
pub push_constant_ranges: Vec<PushConstantRange>,
|
||||
/// The compiled shader module for this stage.
|
||||
pub shader: Handle<Shader>,
|
||||
pub shader_defs: Vec<ShaderDefVal>,
|
||||
|
|
|
@ -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<BindGroupLayoutId>, Vec<PushConstantRange>);
|
||||
#[derive(Default)]
|
||||
struct LayoutCache {
|
||||
layouts: HashMap<Vec<BindGroupLayoutId>, ErasedPipelineLayout>,
|
||||
layouts: HashMap<LayoutCacheKey, ErasedPipelineLayout>,
|
||||
}
|
||||
|
||||
impl LayoutCache {
|
||||
|
@ -308,20 +311,24 @@ impl LayoutCache {
|
|||
&mut self,
|
||||
render_device: &RenderDevice,
|
||||
bind_group_layouts: &[BindGroupLayout],
|
||||
push_constant_ranges: Vec<PushConstantRange>,
|
||||
) -> &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::<Vec<_>>();
|
||||
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::<Vec<_>>();
|
||||
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::<Vec<_>>();
|
||||
|
||||
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 {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -141,14 +141,16 @@ impl FromWorld for GameOfLifePipeline {
|
|||
let pipeline_cache = world.resource::<PipelineCache>();
|
||||
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"),
|
||||
|
|
Loading…
Reference in a new issue