From 794ab87d9b6ced95262717ff0eb2c04a70585f70 Mon Sep 17 00:00:00 2001 From: Daniel Chia Date: Sun, 15 Jan 2023 00:28:18 -0800 Subject: [PATCH 1/4] Make PipelineCache internally mutable. Change queue_*_pipeline functions of PipelineCache to be backed by a mutex-protected Vec of deferred pipeline creations. We don't expect pipelines to regularly be created, so we shouldn't end up hitting this Mutex in the hot path. In return, this will allow for queue systems to request for Res rather than ResMut, removing one barrier for running these systems in parallel. --- crates/bevy_core_pipeline/src/bloom/mod.rs | 2 +- crates/bevy_render/src/lib.rs | 2 +- .../src/render_resource/pipeline_cache.rs | 28 +++++++++++++------ 3 files changed, 22 insertions(+), 10 deletions(-) diff --git a/crates/bevy_core_pipeline/src/bloom/mod.rs b/crates/bevy_core_pipeline/src/bloom/mod.rs index 7112ccba63d9d..d2d813bcef686 100644 --- a/crates/bevy_core_pipeline/src/bloom/mod.rs +++ b/crates/bevy_core_pipeline/src/bloom/mod.rs @@ -434,7 +434,7 @@ impl FromWorld for BloomPipelines { ], }); - let mut pipeline_cache = world.resource_mut::(); + let pipeline_cache = world.resource_mut::(); let downsampling_prefilter_pipeline = pipeline_cache.queue_render_pipeline(RenderPipelineDescriptor { diff --git a/crates/bevy_render/src/lib.rs b/crates/bevy_render/src/lib.rs index 5456c7208accc..bd1b1411820de 100644 --- a/crates/bevy_render/src/lib.rs +++ b/crates/bevy_render/src/lib.rs @@ -198,7 +198,7 @@ impl Plugin for RenderPlugin { .add_stage( RenderStage::Render, SystemStage::parallel() - .with_system(PipelineCache::process_pipeline_queue_system) + .with_system(PipelineCache::process_pipeline_queue_system.at_start()) .with_system(render_system.at_end()), ) .add_stage( diff --git a/crates/bevy_render/src/render_resource/pipeline_cache.rs b/crates/bevy_render/src/render_resource/pipeline_cache.rs index 894103a30d129..f4a50653fa72f 100644 --- a/crates/bevy_render/src/render_resource/pipeline_cache.rs +++ b/crates/bevy_render/src/render_resource/pipeline_cache.rs @@ -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, waiting_pipelines: HashSet, + new_pipelines: Mutex>, } 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 } @@ -484,12 +487,12 @@ impl PipelineCache { &mut 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(_)) { From 8399a50a1eb2c4da64b397a11e8f7ea44e9af72f Mon Sep 17 00:00:00 2001 From: Daniel Chia Date: Sun, 15 Jan 2023 01:22:40 -0800 Subject: [PATCH 2/4] Review comments round 1 --- crates/bevy_core_pipeline/src/bloom/mod.rs | 2 +- crates/bevy_render/src/render_resource/pipeline_cache.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/bevy_core_pipeline/src/bloom/mod.rs b/crates/bevy_core_pipeline/src/bloom/mod.rs index d2d813bcef686..3ceb6a2645581 100644 --- a/crates/bevy_core_pipeline/src/bloom/mod.rs +++ b/crates/bevy_core_pipeline/src/bloom/mod.rs @@ -434,7 +434,7 @@ impl FromWorld for BloomPipelines { ], }); - let pipeline_cache = world.resource_mut::(); + let pipeline_cache = world.resource::(); let downsampling_prefilter_pipeline = pipeline_cache.queue_render_pipeline(RenderPipelineDescriptor { diff --git a/crates/bevy_render/src/render_resource/pipeline_cache.rs b/crates/bevy_render/src/render_resource/pipeline_cache.rs index f4a50653fa72f..36c54e6043e7d 100644 --- a/crates/bevy_render/src/render_resource/pipeline_cache.rs +++ b/crates/bevy_render/src/render_resource/pipeline_cache.rs @@ -484,7 +484,7 @@ 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 mut new_pipelines = self.new_pipelines.lock(); From 1a159a51e123af521db1fa4d0b2209abe3fe19fe Mon Sep 17 00:00:00 2001 From: Daniel Chia Date: Sun, 15 Jan 2023 01:33:17 -0800 Subject: [PATCH 3/4] Change mutable usages of PipelineCache to immutable where possible --- crates/bevy_core_pipeline/src/fxaa/mod.rs | 4 ++-- crates/bevy_core_pipeline/src/tonemapping/mod.rs | 4 ++-- crates/bevy_core_pipeline/src/upscaling/mod.rs | 4 ++-- crates/bevy_pbr/src/material.rs | 4 ++-- crates/bevy_pbr/src/render/light.rs | 4 ++-- crates/bevy_pbr/src/wireframe.rs | 4 ++-- .../bevy_render/src/render_resource/pipeline_specializer.rs | 4 ++-- crates/bevy_sprite/src/mesh2d/material.rs | 4 ++-- crates/bevy_sprite/src/render/mod.rs | 6 +++--- crates/bevy_ui/src/render/mod.rs | 4 ++-- examples/2d/mesh2d_manual.rs | 4 ++-- examples/shader/compute_shader_game_of_life.rs | 2 +- examples/shader/shader_instancing.rs | 4 ++-- 13 files changed, 26 insertions(+), 26 deletions(-) diff --git a/crates/bevy_core_pipeline/src/fxaa/mod.rs b/crates/bevy_core_pipeline/src/fxaa/mod.rs index c843d0df1e87a..4b2a7a2ea9401 100644 --- a/crates/bevy_core_pipeline/src/fxaa/mod.rs +++ b/crates/bevy_core_pipeline/src/fxaa/mod.rs @@ -223,7 +223,7 @@ impl SpecializedRenderPipeline for FxaaPipeline { pub fn prepare_fxaa_pipelines( mut commands: Commands, - mut pipeline_cache: ResMut, + pipeline_cache: Res, mut pipelines: ResMut>, fxaa_pipeline: Res, 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, diff --git a/crates/bevy_core_pipeline/src/tonemapping/mod.rs b/crates/bevy_core_pipeline/src/tonemapping/mod.rs index 785c231a43fb9..f7233fd575102 100644 --- a/crates/bevy_core_pipeline/src/tonemapping/mod.rs +++ b/crates/bevy_core_pipeline/src/tonemapping/mod.rs @@ -126,7 +126,7 @@ pub struct ViewTonemappingPipeline(CachedRenderPipelineId); pub fn queue_view_tonemapping_pipelines( mut commands: Commands, - mut pipeline_cache: ResMut, + pipeline_cache: Res, mut pipelines: ResMut>, upscaling_pipeline: Res, 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) diff --git a/crates/bevy_core_pipeline/src/upscaling/mod.rs b/crates/bevy_core_pipeline/src/upscaling/mod.rs index b8fa9718d000f..a25e10632cd90 100644 --- a/crates/bevy_core_pipeline/src/upscaling/mod.rs +++ b/crates/bevy_core_pipeline/src/upscaling/mod.rs @@ -112,7 +112,7 @@ pub struct ViewUpscalingPipeline(CachedRenderPipelineId); fn queue_view_upscaling_pipelines( mut commands: Commands, - mut pipeline_cache: ResMut, + pipeline_cache: Res, mut pipelines: ResMut>, upscaling_pipeline: Res, 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) diff --git a/crates/bevy_pbr/src/material.rs b/crates/bevy_pbr/src/material.rs index d10fac03a684e..b2ec52cecab5a 100644 --- a/crates/bevy_pbr/src/material.rs +++ b/crates/bevy_pbr/src/material.rs @@ -321,7 +321,7 @@ pub fn queue_material_meshes( transparent_draw_functions: Res>, material_pipeline: Res>, mut pipelines: ResMut>>, - mut pipeline_cache: ResMut, + pipeline_cache: Res, msaa: Res, render_meshes: Res>, render_materials: Res>, @@ -379,7 +379,7 @@ pub fn queue_material_meshes( } let pipeline_id = pipelines.specialize( - &mut pipeline_cache, + &pipeline_cache, &material_pipeline, MaterialPipelineKey { mesh_key, diff --git a/crates/bevy_pbr/src/render/light.rs b/crates/bevy_pbr/src/render/light.rs index f0fd69b5a7d72..78db3bb9b60d4 100644 --- a/crates/bevy_pbr/src/render/light.rs +++ b/crates/bevy_pbr/src/render/light.rs @@ -1626,7 +1626,7 @@ pub fn queue_shadows( casting_meshes: Query<&Handle, Without>, render_meshes: Res>, mut pipelines: ResMut>, - mut pipeline_cache: ResMut, + pipeline_cache: Res, view_lights: Query<&ViewLightEntities>, mut view_light_shadow_phases: Query<(&LightEntity, &mut RenderPhase)>, point_light_entities: Query<&CubemapVisibleEntities, With>, @@ -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, diff --git a/crates/bevy_pbr/src/wireframe.rs b/crates/bevy_pbr/src/wireframe.rs index 2b31a051317d2..b7d747db07302 100644 --- a/crates/bevy_pbr/src/wireframe.rs +++ b/crates/bevy_pbr/src/wireframe.rs @@ -108,7 +108,7 @@ fn queue_wireframes( wireframe_config: Res, wireframe_pipeline: Res, mut pipelines: ResMut>, - mut pipeline_cache: ResMut, + pipeline_cache: Res, msaa: Res, mut material_meshes: ParamSet<( Query<(Entity, &Handle, &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, diff --git a/crates/bevy_render/src/render_resource/pipeline_specializer.rs b/crates/bevy_render/src/render_resource/pipeline_specializer.rs index d685ca7f228a5..10035133adcec 100644 --- a/crates/bevy_render/src/render_resource/pipeline_specializer.rs +++ b/crates/bevy_render/src/render_resource/pipeline_specializer.rs @@ -33,7 +33,7 @@ impl Default for SpecializedRenderPipelines { impl SpecializedRenderPipelines { pub fn specialize( &mut self, - cache: &mut PipelineCache, + cache: &PipelineCache, specialize_pipeline: &S, key: S::Key, ) -> CachedRenderPipelineId { @@ -103,7 +103,7 @@ impl SpecializedMeshPipelines { #[inline] pub fn specialize( &mut self, - cache: &mut PipelineCache, + cache: &PipelineCache, specialize_pipeline: &S, key: S::Key, layout: &MeshVertexBufferLayout, diff --git a/crates/bevy_sprite/src/mesh2d/material.rs b/crates/bevy_sprite/src/mesh2d/material.rs index 0a2a0b35ee116..13ed41a56a431 100644 --- a/crates/bevy_sprite/src/mesh2d/material.rs +++ b/crates/bevy_sprite/src/mesh2d/material.rs @@ -307,7 +307,7 @@ pub fn queue_material2d_meshes( transparent_draw_functions: Res>, material2d_pipeline: Res>, mut pipelines: ResMut>>, - mut pipeline_cache: ResMut, + pipeline_cache: Res, msaa: Res, render_meshes: Res>, render_materials: Res>, @@ -351,7 +351,7 @@ pub fn queue_material2d_meshes( | Mesh2dPipelineKey::from_primitive_topology(mesh.primitive_topology); let pipeline_id = pipelines.specialize( - &mut pipeline_cache, + &pipeline_cache, &material2d_pipeline, Material2dKey { mesh_key, diff --git a/crates/bevy_sprite/src/render/mod.rs b/crates/bevy_sprite/src/render/mod.rs index 09c386b4064c2..95fa7cb3f5800 100644 --- a/crates/bevy_sprite/src/render/mod.rs +++ b/crates/bevy_sprite/src/render/mod.rs @@ -451,7 +451,7 @@ pub fn queue_sprites( view_uniforms: Res, sprite_pipeline: Res, mut pipelines: ResMut>, - mut pipeline_cache: ResMut, + pipeline_cache: Res, mut image_bind_groups: ResMut, gpu_images: Res>, msaa: Res, @@ -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), ); diff --git a/crates/bevy_ui/src/render/mod.rs b/crates/bevy_ui/src/render/mod.rs index 0a6d93285ac4e..e7dcf453f474e 100644 --- a/crates/bevy_ui/src/render/mod.rs +++ b/crates/bevy_ui/src/render/mod.rs @@ -557,7 +557,7 @@ pub fn queue_uinodes( view_uniforms: Res, ui_pipeline: Res, mut pipelines: ResMut>, - mut pipeline_cache: ResMut, + pipeline_cache: Res, mut image_bind_groups: ResMut, gpu_images: Res>, ui_batches: Query<(Entity, &UiBatch)>, @@ -586,7 +586,7 @@ pub fn queue_uinodes( let draw_ui_function = draw_functions.read().id::(); for (view, mut transparent_phase) in &mut views { let pipeline = pipelines.specialize( - &mut pipeline_cache, + &pipeline_cache, &ui_pipeline, UiPipelineKey { hdr: view.hdr }, ); diff --git a/examples/2d/mesh2d_manual.rs b/examples/2d/mesh2d_manual.rs index 4147a4a4966f4..560cffa2568e5 100644 --- a/examples/2d/mesh2d_manual.rs +++ b/examples/2d/mesh2d_manual.rs @@ -312,7 +312,7 @@ pub fn queue_colored_mesh2d( transparent_draw_functions: Res>, colored_mesh2d_pipeline: Res, mut pipelines: ResMut>, - mut pipeline_cache: ResMut, + pipeline_cache: Res, msaa: Res, render_meshes: Res>, colored_mesh2d: Query<(&Mesh2dHandle, &Mesh2dUniform), With>, @@ -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 { diff --git a/examples/shader/compute_shader_game_of_life.rs b/examples/shader/compute_shader_game_of_life.rs index 78221b8aa9442..74b5cba036a04 100644 --- a/examples/shader/compute_shader_game_of_life.rs +++ b/examples/shader/compute_shader_game_of_life.rs @@ -137,7 +137,7 @@ impl FromWorld for GameOfLifePipeline { let shader = world .resource::() .load("shaders/game_of_life.wgsl"); - let mut pipeline_cache = world.resource_mut::(); + let pipeline_cache = world.resource::(); let init_pipeline = pipeline_cache.queue_compute_pipeline(ComputePipelineDescriptor { label: None, layout: Some(vec![texture_bind_group_layout.clone()]), diff --git a/examples/shader/shader_instancing.rs b/examples/shader/shader_instancing.rs index 7217722253b50..711f0d2293c8c 100644 --- a/examples/shader/shader_instancing.rs +++ b/examples/shader/shader_instancing.rs @@ -104,7 +104,7 @@ fn queue_custom( custom_pipeline: Res, msaa: Res, mut pipelines: ResMut>, - mut pipeline_cache: ResMut, + pipeline_cache: Res, meshes: Res>, material_meshes: Query<(Entity, &MeshUniform, &Handle), With>, mut views: Query<(&ExtractedView, &mut RenderPhase)>, @@ -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, From 1851375d1af7efa99a952e834664bbc1634d19cc Mon Sep 17 00:00:00 2001 From: Daniel Chia Date: Sun, 15 Jan 2023 15:16:34 -0800 Subject: [PATCH 4/4] update system ordering --- crates/bevy_render/src/lib.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/crates/bevy_render/src/lib.rs b/crates/bevy_render/src/lib.rs index bd1b1411820de..bb37fc829a7ad 100644 --- a/crates/bevy_render/src/lib.rs +++ b/crates/bevy_render/src/lib.rs @@ -198,7 +198,9 @@ impl Plugin for RenderPlugin { .add_stage( RenderStage::Render, SystemStage::parallel() - .with_system(PipelineCache::process_pipeline_queue_system.at_start()) + // 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()), ) .add_stage(