Skip to content

Commit 16feb9a

Browse files
committed
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 <[email protected]>
1 parent c5d2d1a commit 16feb9a

File tree

17 files changed

+87
-55
lines changed

17 files changed

+87
-55
lines changed

crates/bevy_core_pipeline/src/bloom/mod.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -437,7 +437,7 @@ impl FromWorld for BloomPipelines {
437437
let downsampling_prefilter_pipeline =
438438
pipeline_cache.queue_render_pipeline(RenderPipelineDescriptor {
439439
label: Some("bloom_downsampling_prefilter_pipeline".into()),
440-
layout: Some(vec![downsampling_bind_group_layout.clone()]),
440+
layout: vec![downsampling_bind_group_layout.clone()],
441441
vertex: fullscreen_shader_vertex_state(),
442442
fragment: Some(FragmentState {
443443
shader: BLOOM_SHADER_HANDLE.typed::<Shader>(),
@@ -452,12 +452,13 @@ impl FromWorld for BloomPipelines {
452452
primitive: PrimitiveState::default(),
453453
depth_stencil: None,
454454
multisample: MultisampleState::default(),
455+
push_constant_ranges: Vec::new(),
455456
});
456457

457458
let downsampling_pipeline =
458459
pipeline_cache.queue_render_pipeline(RenderPipelineDescriptor {
459460
label: Some("bloom_downsampling_pipeline".into()),
460-
layout: Some(vec![downsampling_bind_group_layout.clone()]),
461+
layout: vec![downsampling_bind_group_layout.clone()],
461462
vertex: fullscreen_shader_vertex_state(),
462463
fragment: Some(FragmentState {
463464
shader: BLOOM_SHADER_HANDLE.typed::<Shader>(),
@@ -472,11 +473,12 @@ impl FromWorld for BloomPipelines {
472473
primitive: PrimitiveState::default(),
473474
depth_stencil: None,
474475
multisample: MultisampleState::default(),
476+
push_constant_ranges: Vec::new(),
475477
});
476478

477479
let upsampling_pipeline = pipeline_cache.queue_render_pipeline(RenderPipelineDescriptor {
478480
label: Some("bloom_upsampling_pipeline".into()),
479-
layout: Some(vec![upsampling_bind_group_layout.clone()]),
481+
layout: vec![upsampling_bind_group_layout.clone()],
480482
vertex: fullscreen_shader_vertex_state(),
481483
fragment: Some(FragmentState {
482484
shader: BLOOM_SHADER_HANDLE.typed::<Shader>(),
@@ -491,12 +493,13 @@ impl FromWorld for BloomPipelines {
491493
primitive: PrimitiveState::default(),
492494
depth_stencil: None,
493495
multisample: MultisampleState::default(),
496+
push_constant_ranges: Vec::new(),
494497
});
495498

496499
let upsampling_final_pipeline =
497500
pipeline_cache.queue_render_pipeline(RenderPipelineDescriptor {
498501
label: Some("bloom_upsampling_final_pipeline".into()),
499-
layout: Some(vec![downsampling_bind_group_layout.clone()]),
502+
layout: vec![downsampling_bind_group_layout.clone()],
500503
vertex: fullscreen_shader_vertex_state(),
501504
fragment: Some(FragmentState {
502505
shader: BLOOM_SHADER_HANDLE.typed::<Shader>(),
@@ -518,6 +521,7 @@ impl FromWorld for BloomPipelines {
518521
primitive: PrimitiveState::default(),
519522
depth_stencil: None,
520523
multisample: MultisampleState::default(),
524+
push_constant_ranges: Vec::new(),
521525
});
522526

523527
BloomPipelines {

crates/bevy_core_pipeline/src/fxaa/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ impl SpecializedRenderPipeline for FxaaPipeline {
194194
fn specialize(&self, key: Self::Key) -> RenderPipelineDescriptor {
195195
RenderPipelineDescriptor {
196196
label: Some("fxaa".into()),
197-
layout: Some(vec![self.texture_bind_group.clone()]),
197+
layout: vec![self.texture_bind_group.clone()],
198198
vertex: fullscreen_shader_vertex_state(),
199199
fragment: Some(FragmentState {
200200
shader: FXAA_SHADER_HANDLE.typed(),
@@ -212,6 +212,7 @@ impl SpecializedRenderPipeline for FxaaPipeline {
212212
primitive: PrimitiveState::default(),
213213
depth_stencil: None,
214214
multisample: MultisampleState::default(),
215+
push_constant_ranges: Vec::new(),
215216
}
216217
}
217218
}

crates/bevy_core_pipeline/src/tonemapping/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ impl SpecializedRenderPipeline for TonemappingPipeline {
6969
}
7070
RenderPipelineDescriptor {
7171
label: Some("tonemapping pipeline".into()),
72-
layout: Some(vec![self.texture_bind_group.clone()]),
72+
layout: vec![self.texture_bind_group.clone()],
7373
vertex: fullscreen_shader_vertex_state(),
7474
fragment: Some(FragmentState {
7575
shader: TONEMAPPING_SHADER_HANDLE.typed(),
@@ -84,6 +84,7 @@ impl SpecializedRenderPipeline for TonemappingPipeline {
8484
primitive: PrimitiveState::default(),
8585
depth_stencil: None,
8686
multisample: MultisampleState::default(),
87+
push_constant_ranges: Vec::new(),
8788
}
8889
}
8990
}

crates/bevy_core_pipeline/src/upscaling/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ impl SpecializedRenderPipeline for UpscalingPipeline {
8888
fn specialize(&self, key: Self::Key) -> RenderPipelineDescriptor {
8989
RenderPipelineDescriptor {
9090
label: Some("upscaling pipeline".into()),
91-
layout: Some(vec![self.texture_bind_group.clone()]),
91+
layout: vec![self.texture_bind_group.clone()],
9292
vertex: fullscreen_shader_vertex_state(),
9393
fragment: Some(FragmentState {
9494
shader: UPSCALING_SHADER_HANDLE.typed(),
@@ -103,6 +103,7 @@ impl SpecializedRenderPipeline for UpscalingPipeline {
103103
primitive: PrimitiveState::default(),
104104
depth_stencil: None,
105105
multisample: MultisampleState::default(),
106+
push_constant_ranges: Vec::new(),
106107
}
107108
}
108109
}

crates/bevy_pbr/src/material.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -291,10 +291,7 @@ where
291291
descriptor.fragment.as_mut().unwrap().shader = fragment_shader.clone();
292292
}
293293

294-
// MeshPipeline::specialize's current implementation guarantees that the returned
295-
// specialized descriptor has a populated layout
296-
let descriptor_layout = descriptor.layout.as_mut().unwrap();
297-
descriptor_layout.insert(1, self.material_layout.clone());
294+
descriptor.layout.insert(1, self.material_layout.clone());
298295

299296
M::specialize(self, &mut descriptor, layout, key)?;
300297
Ok(descriptor)

crates/bevy_pbr/src/prepass/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,7 @@ where
285285
buffers: vec![vertex_buffer_layout],
286286
},
287287
fragment,
288-
layout: Some(bind_group_layout),
288+
layout: bind_group_layout,
289289
primitive: PrimitiveState {
290290
topology: key.mesh_key.primitive_topology(),
291291
strip_index_format: None,
@@ -316,6 +316,7 @@ where
316316
mask: !0,
317317
alpha_to_coverage_enabled: false,
318318
},
319+
push_constant_ranges: Vec::new(),
319320
label: Some("prepass_pipeline".into()),
320321
};
321322

crates/bevy_pbr/src/render/light.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -372,7 +372,7 @@ impl SpecializedMeshPipeline for ShadowPipeline {
372372
buffers: vec![vertex_buffer_layout],
373373
},
374374
fragment: None,
375-
layout: Some(bind_group_layout),
375+
layout: bind_group_layout,
376376
primitive: PrimitiveState {
377377
topology: key.primitive_topology(),
378378
strip_index_format: None,
@@ -400,6 +400,7 @@ impl SpecializedMeshPipeline for ShadowPipeline {
400400
}),
401401
multisample: MultisampleState::default(),
402402
label: Some("shadow_pipeline".into()),
403+
push_constant_ranges: Vec::new(),
403404
})
404405
}
405406
}

crates/bevy_pbr/src/render/mesh.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -776,7 +776,8 @@ impl SpecializedMeshPipeline for MeshPipeline {
776776
write_mask: ColorWrites::ALL,
777777
})],
778778
}),
779-
layout: Some(bind_group_layout),
779+
layout: bind_group_layout,
780+
push_constant_ranges: Vec::new(),
780781
primitive: PrimitiveState {
781782
front_face: FrontFace::Ccw,
782783
cull_mode: Some(Face::Back),

crates/bevy_render/src/render_resource/mod.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,14 @@ pub use wgpu::{
3535
FrontFace, ImageCopyBuffer, ImageCopyBufferBase, ImageCopyTexture, ImageCopyTextureBase,
3636
ImageDataLayout, ImageSubresourceRange, IndexFormat, Limits as WgpuLimits, LoadOp, MapMode,
3737
MultisampleState, Operations, Origin3d, PipelineLayout, PipelineLayoutDescriptor, PolygonMode,
38-
PrimitiveState, PrimitiveTopology, RenderPassColorAttachment, RenderPassDepthStencilAttachment,
39-
RenderPassDescriptor, RenderPipelineDescriptor as RawRenderPipelineDescriptor,
40-
SamplerBindingType, SamplerDescriptor, ShaderModule, ShaderModuleDescriptor, ShaderSource,
41-
ShaderStages, StencilFaceState, StencilOperation, StencilState, StorageTextureAccess,
42-
TextureAspect, TextureDescriptor, TextureDimension, TextureFormat, TextureSampleType,
43-
TextureUsages, TextureViewDescriptor, TextureViewDimension, VertexAttribute,
44-
VertexBufferLayout as RawVertexBufferLayout, VertexFormat, VertexState as RawVertexState,
45-
VertexStepMode,
38+
PrimitiveState, PrimitiveTopology, PushConstantRange, RenderPassColorAttachment,
39+
RenderPassDepthStencilAttachment, RenderPassDescriptor,
40+
RenderPipelineDescriptor as RawRenderPipelineDescriptor, SamplerBindingType, SamplerDescriptor,
41+
ShaderModule, ShaderModuleDescriptor, ShaderSource, ShaderStages, StencilFaceState,
42+
StencilOperation, StencilState, StorageTextureAccess, TextureAspect, TextureDescriptor,
43+
TextureDimension, TextureFormat, TextureSampleType, TextureUsages, TextureViewDescriptor,
44+
TextureViewDimension, VertexAttribute, VertexBufferLayout as RawVertexBufferLayout,
45+
VertexFormat, VertexState as RawVertexState, VertexStepMode,
4646
};
4747

4848
pub mod encase {

crates/bevy_render/src/render_resource/pipeline.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use bevy_asset::Handle;
77
use std::{borrow::Cow, ops::Deref};
88
use wgpu::{
99
BufferAddress, ColorTargetState, DepthStencilState, MultisampleState, PrimitiveState,
10-
VertexAttribute, VertexFormat, VertexStepMode,
10+
PushConstantRange, VertexAttribute, VertexFormat, VertexStepMode,
1111
};
1212

1313
define_atomic_id!(RenderPipelineId);
@@ -93,7 +93,10 @@ pub struct RenderPipelineDescriptor {
9393
/// Debug label of the pipeline. This will show up in graphics debuggers for easy identification.
9494
pub label: Option<Cow<'static, str>>,
9595
/// The layout of bind groups for this pipeline.
96-
pub layout: Option<Vec<BindGroupLayout>>,
96+
pub layout: Vec<BindGroupLayout>,
97+
/// The push constant ranges for this pipeline.
98+
/// Supply an empty vector if the pipeline doesn't use push constants.
99+
pub push_constant_ranges: Vec<PushConstantRange>,
97100
/// The compiled vertex stage, its entry point, and the input buffers layout.
98101
pub vertex: VertexState,
99102
/// The properties of the pipeline at the primitive assembly and rasterization level.
@@ -174,7 +177,8 @@ pub struct FragmentState {
174177
#[derive(Clone, Debug)]
175178
pub struct ComputePipelineDescriptor {
176179
pub label: Option<Cow<'static, str>>,
177-
pub layout: Option<Vec<BindGroupLayout>>,
180+
pub layout: Vec<BindGroupLayout>,
181+
pub push_constant_ranges: Vec<PushConstantRange>,
178182
/// The compiled shader module for this stage.
179183
pub shader: Handle<Shader>,
180184
pub shader_defs: Vec<ShaderDefVal>,

crates/bevy_render/src/render_resource/pipeline_cache.rs

Lines changed: 36 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@ use bevy_utils::{
2020
use parking_lot::Mutex;
2121
use std::{hash::Hash, iter::FusedIterator, mem, ops::Deref};
2222
use thiserror::Error;
23-
use wgpu::{PipelineLayoutDescriptor, VertexBufferLayout as RawVertexBufferLayout};
23+
use wgpu::{
24+
PipelineLayoutDescriptor, PushConstantRange, VertexBufferLayout as RawVertexBufferLayout,
25+
};
2426

2527
use crate::render_resource::resource_macros::*;
2628

@@ -298,30 +300,35 @@ impl ShaderCache {
298300
}
299301
}
300302

303+
type LayoutCacheKey = (Vec<BindGroupLayoutId>, Vec<PushConstantRange>);
301304
#[derive(Default)]
302305
struct LayoutCache {
303-
layouts: HashMap<Vec<BindGroupLayoutId>, ErasedPipelineLayout>,
306+
layouts: HashMap<LayoutCacheKey, ErasedPipelineLayout>,
304307
}
305308

306309
impl LayoutCache {
307310
fn get(
308311
&mut self,
309312
render_device: &RenderDevice,
310313
bind_group_layouts: &[BindGroupLayout],
314+
push_constant_ranges: Vec<PushConstantRange>,
311315
) -> &wgpu::PipelineLayout {
312-
let key = bind_group_layouts.iter().map(|l| l.id()).collect();
313-
self.layouts.entry(key).or_insert_with(|| {
314-
let bind_group_layouts = bind_group_layouts
315-
.iter()
316-
.map(|l| l.value())
317-
.collect::<Vec<_>>();
318-
ErasedPipelineLayout::new(render_device.create_pipeline_layout(
319-
&PipelineLayoutDescriptor {
320-
bind_group_layouts: &bind_group_layouts,
321-
..default()
322-
},
323-
))
324-
})
316+
let bind_group_ids = bind_group_layouts.iter().map(|l| l.id()).collect();
317+
self.layouts
318+
.entry((bind_group_ids, push_constant_ranges))
319+
.or_insert_with_key(|(_, push_constant_ranges)| {
320+
let bind_group_layouts = bind_group_layouts
321+
.iter()
322+
.map(|l| l.value())
323+
.collect::<Vec<_>>();
324+
ErasedPipelineLayout::new(render_device.create_pipeline_layout(
325+
&PipelineLayoutDescriptor {
326+
bind_group_layouts: &bind_group_layouts,
327+
push_constant_ranges,
328+
..default()
329+
},
330+
))
331+
})
325332
}
326333
}
327334

@@ -561,10 +568,14 @@ impl PipelineCache {
561568
})
562569
.collect::<Vec<_>>();
563570

564-
let layout = if let Some(layout) = &descriptor.layout {
565-
Some(self.layout_cache.get(&self.device, layout))
566-
} else {
571+
let layout = if descriptor.layout.is_empty() && descriptor.push_constant_ranges.is_empty() {
567572
None
573+
} else {
574+
Some(self.layout_cache.get(
575+
&self.device,
576+
&descriptor.layout,
577+
descriptor.push_constant_ranges.to_vec(),
578+
))
568579
};
569580

570581
let descriptor = RawRenderPipelineDescriptor {
@@ -610,10 +621,14 @@ impl PipelineCache {
610621
}
611622
};
612623

613-
let layout = if let Some(layout) = &descriptor.layout {
614-
Some(self.layout_cache.get(&self.device, layout))
615-
} else {
624+
let layout = if descriptor.layout.is_empty() && descriptor.push_constant_ranges.is_empty() {
616625
None
626+
} else {
627+
Some(self.layout_cache.get(
628+
&self.device,
629+
&descriptor.layout,
630+
descriptor.push_constant_ranges.to_vec(),
631+
))
617632
};
618633

619634
let descriptor = RawComputePipelineDescriptor {

crates/bevy_sprite/src/mesh2d/material.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -248,11 +248,11 @@ where
248248
if let Some(fragment_shader) = &self.fragment_shader {
249249
descriptor.fragment.as_mut().unwrap().shader = fragment_shader.clone();
250250
}
251-
descriptor.layout = Some(vec![
251+
descriptor.layout = vec![
252252
self.mesh2d_pipeline.view_layout.clone(),
253253
self.material2d_layout.clone(),
254254
self.mesh2d_pipeline.mesh_layout.clone(),
255-
]);
255+
];
256256

257257
M::specialize(&mut descriptor, layout, key)?;
258258
Ok(descriptor)

crates/bevy_sprite/src/mesh2d/mesh.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -409,7 +409,8 @@ impl SpecializedMeshPipeline for Mesh2dPipeline {
409409
write_mask: ColorWrites::ALL,
410410
})],
411411
}),
412-
layout: Some(vec![self.view_layout.clone(), self.mesh_layout.clone()]),
412+
layout: vec![self.view_layout.clone(), self.mesh_layout.clone()],
413+
push_constant_ranges: Vec::new(),
413414
primitive: PrimitiveState {
414415
front_face: FrontFace::Ccw,
415416
cull_mode: None,

crates/bevy_sprite/src/render/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ impl SpecializedRenderPipeline for SpritePipeline {
246246
write_mask: ColorWrites::ALL,
247247
})],
248248
}),
249-
layout: Some(vec![self.view_layout.clone(), self.material_layout.clone()]),
249+
layout: vec![self.view_layout.clone(), self.material_layout.clone()],
250250
primitive: PrimitiveState {
251251
front_face: FrontFace::Ccw,
252252
cull_mode: None,
@@ -263,6 +263,7 @@ impl SpecializedRenderPipeline for SpritePipeline {
263263
alpha_to_coverage_enabled: false,
264264
},
265265
label: Some("sprite_pipeline".into()),
266+
push_constant_ranges: Vec::new(),
266267
}
267268
}
268269
}

crates/bevy_ui/src/render/pipeline.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,8 @@ impl SpecializedRenderPipeline for UiPipeline {
102102
write_mask: ColorWrites::ALL,
103103
})],
104104
}),
105-
layout: Some(vec![self.view_layout.clone(), self.image_layout.clone()]),
105+
layout: vec![self.view_layout.clone(), self.image_layout.clone()],
106+
push_constant_ranges: Vec::new(),
106107
primitive: PrimitiveState {
107108
front_face: FrontFace::Ccw,
108109
cull_mode: None,

examples/2d/mesh2d_manual.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -172,12 +172,13 @@ impl SpecializedRenderPipeline for ColoredMesh2dPipeline {
172172
})],
173173
}),
174174
// Use the two standard uniforms for 2d meshes
175-
layout: Some(vec![
175+
layout: vec![
176176
// Bind group 0 is the view uniform
177177
self.mesh2d_pipeline.view_layout.clone(),
178178
// Bind group 1 is the mesh uniform
179179
self.mesh2d_pipeline.mesh_layout.clone(),
180-
]),
180+
],
181+
push_constant_ranges: Vec::new(),
181182
primitive: PrimitiveState {
182183
front_face: FrontFace::Ccw,
183184
cull_mode: Some(Face::Back),

0 commit comments

Comments
 (0)