diff --git a/crates/bevy_core_pipeline/src/bloom/mod.rs b/crates/bevy_core_pipeline/src/bloom/mod.rs index 7112ccba63d9d..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 mut 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_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 426b2cee1cf64..622659effd435 100644 --- a/crates/bevy_pbr/src/material.rs +++ b/crates/bevy_pbr/src/material.rs @@ -333,7 +333,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>, @@ -391,7 +391,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 b6b4ee9131180..657534c30c220 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 9534dafb785c3..5339043913454 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/lib.rs b/crates/bevy_render/src/lib.rs index 5456c7208accc..bb37fc829a7ad 100644 --- a/crates/bevy_render/src/lib.rs +++ b/crates/bevy_render/src/lib.rs @@ -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()), ) diff --git a/crates/bevy_render/src/render_resource/pipeline_cache.rs b/crates/bevy_render/src/render_resource/pipeline_cache.rs index 894103a30d129..36c54e6043e7d 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 } @@ -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(_)) { 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 9ec94b7cf37b5..b636e8b2fb782 100644 --- a/crates/bevy_sprite/src/mesh2d/material.rs +++ b/crates/bevy_sprite/src/mesh2d/material.rs @@ -319,7 +319,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>, @@ -363,7 +363,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,