diff --git a/crates/bevy_render/src/draw.rs b/crates/bevy_render/src/draw.rs index abeedd56064d5..b61e8d7b49ec1 100644 --- a/crates/bevy_render/src/draw.rs +++ b/crates/bevy_render/src/draw.rs @@ -158,8 +158,7 @@ impl<'a> DrawContext<'a> { &mut self, draw: &mut Draw, pipeline_handle: &Handle, - specialization: &mut PipelineSpecialization, - render_resource_bindings: &mut [&mut RenderResourceBindings], + specialization: &PipelineSpecialization, ) -> Result<(), DrawError> { let specialized_pipeline = if let Some(specialized_pipeline) = self .pipeline_compiler @@ -173,7 +172,6 @@ impl<'a> DrawContext<'a> { &mut self.shaders, pipeline_handle, specialization, - render_resource_bindings, ) }; diff --git a/crates/bevy_render/src/pipeline/pipeline_compiler.rs b/crates/bevy_render/src/pipeline/pipeline_compiler.rs index 2c04d4538bea1..1c122d4993b46 100644 --- a/crates/bevy_render/src/pipeline/pipeline_compiler.rs +++ b/crates/bevy_render/src/pipeline/pipeline_compiler.rs @@ -4,7 +4,7 @@ use crate::{ BindType, InputStepMode, VertexAttributeDescriptor, VertexBufferDescriptor, VertexFormat, VERTEX_FALLBACK_LAYOUT_NAME, }, - renderer::{RenderResourceBinding, RenderResourceBindings, RenderResourceContext}, + renderer::RenderResourceContext, shader::{Shader, ShaderSource}, }; use bevy_asset::{Assets, Handle}; @@ -136,8 +136,7 @@ impl PipelineCompiler { pipelines: &mut Assets, shaders: &mut Assets, source_pipeline: &Handle, - pipeline_specialization: &mut PipelineSpecialization, - render_resource_bindings: &mut [&mut RenderResourceBindings], + pipeline_specialization: &PipelineSpecialization, ) -> Handle { let source_descriptor = pipelines.get(source_pipeline).unwrap(); let mut specialized_descriptor = source_descriptor.clone(); @@ -164,14 +163,16 @@ impl PipelineCompiler { true, ); - let dynamic_bindings = self.get_dynamic_bindings(render_resource_bindings); - - if !dynamic_bindings.is_empty() { + if !pipeline_specialization.dynamic_bindings.is_empty() { // set binding uniforms to dynamic if render resource bindings use dynamic for bind_group in layout.bind_groups.iter_mut() { let mut binding_changed = false; for binding in bind_group.bindings.iter_mut() { - if dynamic_bindings.iter().any(|b| b == &binding.name) { + if pipeline_specialization + .dynamic_bindings + .iter() + .any(|b| b == &binding.name) + { if let BindType::Uniform { ref mut dynamic, .. } = binding.bind_type @@ -187,7 +188,6 @@ impl PipelineCompiler { } } } - pipeline_specialization.dynamic_bindings = dynamic_bindings; specialized_descriptor.layout = Some(layout); // create a vertex layout that provides all attributes from either the specialized vertex buffers or a zero buffer @@ -267,28 +267,6 @@ impl PipelineCompiler { weak_specialized_pipeline_handle } - fn get_dynamic_bindings( - &self, - render_resource_bindings: &mut [&mut RenderResourceBindings], - ) -> Vec { - render_resource_bindings - .iter() - .flat_map(|bindings| { - bindings - .bindings - .iter() - .filter(|(_, binding)| { - matches!(binding, RenderResourceBinding::Buffer { - dynamic_index: Some(_), - .. - }) - }) - .map(|(name, _)| name) - }) - .cloned() - .collect() - } - pub fn iter_compiled_pipelines( &self, pipeline_handle: Handle, diff --git a/crates/bevy_render/src/pipeline/render_pipelines.rs b/crates/bevy_render/src/pipeline/render_pipelines.rs index acf71d6370a29..6fa8871060216 100644 --- a/crates/bevy_render/src/pipeline/render_pipelines.rs +++ b/crates/bevy_render/src/pipeline/render_pipelines.rs @@ -14,13 +14,16 @@ use bevy_property::Properties; pub struct RenderPipeline { pub pipeline: Handle, pub specialization: PipelineSpecialization, + /// used to track if PipelineSpecialization::dynamic_bindings is in sync with RenderResourceBindings + pub dynamic_bindings_generation: usize, } impl RenderPipeline { pub fn new(pipeline: Handle) -> Self { RenderPipeline { + specialization: Default::default(), pipeline, - ..Default::default() + dynamic_bindings_generation: std::usize::MAX, } } @@ -31,6 +34,7 @@ impl RenderPipeline { RenderPipeline { pipeline, specialization, + dynamic_bindings_generation: std::usize::MAX, } } } @@ -100,7 +104,17 @@ pub fn draw_render_pipelines_system( let render_pipelines = &mut *render_pipelines; for pipeline in render_pipelines.pipelines.iter_mut() { pipeline.specialization.sample_count = msaa.samples; - // TODO: move these to mesh.rs? + if pipeline.dynamic_bindings_generation + != render_pipelines.bindings.dynamic_bindings_generation() + { + pipeline.specialization.dynamic_bindings = render_pipelines + .bindings + .iter_dynamic_bindings() + .map(|name| name.to_string()) + .collect::>(); + pipeline.dynamic_bindings_generation = + render_pipelines.bindings.dynamic_bindings_generation(); + } } for render_pipeline in render_pipelines.pipelines.iter_mut() { @@ -112,8 +126,7 @@ pub fn draw_render_pipelines_system( .set_pipeline( &mut draw, &render_pipeline.pipeline, - &mut render_pipeline.specialization, - render_resource_bindings, + &render_pipeline.specialization, ) .unwrap(); draw_context diff --git a/crates/bevy_render/src/renderer/render_resource/render_resource_bindings.rs b/crates/bevy_render/src/renderer/render_resource/render_resource_bindings.rs index 4f1a6b8b1e1fa..70d3fd0929f45 100644 --- a/crates/bevy_render/src/renderer/render_resource/render_resource_bindings.rs +++ b/crates/bevy_render/src/renderer/render_resource/render_resource_bindings.rs @@ -35,6 +35,13 @@ impl RenderResourceBinding { } } + pub fn is_dynamic_buffer(&self) -> bool { + matches!(self, RenderResourceBinding::Buffer { + dynamic_index: Some(_), + .. + }) + } + pub fn get_sampler(&self) -> Option { if let RenderResourceBinding::Sampler(sampler) = self { Some(*sampler) @@ -112,6 +119,7 @@ pub struct RenderResourceBindings { bind_groups: HashMap, bind_group_descriptors: HashMap>, dirty_bind_groups: HashSet, + dynamic_bindings_generation: usize, } impl RenderResourceBindings { @@ -124,9 +132,17 @@ impl RenderResourceBindings { self.bindings.insert(name.to_string(), binding); } + /// The current "generation" of dynamic bindings. This number increments every time a dynamic binding changes + pub fn dynamic_bindings_generation(&self) -> usize { + self.dynamic_bindings_generation + } + fn try_set_dirty(&mut self, name: &str, binding: &RenderResourceBinding) { if let Some(current_binding) = self.bindings.get(name) { if current_binding != binding { + if current_binding.is_dynamic_buffer() { + self.dynamic_bindings_generation += 1; + } // TODO: this is crude. we shouldn't need to invalidate all bind groups for id in self.bind_groups.keys() { self.dirty_bind_groups.insert(*id); @@ -236,6 +252,18 @@ impl RenderResourceBindings { Some(bind_group_builder.finish()) } + + pub fn iter_dynamic_bindings(&self) -> impl Iterator { + self.bindings + .iter() + .filter(|(_, binding)| { + matches!(binding, RenderResourceBinding::Buffer { + dynamic_index: Some(_), + .. + }) + }) + .map(|(name, _)| name.as_str()) + } } #[derive(Debug, Default)] diff --git a/crates/bevy_text/src/draw.rs b/crates/bevy_text/src/draw.rs index cf9d13e9176ee..4f08bd40d5ecb 100644 --- a/crates/bevy_text/src/draw.rs +++ b/crates/bevy_text/src/draw.rs @@ -49,12 +49,11 @@ impl<'a> Drawable for DrawableText<'a> { context.set_pipeline( draw, &bevy_sprite::SPRITE_SHEET_PIPELINE_HANDLE, - &mut PipelineSpecialization { + &PipelineSpecialization { sample_count: self.msaa.samples, vertex_buffer_descriptor: self.font_quad_vertex_descriptor.clone(), ..Default::default() }, - &mut [self.render_resource_bindings], )?; let render_resource_context = &**context.render_resource_context;