Make PipelineCache internally mutable. (#7205)
# Objective - Allow rendering queue systems to use a `Res<PipelineCache>` even for queueing up new rendering pipelines. This is part of unblocking parallel execution queue systems. ## Solution - Make `PipelineCache` internally mutable w.r.t to queueing new pipelines. Pipelines are no longer immediately updated into the cache state, but rather queued into a Vec. The Vec of pending new pipelines is then later processed at the same time we actually create the queued pipelines on the GPU device. --- ## Changelog `PipelineCache` no longer requires mutable access in order to queue render / compute pipelines. ## Migration Guide * Most usages of `resource_mut::<PipelineCache>` and `ResMut<PipelineCache>` can be changed to `resource::<PipelineCache>` and `Res<PipelineCache>` as long as they don't use any methods requiring mutability - the only public method requiring it is `process_queue`.
This commit is contained in:
parent
4b326fb4ca
commit
517deda215
@ -434,7 +434,7 @@ impl FromWorld for BloomPipelines {
|
||||
],
|
||||
});
|
||||
|
||||
let mut pipeline_cache = world.resource_mut::<PipelineCache>();
|
||||
let pipeline_cache = world.resource::<PipelineCache>();
|
||||
|
||||
let downsampling_prefilter_pipeline =
|
||||
pipeline_cache.queue_render_pipeline(RenderPipelineDescriptor {
|
||||
|
||||
@ -223,7 +223,7 @@ impl SpecializedRenderPipeline for FxaaPipeline {
|
||||
|
||||
pub fn prepare_fxaa_pipelines(
|
||||
mut commands: Commands,
|
||||
mut pipeline_cache: ResMut<PipelineCache>,
|
||||
pipeline_cache: Res<PipelineCache>,
|
||||
mut pipelines: ResMut<SpecializedRenderPipelines<FxaaPipeline>>,
|
||||
fxaa_pipeline: Res<FxaaPipeline>,
|
||||
views: Query<(Entity, &ExtractedView, &Fxaa)>,
|
||||
@ -233,7 +233,7 @@ pub fn prepare_fxaa_pipelines(
|
||||
continue;
|
||||
}
|
||||
let pipeline_id = pipelines.specialize(
|
||||
&mut pipeline_cache,
|
||||
&pipeline_cache,
|
||||
&fxaa_pipeline,
|
||||
FxaaPipelineKey {
|
||||
edge_threshold: fxaa.edge_threshold,
|
||||
|
||||
@ -126,7 +126,7 @@ pub struct ViewTonemappingPipeline(CachedRenderPipelineId);
|
||||
|
||||
pub fn queue_view_tonemapping_pipelines(
|
||||
mut commands: Commands,
|
||||
mut pipeline_cache: ResMut<PipelineCache>,
|
||||
pipeline_cache: Res<PipelineCache>,
|
||||
mut pipelines: ResMut<SpecializedRenderPipelines<TonemappingPipeline>>,
|
||||
upscaling_pipeline: Res<TonemappingPipeline>,
|
||||
view_targets: Query<(Entity, &Tonemapping)>,
|
||||
@ -136,7 +136,7 @@ pub fn queue_view_tonemapping_pipelines(
|
||||
let key = TonemappingPipelineKey {
|
||||
deband_dither: *deband_dither,
|
||||
};
|
||||
let pipeline = pipelines.specialize(&mut pipeline_cache, &upscaling_pipeline, key);
|
||||
let pipeline = pipelines.specialize(&pipeline_cache, &upscaling_pipeline, key);
|
||||
|
||||
commands
|
||||
.entity(entity)
|
||||
|
||||
@ -112,7 +112,7 @@ pub struct ViewUpscalingPipeline(CachedRenderPipelineId);
|
||||
|
||||
fn queue_view_upscaling_pipelines(
|
||||
mut commands: Commands,
|
||||
mut pipeline_cache: ResMut<PipelineCache>,
|
||||
pipeline_cache: Res<PipelineCache>,
|
||||
mut pipelines: ResMut<SpecializedRenderPipelines<UpscalingPipeline>>,
|
||||
upscaling_pipeline: Res<UpscalingPipeline>,
|
||||
view_targets: Query<(Entity, &ViewTarget)>,
|
||||
@ -122,7 +122,7 @@ fn queue_view_upscaling_pipelines(
|
||||
upscaling_mode: UpscalingMode::Filtering,
|
||||
texture_format: view_target.out_texture_format(),
|
||||
};
|
||||
let pipeline = pipelines.specialize(&mut pipeline_cache, &upscaling_pipeline, key);
|
||||
let pipeline = pipelines.specialize(&pipeline_cache, &upscaling_pipeline, key);
|
||||
|
||||
commands
|
||||
.entity(entity)
|
||||
|
||||
@ -333,7 +333,7 @@ pub fn queue_material_meshes<M: Material>(
|
||||
transparent_draw_functions: Res<DrawFunctions<Transparent3d>>,
|
||||
material_pipeline: Res<MaterialPipeline<M>>,
|
||||
mut pipelines: ResMut<SpecializedMeshPipelines<MaterialPipeline<M>>>,
|
||||
mut pipeline_cache: ResMut<PipelineCache>,
|
||||
pipeline_cache: Res<PipelineCache>,
|
||||
msaa: Res<Msaa>,
|
||||
render_meshes: Res<RenderAssets<Mesh>>,
|
||||
render_materials: Res<RenderMaterials<M>>,
|
||||
@ -391,7 +391,7 @@ pub fn queue_material_meshes<M: Material>(
|
||||
}
|
||||
|
||||
let pipeline_id = pipelines.specialize(
|
||||
&mut pipeline_cache,
|
||||
&pipeline_cache,
|
||||
&material_pipeline,
|
||||
MaterialPipelineKey {
|
||||
mesh_key,
|
||||
|
||||
@ -1626,7 +1626,7 @@ pub fn queue_shadows(
|
||||
casting_meshes: Query<&Handle<Mesh>, Without<NotShadowCaster>>,
|
||||
render_meshes: Res<RenderAssets<Mesh>>,
|
||||
mut pipelines: ResMut<SpecializedMeshPipelines<ShadowPipeline>>,
|
||||
mut pipeline_cache: ResMut<PipelineCache>,
|
||||
pipeline_cache: Res<PipelineCache>,
|
||||
view_lights: Query<&ViewLightEntities>,
|
||||
mut view_light_shadow_phases: Query<(&LightEntity, &mut RenderPhase<Shadow>)>,
|
||||
point_light_entities: Query<&CubemapVisibleEntities, With<ExtractedPointLight>>,
|
||||
@ -1661,7 +1661,7 @@ pub fn queue_shadows(
|
||||
let key =
|
||||
ShadowPipelineKey::from_primitive_topology(mesh.primitive_topology);
|
||||
let pipeline_id = pipelines.specialize(
|
||||
&mut pipeline_cache,
|
||||
&pipeline_cache,
|
||||
&shadow_pipeline,
|
||||
key,
|
||||
&mesh.layout,
|
||||
|
||||
@ -108,7 +108,7 @@ fn queue_wireframes(
|
||||
wireframe_config: Res<WireframeConfig>,
|
||||
wireframe_pipeline: Res<WireframePipeline>,
|
||||
mut pipelines: ResMut<SpecializedMeshPipelines<WireframePipeline>>,
|
||||
mut pipeline_cache: ResMut<PipelineCache>,
|
||||
pipeline_cache: Res<PipelineCache>,
|
||||
msaa: Res<Msaa>,
|
||||
mut material_meshes: ParamSet<(
|
||||
Query<(Entity, &Handle<Mesh>, &MeshUniform)>,
|
||||
@ -128,7 +128,7 @@ fn queue_wireframes(
|
||||
let key = view_key
|
||||
| MeshPipelineKey::from_primitive_topology(mesh.primitive_topology);
|
||||
let pipeline_id = pipelines.specialize(
|
||||
&mut pipeline_cache,
|
||||
&pipeline_cache,
|
||||
&wireframe_pipeline,
|
||||
key,
|
||||
&mesh.layout,
|
||||
|
||||
@ -198,6 +198,8 @@ impl Plugin for RenderPlugin {
|
||||
.add_stage(
|
||||
RenderStage::Render,
|
||||
SystemStage::parallel()
|
||||
// Note: Must run before `render_system` in order to
|
||||
// processed newly queued pipelines.
|
||||
.with_system(PipelineCache::process_pipeline_queue_system)
|
||||
.with_system(render_system.at_end()),
|
||||
)
|
||||
|
||||
@ -17,6 +17,7 @@ use bevy_utils::{
|
||||
tracing::{debug, error},
|
||||
Entry, HashMap, HashSet,
|
||||
};
|
||||
use parking_lot::Mutex;
|
||||
use std::{hash::Hash, iter::FusedIterator, mem, ops::Deref};
|
||||
use thiserror::Error;
|
||||
use wgpu::{PipelineLayoutDescriptor, VertexBufferLayout as RawVertexBufferLayout};
|
||||
@ -343,6 +344,7 @@ pub struct PipelineCache {
|
||||
device: RenderDevice,
|
||||
pipelines: Vec<CachedPipeline>,
|
||||
waiting_pipelines: HashSet<CachedPipelineId>,
|
||||
new_pipelines: Mutex<Vec<CachedPipeline>>,
|
||||
}
|
||||
|
||||
impl PipelineCache {
|
||||
@ -357,6 +359,7 @@ impl PipelineCache {
|
||||
layout_cache: default(),
|
||||
shader_cache: default(),
|
||||
waiting_pipelines: default(),
|
||||
new_pipelines: default(),
|
||||
pipelines: default(),
|
||||
}
|
||||
}
|
||||
@ -455,15 +458,15 @@ impl PipelineCache {
|
||||
/// [`get_render_pipeline_state()`]: PipelineCache::get_render_pipeline_state
|
||||
/// [`get_render_pipeline()`]: PipelineCache::get_render_pipeline
|
||||
pub fn queue_render_pipeline(
|
||||
&mut self,
|
||||
&self,
|
||||
descriptor: RenderPipelineDescriptor,
|
||||
) -> CachedRenderPipelineId {
|
||||
let id = CachedRenderPipelineId(self.pipelines.len());
|
||||
self.pipelines.push(CachedPipeline {
|
||||
let mut new_pipelines = self.new_pipelines.lock();
|
||||
let id = CachedRenderPipelineId(self.pipelines.len() + new_pipelines.len());
|
||||
new_pipelines.push(CachedPipeline {
|
||||
descriptor: PipelineDescriptor::RenderPipelineDescriptor(Box::new(descriptor)),
|
||||
state: CachedPipelineState::Queued,
|
||||
});
|
||||
self.waiting_pipelines.insert(id.0);
|
||||
id
|
||||
}
|
||||
|
||||
@ -481,15 +484,15 @@ impl PipelineCache {
|
||||
/// [`get_compute_pipeline_state()`]: PipelineCache::get_compute_pipeline_state
|
||||
/// [`get_compute_pipeline()`]: PipelineCache::get_compute_pipeline
|
||||
pub fn queue_compute_pipeline(
|
||||
&mut self,
|
||||
&self,
|
||||
descriptor: ComputePipelineDescriptor,
|
||||
) -> CachedComputePipelineId {
|
||||
let id = CachedComputePipelineId(self.pipelines.len());
|
||||
self.pipelines.push(CachedPipeline {
|
||||
let mut new_pipelines = self.new_pipelines.lock();
|
||||
let id = CachedComputePipelineId(self.pipelines.len() + new_pipelines.len());
|
||||
new_pipelines.push(CachedPipeline {
|
||||
descriptor: PipelineDescriptor::ComputePipelineDescriptor(Box::new(descriptor)),
|
||||
state: CachedPipelineState::Queued,
|
||||
});
|
||||
self.waiting_pipelines.insert(id.0);
|
||||
id
|
||||
}
|
||||
|
||||
@ -632,9 +635,18 @@ impl PipelineCache {
|
||||
///
|
||||
/// [`RenderStage::Render`]: crate::RenderStage::Render
|
||||
pub fn process_queue(&mut self) {
|
||||
let waiting_pipelines = mem::take(&mut self.waiting_pipelines);
|
||||
let mut waiting_pipelines = mem::take(&mut self.waiting_pipelines);
|
||||
let mut pipelines = mem::take(&mut self.pipelines);
|
||||
|
||||
{
|
||||
let mut new_pipelines = self.new_pipelines.lock();
|
||||
for new_pipeline in new_pipelines.drain(..) {
|
||||
let id = pipelines.len();
|
||||
pipelines.push(new_pipeline);
|
||||
waiting_pipelines.insert(id);
|
||||
}
|
||||
}
|
||||
|
||||
for id in waiting_pipelines {
|
||||
let pipeline = &mut pipelines[id];
|
||||
if matches!(pipeline.state, CachedPipelineState::Ok(_)) {
|
||||
|
||||
@ -33,7 +33,7 @@ impl<S: SpecializedRenderPipeline> Default for SpecializedRenderPipelines<S> {
|
||||
impl<S: SpecializedRenderPipeline> SpecializedRenderPipelines<S> {
|
||||
pub fn specialize(
|
||||
&mut self,
|
||||
cache: &mut PipelineCache,
|
||||
cache: &PipelineCache,
|
||||
specialize_pipeline: &S,
|
||||
key: S::Key,
|
||||
) -> CachedRenderPipelineId {
|
||||
@ -103,7 +103,7 @@ impl<S: SpecializedMeshPipeline> SpecializedMeshPipelines<S> {
|
||||
#[inline]
|
||||
pub fn specialize(
|
||||
&mut self,
|
||||
cache: &mut PipelineCache,
|
||||
cache: &PipelineCache,
|
||||
specialize_pipeline: &S,
|
||||
key: S::Key,
|
||||
layout: &MeshVertexBufferLayout,
|
||||
|
||||
@ -319,7 +319,7 @@ pub fn queue_material2d_meshes<M: Material2d>(
|
||||
transparent_draw_functions: Res<DrawFunctions<Transparent2d>>,
|
||||
material2d_pipeline: Res<Material2dPipeline<M>>,
|
||||
mut pipelines: ResMut<SpecializedMeshPipelines<Material2dPipeline<M>>>,
|
||||
mut pipeline_cache: ResMut<PipelineCache>,
|
||||
pipeline_cache: Res<PipelineCache>,
|
||||
msaa: Res<Msaa>,
|
||||
render_meshes: Res<RenderAssets<Mesh>>,
|
||||
render_materials: Res<RenderMaterials2d<M>>,
|
||||
@ -363,7 +363,7 @@ pub fn queue_material2d_meshes<M: Material2d>(
|
||||
| Mesh2dPipelineKey::from_primitive_topology(mesh.primitive_topology);
|
||||
|
||||
let pipeline_id = pipelines.specialize(
|
||||
&mut pipeline_cache,
|
||||
&pipeline_cache,
|
||||
&material2d_pipeline,
|
||||
Material2dKey {
|
||||
mesh_key,
|
||||
|
||||
@ -451,7 +451,7 @@ pub fn queue_sprites(
|
||||
view_uniforms: Res<ViewUniforms>,
|
||||
sprite_pipeline: Res<SpritePipeline>,
|
||||
mut pipelines: ResMut<SpecializedRenderPipelines<SpritePipeline>>,
|
||||
mut pipeline_cache: ResMut<PipelineCache>,
|
||||
pipeline_cache: Res<PipelineCache>,
|
||||
mut image_bind_groups: ResMut<ImageBindGroups>,
|
||||
gpu_images: Res<RenderAssets<Image>>,
|
||||
msaa: Res<Msaa>,
|
||||
@ -528,12 +528,12 @@ pub fn queue_sprites(
|
||||
}
|
||||
}
|
||||
let pipeline = pipelines.specialize(
|
||||
&mut pipeline_cache,
|
||||
&pipeline_cache,
|
||||
&sprite_pipeline,
|
||||
view_key | SpritePipelineKey::from_colored(false),
|
||||
);
|
||||
let colored_pipeline = pipelines.specialize(
|
||||
&mut pipeline_cache,
|
||||
&pipeline_cache,
|
||||
&sprite_pipeline,
|
||||
view_key | SpritePipelineKey::from_colored(true),
|
||||
);
|
||||
|
||||
@ -557,7 +557,7 @@ pub fn queue_uinodes(
|
||||
view_uniforms: Res<ViewUniforms>,
|
||||
ui_pipeline: Res<UiPipeline>,
|
||||
mut pipelines: ResMut<SpecializedRenderPipelines<UiPipeline>>,
|
||||
mut pipeline_cache: ResMut<PipelineCache>,
|
||||
pipeline_cache: Res<PipelineCache>,
|
||||
mut image_bind_groups: ResMut<UiImageBindGroups>,
|
||||
gpu_images: Res<RenderAssets<Image>>,
|
||||
ui_batches: Query<(Entity, &UiBatch)>,
|
||||
@ -586,7 +586,7 @@ pub fn queue_uinodes(
|
||||
let draw_ui_function = draw_functions.read().id::<DrawUi>();
|
||||
for (view, mut transparent_phase) in &mut views {
|
||||
let pipeline = pipelines.specialize(
|
||||
&mut pipeline_cache,
|
||||
&pipeline_cache,
|
||||
&ui_pipeline,
|
||||
UiPipelineKey { hdr: view.hdr },
|
||||
);
|
||||
|
||||
@ -312,7 +312,7 @@ pub fn queue_colored_mesh2d(
|
||||
transparent_draw_functions: Res<DrawFunctions<Transparent2d>>,
|
||||
colored_mesh2d_pipeline: Res<ColoredMesh2dPipeline>,
|
||||
mut pipelines: ResMut<SpecializedRenderPipelines<ColoredMesh2dPipeline>>,
|
||||
mut pipeline_cache: ResMut<PipelineCache>,
|
||||
pipeline_cache: Res<PipelineCache>,
|
||||
msaa: Res<Msaa>,
|
||||
render_meshes: Res<RenderAssets<Mesh>>,
|
||||
colored_mesh2d: Query<(&Mesh2dHandle, &Mesh2dUniform), With<ColoredMesh2d>>,
|
||||
@ -343,7 +343,7 @@ pub fn queue_colored_mesh2d(
|
||||
}
|
||||
|
||||
let pipeline_id =
|
||||
pipelines.specialize(&mut pipeline_cache, &colored_mesh2d_pipeline, mesh2d_key);
|
||||
pipelines.specialize(&pipeline_cache, &colored_mesh2d_pipeline, mesh2d_key);
|
||||
|
||||
let mesh_z = mesh2d_uniform.transform.w_axis.z;
|
||||
transparent_phase.add(Transparent2d {
|
||||
|
||||
@ -137,7 +137,7 @@ impl FromWorld for GameOfLifePipeline {
|
||||
let shader = world
|
||||
.resource::<AssetServer>()
|
||||
.load("shaders/game_of_life.wgsl");
|
||||
let mut pipeline_cache = world.resource_mut::<PipelineCache>();
|
||||
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()]),
|
||||
|
||||
@ -104,7 +104,7 @@ fn queue_custom(
|
||||
custom_pipeline: Res<CustomPipeline>,
|
||||
msaa: Res<Msaa>,
|
||||
mut pipelines: ResMut<SpecializedMeshPipelines<CustomPipeline>>,
|
||||
mut pipeline_cache: ResMut<PipelineCache>,
|
||||
pipeline_cache: Res<PipelineCache>,
|
||||
meshes: Res<RenderAssets<Mesh>>,
|
||||
material_meshes: Query<(Entity, &MeshUniform, &Handle<Mesh>), With<InstanceMaterialData>>,
|
||||
mut views: Query<(&ExtractedView, &mut RenderPhase<Transparent3d>)>,
|
||||
@ -121,7 +121,7 @@ fn queue_custom(
|
||||
let key =
|
||||
view_key | MeshPipelineKey::from_primitive_topology(mesh.primitive_topology);
|
||||
let pipeline = pipelines
|
||||
.specialize(&mut pipeline_cache, &custom_pipeline, key, &mesh.layout)
|
||||
.specialize(&pipeline_cache, &custom_pipeline, key, &mesh.layout)
|
||||
.unwrap();
|
||||
transparent_phase.add(Transparent3d {
|
||||
entity,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user