diff --git a/crates/bevy_render/src/render_graph/nodes/render_resources_node.rs b/crates/bevy_render/src/render_graph/nodes/render_resources_node.rs index 102ac515944178..a6ecaf4ac6bd91 100644 --- a/crates/bevy_render/src/render_graph/nodes/render_resources_node.rs +++ b/crates/bevy_render/src/render_graph/nodes/render_resources_node.rs @@ -4,16 +4,17 @@ use crate::{ render_graph::{CommandQueue, Node, ResourceSlots, SystemNode}, renderer::{ self, BufferInfo, BufferUsage, RenderContext, RenderResourceBinding, - RenderResourceBindings, RenderResourceBindingsId, RenderResourceContext, - RenderResourceHints, + RenderResourceBindings, RenderResourceContext, RenderResourceHints, }, texture, }; use bevy_asset::{Assets, Handle}; -use bevy_ecs::{Commands, IntoQuerySystem, Local, Query, Res, ResMut, Resources, System, World}; +use bevy_ecs::{ + Commands, Entity, IntoQuerySystem, Local, Query, Res, ResMut, Resources, System, World, +}; use renderer::{AssetRenderResourceBindings, BufferId, RenderResourceType, RenderResources}; -use std::{collections::HashMap, marker::PhantomData, ops::DerefMut}; +use std::{collections::HashMap, hash::Hash, marker::PhantomData, ops::DerefMut}; pub const BIND_BUFFER_ALIGNMENT: usize = 256; @@ -29,19 +30,19 @@ struct QueuedBufferWrite { size: usize, } -/// Used to track items in a gpu buffer in an "array" style +/// Used to track items in a gpu buffer in an "array" style #[derive(Debug)] -struct BufferArray { +struct BufferArray { item_size: usize, buffer_capacity: usize, min_capacity: usize, len: usize, buffer: Option, free_indices: Vec, - indices: HashMap, + indices: HashMap, } -impl BufferArray { +impl BufferArray { pub fn new(item_size: usize, min_capacity: usize, align: bool) -> Self { BufferArray { item_size: if align { @@ -58,19 +59,26 @@ impl BufferArray { } } - fn get_or_assign_index(&mut self, id: RenderResourceBindingsId) -> usize { + fn get_or_assign_index(&mut self, id: I) -> usize { if let Some(index) = self.indices.get(&id) { *index } else { - let index = self.len; - self.indices.insert(id, index); - self.len += 1; - index + if let Some(index) = self.free_indices.pop() { + self.indices.insert(id, index); + self.len += 1; + index + } else { + let index = self.len; + self.indices.insert(id, index); + self.len += 1; + index + } } } - pub fn get_binding(&self, id: RenderResourceBindingsId) -> Option { - self.indices.get(&id) + pub fn get_binding(&self, id: I) -> Option { + self.indices + .get(&id) .map(|index| RenderResourceBinding::Buffer { buffer: self.buffer.unwrap(), dynamic_index: Some((index * self.item_size) as u32), @@ -78,6 +86,13 @@ impl BufferArray { }) } + pub fn remove_binding(&mut self, id: I) { + if let Some(index) = self.indices.remove(&id) { + self.free_indices.push(index); + self.len -= 1; + } + } + pub fn resize(&mut self, render_resource_context: &dyn RenderResourceContext) { if self.len <= self.buffer_capacity { return; @@ -93,9 +108,9 @@ impl BufferArray { } let new_len = if self.buffer_capacity == 0 { - self.min_capacity.max(self.len) + self.min_capacity.max(self.len) } else { - self.min_capacity.max(self.len * 2) + self.min_capacity.max(self.len * 2) }; let size = new_len * self.item_size; @@ -110,11 +125,11 @@ impl BufferArray { } } -struct UniformBufferArrays +struct UniformBufferArrays where T: renderer::RenderResources, { - buffer_arrays: Vec>, + buffer_arrays: Vec>>, staging_buffer: Option, staging_buffer_size: usize, required_staging_buffer_size: usize, @@ -123,7 +138,7 @@ where _marker: PhantomData, } -impl Default for UniformBufferArrays +impl Default for UniformBufferArrays where T: renderer::RenderResources, { @@ -140,8 +155,9 @@ where } } -impl UniformBufferArrays +impl UniformBufferArrays where + I: Hash + Eq + Copy, T: renderer::RenderResources, { /// Initialize this UniformBufferArrays using information from a RenderResources value. @@ -168,7 +184,7 @@ where } /// Find a spot for the given RenderResources in each uniform's BufferArray and prepare space in the staging buffer - fn prepare_uniform_buffers(&mut self, id: RenderResourceBindingsId, render_resources: &T) { + fn prepare_uniform_buffers(&mut self, id: I, render_resources: &T) { for (i, render_resource) in render_resources.iter().enumerate() { if let Some(RenderResourceType::Buffer) = render_resource.resource_type() { let size = render_resource.buffer_byte_len().unwrap(); @@ -212,8 +228,17 @@ where } } + fn remove_bindings(&mut self, id: I) { + for buffer_array in self.buffer_arrays.iter_mut() { + if let Some(buffer_array) = buffer_array { + buffer_array.remove_binding(id); + } + } + } + fn write_uniform_buffers( &mut self, + id: I, uniforms: &T, dynamic_uniforms: bool, render_resource_context: &dyn RenderResourceContext, @@ -228,7 +253,7 @@ where let buffer_array = self.buffer_arrays[i].as_mut().unwrap(); let range = 0..size as u64; let (target_buffer, target_offset) = if dynamic_uniforms { - let binding = buffer_array.get_binding(render_resource_bindings.id).unwrap(); + let binding = buffer_array.get_binding(id).unwrap(); let dynamic_index = if let RenderResourceBinding::Buffer { dynamic_index: Some(dynamic_index), .. @@ -374,7 +399,7 @@ where system.id(), RenderResourcesNodeState { command_queue: self.command_queue.clone(), - uniform_buffer_arrays: UniformBufferArrays::::default(), + uniform_buffer_arrays: UniformBufferArrays::::default(), dynamic_uniforms: self.dynamic_uniforms, }, ); @@ -383,13 +408,13 @@ where } } -struct RenderResourcesNodeState { +struct RenderResourcesNodeState { command_queue: CommandQueue, - uniform_buffer_arrays: UniformBufferArrays, + uniform_buffer_arrays: UniformBufferArrays, dynamic_uniforms: bool, } -impl Default for RenderResourcesNodeState { +impl Default for RenderResourcesNodeState { fn default() -> Self { Self { command_queue: Default::default(), @@ -400,25 +425,29 @@ impl Default for RenderResourcesNodeState { } fn render_resources_node_system( - mut state: Local>, + mut state: Local>, render_resource_context: Res>, - mut query: Query<(&T, &Draw, &mut RenderPipelines)>, + mut query: Query<(Entity, &T, &Draw, &mut RenderPipelines)>, ) { let state = state.deref_mut(); let uniform_buffer_arrays = &mut state.uniform_buffer_arrays; let render_resource_context = &**render_resource_context; uniform_buffer_arrays.begin_update(); // initialize uniform buffer arrays using the first RenderResources - if let Some((first, _, _)) = query.iter().iter().next() { + if let Some((_, first, _, _)) = query.iter().iter().next() { uniform_buffer_arrays.initialize(first); } - for (uniforms, draw, mut render_pipelines) in &mut query.iter() { + for entity in query.removed::() { + uniform_buffer_arrays.remove_bindings(*entity); + } + + for (entity, uniforms, draw, mut render_pipelines) in &mut query.iter() { if !draw.is_visible { continue; } - uniform_buffer_arrays.prepare_uniform_buffers(render_pipelines.bindings.id, uniforms); + uniform_buffer_arrays.prepare_uniform_buffers(entity, uniforms); setup_uniform_texture_resources::( &uniforms, render_resource_context, @@ -435,12 +464,13 @@ fn render_resources_node_system( staging_buffer, 0..state.uniform_buffer_arrays.staging_buffer_size as u64, &mut |mut staging_buffer, _render_resource_context| { - for (uniforms, draw, mut render_pipelines) in &mut query.iter() { + for (entity, uniforms, draw, mut render_pipelines) in &mut query.iter() { if !draw.is_visible { continue; } state.uniform_buffer_arrays.write_uniform_buffers( + entity, &uniforms, state.dynamic_uniforms, render_resource_context, @@ -458,12 +488,13 @@ fn render_resources_node_system( } else { // TODO: can we just remove this? let mut staging_buffer: [u8; 0] = []; - for (uniforms, draw, mut render_pipelines) in &mut query.iter() { + for (entity, uniforms, draw, mut render_pipelines) in &mut query.iter() { if !draw.is_visible { continue; } state.uniform_buffer_arrays.write_uniform_buffers( + entity, &uniforms, state.dynamic_uniforms, render_resource_context, @@ -525,7 +556,7 @@ where system.id(), RenderResourcesNodeState { command_queue: self.command_queue.clone(), - uniform_buffer_arrays: UniformBufferArrays::::default(), + uniform_buffer_arrays: UniformBufferArrays::, T>::default(), dynamic_uniforms: self.dynamic_uniforms, }, ); @@ -535,9 +566,8 @@ where } fn asset_render_resources_node_system( - mut state: Local>, + mut state: Local, T>>, assets: Res>, - // asset_events: Res>>, mut asset_render_resource_bindings: ResMut, render_resource_context: Res>, mut query: Query<(&Handle, &Draw, &mut RenderPipelines)>, @@ -560,8 +590,8 @@ fn asset_render_resources_node_system( for asset_handle in modified_assets.iter() { let asset = assets.get(&asset_handle).expect(EXPECT_ASSET_MESSAGE); + uniform_buffer_arrays.prepare_uniform_buffers(*asset_handle, asset); let mut bindings = asset_render_resource_bindings.get_or_insert_mut(*asset_handle); - uniform_buffer_arrays.prepare_uniform_buffers(bindings.id, asset); setup_uniform_texture_resources::(&asset, render_resource_context, &mut bindings); } @@ -580,6 +610,7 @@ fn asset_render_resources_node_system( asset_render_resource_bindings.get_or_insert_mut(*asset_handle); // TODO: only setup buffer if we haven't seen this handle before state.uniform_buffer_arrays.write_uniform_buffers( + *asset_handle, &asset, state.dynamic_uniforms, render_resource_context, @@ -602,6 +633,7 @@ fn asset_render_resources_node_system( asset_render_resource_bindings.get_or_insert_mut(*asset_handle); // TODO: only setup buffer if we haven't seen this handle before state.uniform_buffer_arrays.write_uniform_buffers( + *asset_handle, &asset, state.dynamic_uniforms, render_resource_context,