Fix despawn (#361)

* simplify RenderResourcesNode gpu array management

* support removals in RenderResourcesNode
This commit is contained in:
Carter Anderson 2020-08-26 23:03:55 -07:00 committed by GitHub
parent 93040ef9a0
commit 89a1d360c1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 235 additions and 254 deletions

View File

@ -66,7 +66,7 @@ pub fn derive_render_resources(input: TokenStream) -> TokenStream {
} }
} }
fn iter_render_resources(&self) -> #bevy_render_path::renderer::RenderResourceIterator { fn iter(&self) -> #bevy_render_path::renderer::RenderResourceIterator {
#bevy_render_path::renderer::RenderResourceIterator::new(self) #bevy_render_path::renderer::RenderResourceIterator::new(self)
} }
} }
@ -167,7 +167,7 @@ pub fn derive_render_resources(input: TokenStream) -> TokenStream {
#render_resource_hints_ident[index].clone() #render_resource_hints_ident[index].clone()
} }
fn iter_render_resources(&self) -> #bevy_render_path::renderer::RenderResourceIterator { fn iter(&self) -> #bevy_render_path::renderer::RenderResourceIterator {
#bevy_render_path::renderer::RenderResourceIterator::new(self) #bevy_render_path::renderer::RenderResourceIterator::new(self)
} }
} }

View File

@ -4,18 +4,24 @@ use crate::{
render_graph::{CommandQueue, Node, ResourceSlots, SystemNode}, render_graph::{CommandQueue, Node, ResourceSlots, SystemNode},
renderer::{ renderer::{
self, BufferInfo, BufferUsage, RenderContext, RenderResourceBinding, self, BufferInfo, BufferUsage, RenderContext, RenderResourceBinding,
RenderResourceBindings, RenderResourceBindingsId, RenderResourceContext, RenderResourceBindings, RenderResourceContext, RenderResourceHints,
RenderResourceHints,
}, },
texture, texture,
}; };
use bevy_asset::{Assets, Handle}; 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 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; pub const BIND_BUFFER_ALIGNMENT: usize = 256;
fn get_aligned_dynamic_uniform_size(data_size: usize) -> usize {
BIND_BUFFER_ALIGNMENT * ((data_size as f32 / BIND_BUFFER_ALIGNMENT as f32).ceil() as usize)
}
#[derive(Debug)] #[derive(Debug)]
struct QueuedBufferWrite { struct QueuedBufferWrite {
buffer: BufferId, buffer: BufferId,
@ -24,189 +30,191 @@ struct QueuedBufferWrite {
size: usize, size: usize,
} }
/// Used to track items in a gpu buffer in an "array" style
#[derive(Debug)] #[derive(Debug)]
struct BufferArrayStatus { struct BufferArray<I> {
changed_item_count: usize,
item_size: usize, item_size: usize,
aligned_size: usize, buffer_capacity: usize,
staging_buffer_offset: usize, min_capacity: usize,
len: usize,
buffer: Option<BufferId>, buffer: Option<BufferId>,
queued_buffer_writes: Vec<QueuedBufferWrite>, free_indices: Vec<usize>,
current_item_count: usize, indices: HashMap<I, usize>,
current_item_capacity: usize,
indices: HashMap<RenderResourceBindingsId, usize>,
current_index: usize,
// TODO: this is a hack to workaround RenderResources without a fixed length
changed_size: usize,
current_offset: usize,
} }
impl BufferArrayStatus { impl<I: Hash + Eq> BufferArray<I> {
pub fn get_or_assign_index(&mut self, id: RenderResourceBindingsId) -> usize { pub fn new(item_size: usize, min_capacity: usize, align: bool) -> Self {
if let Some(offset) = self.indices.get(&id) { BufferArray {
*offset item_size: if align {
} else { get_aligned_dynamic_uniform_size(item_size)
if self.current_index == self.current_item_capacity { } else {
panic!("no empty slots available in array"); item_size
} },
len: 0,
buffer_capacity: 0,
min_capacity,
buffer: None,
free_indices: Vec::new(),
indices: HashMap::new(),
}
}
let index = self.current_index; fn get_or_assign_index(&mut self, id: I) -> usize {
if let Some(index) = self.indices.get(&id) {
*index
} else if let Some(index) = self.free_indices.pop() {
self.indices.insert(id, index); self.indices.insert(id, index);
self.current_index += 1; self.len += 1;
index
} else {
let index = self.len;
self.indices.insert(id, index);
self.len += 1;
index index
} }
} }
pub fn get_binding(&self, id: I) -> Option<RenderResourceBinding> {
self.indices
.get(&id)
.map(|index| RenderResourceBinding::Buffer {
buffer: self.buffer.unwrap(),
dynamic_index: Some((index * self.item_size) as u32),
range: 0..self.item_size as u64,
})
}
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;
}
self.allocate_buffer(render_resource_context);
// TODO: allow shrinking
}
pub fn allocate_buffer(&mut self, render_resource_context: &dyn RenderResourceContext) {
if let Some(old_buffer) = self.buffer.take() {
render_resource_context.remove_buffer(old_buffer);
}
let new_len = if self.buffer_capacity == 0 {
self.min_capacity.max(self.len)
} else {
self.min_capacity.max(self.len * 2)
};
let size = new_len * self.item_size;
let buffer = render_resource_context.create_buffer(BufferInfo {
size,
buffer_usage: BufferUsage::COPY_DST | BufferUsage::UNIFORM,
..Default::default()
});
self.buffer = Some(buffer);
self.buffer_capacity = new_len;
}
} }
struct UniformBufferArrays<T> struct UniformBufferArrays<I, T>
where where
T: renderer::RenderResources, T: renderer::RenderResources,
{ {
uniform_arrays: Vec<Option<(String, BufferArrayStatus)>>, buffer_arrays: Vec<Option<BufferArray<I>>>,
staging_buffer: Option<BufferId>, staging_buffer: Option<BufferId>,
staging_buffer_size: usize, staging_buffer_size: usize,
required_staging_buffer_size: usize,
current_staging_buffer_offset: usize,
queued_buffer_writes: Vec<QueuedBufferWrite>,
_marker: PhantomData<T>, _marker: PhantomData<T>,
} }
impl<T> Default for UniformBufferArrays<T> impl<I, T> Default for UniformBufferArrays<I, T>
where where
T: renderer::RenderResources, T: renderer::RenderResources,
{ {
fn default() -> Self { fn default() -> Self {
Self { Self {
uniform_arrays: Default::default(), buffer_arrays: Default::default(),
staging_buffer: Default::default(), staging_buffer: Default::default(),
staging_buffer_size: 0, staging_buffer_size: 0,
current_staging_buffer_offset: 0,
queued_buffer_writes: Vec::new(),
required_staging_buffer_size: 0,
_marker: Default::default(), _marker: Default::default(),
} }
} }
} }
impl<T> UniformBufferArrays<T> impl<I, T> UniformBufferArrays<I, T>
where where
I: Hash + Eq + Copy,
T: renderer::RenderResources, T: renderer::RenderResources,
{ {
fn reset_changed_item_counts(&mut self) { /// Initialize this UniformBufferArrays using information from a RenderResources value.
for buffer_status in self.uniform_arrays.iter_mut() { fn initialize(&mut self, render_resources: &T) {
if let Some((_name, buffer_status)) = buffer_status { if self.buffer_arrays.len() != render_resources.render_resources_len() {
buffer_status.changed_item_count = 0; let mut buffer_arrays = Vec::with_capacity(render_resources.render_resources_len());
buffer_status.current_index = 0; for render_resource in render_resources.iter() {
buffer_status.indices.clear(); if let Some(RenderResourceType::Buffer) = render_resource.resource_type() {
buffer_status.current_offset = 0; let size = render_resource.buffer_byte_len().unwrap();
buffer_status.changed_size = 0; buffer_arrays.push(Some(BufferArray::new(size, 10, true)));
}
}
}
fn increment_changed_item_counts(&mut self, uniforms: &T) {
if self.uniform_arrays.len() != uniforms.render_resources_len() {
self.uniform_arrays
.resize_with(uniforms.render_resources_len(), || None);
}
for (i, render_resource) in uniforms.iter_render_resources().enumerate() {
if let Some(RenderResourceType::Buffer) = render_resource.resource_type() {
let render_resource_name = uniforms.get_render_resource_name(i).unwrap();
let size = render_resource.buffer_byte_len().unwrap();
if let Some((ref _name, ref mut buffer_array_status)) = self.uniform_arrays[i] {
buffer_array_status.changed_item_count += 1;
buffer_array_status.changed_size += size;
} else { } else {
self.uniform_arrays[i] = Some(( buffer_arrays.push(None);
render_resource_name.to_string(), }
BufferArrayStatus { }
changed_item_count: 1,
queued_buffer_writes: Vec::new(), self.buffer_arrays = buffer_arrays;
aligned_size: Self::get_aligned_dynamic_uniform_size(size), }
item_size: size, }
staging_buffer_offset: 0,
buffer: None, /// Resets staging buffer tracking information
current_index: 0, fn begin_update(&mut self) {
current_item_count: 0, self.required_staging_buffer_size = 0;
current_item_capacity: 0, self.current_staging_buffer_offset = 0;
indices: HashMap::new(), }
changed_size: size,
current_offset: 0, /// 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: 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();
if let Some(buffer_array) = &mut self.buffer_arrays[i] {
buffer_array.get_or_assign_index(id);
self.required_staging_buffer_size += size;
} }
} }
} }
} }
fn get_aligned_dynamic_uniform_size(data_size: usize) -> usize { /// Resize BufferArray buffers if they aren't large enough
BIND_BUFFER_ALIGNMENT * ((data_size as f32 / BIND_BUFFER_ALIGNMENT as f32).ceil() as usize) fn resize_buffer_arrays(&mut self, render_resource_context: &dyn RenderResourceContext) {
} for buffer_array in self.buffer_arrays.iter_mut() {
if let Some(buffer_array) = buffer_array {
fn setup_buffer_arrays( buffer_array.resize(render_resource_context);
&mut self,
render_resource_context: &dyn RenderResourceContext,
dynamic_uniforms: bool,
) {
for buffer_array_status in self.uniform_arrays.iter_mut() {
if let Some((_name, buffer_array_status)) = buffer_array_status {
if dynamic_uniforms {
Self::setup_buffer_array(buffer_array_status, render_resource_context, true);
}
buffer_array_status.queued_buffer_writes =
Vec::with_capacity(buffer_array_status.changed_item_count);
} }
} }
} }
fn setup_buffer_array( /// Update the staging buffer to provide enough space to copy data to target buffers.
buffer_array_status: &mut BufferArrayStatus, fn resize_staging_buffer(&mut self, render_resource_context: &dyn RenderResourceContext) {
render_resource_context: &dyn RenderResourceContext, // TODO: allow staging buffer to scale down
align: bool, if self.required_staging_buffer_size > self.staging_buffer_size {
) {
if buffer_array_status.current_item_capacity < buffer_array_status.changed_item_count {
let new_capacity =
buffer_array_status.changed_item_count + buffer_array_status.changed_item_count / 2;
let mut item_size = buffer_array_status.item_size;
if align {
item_size = Self::get_aligned_dynamic_uniform_size(item_size);
}
let total_size = item_size * new_capacity;
let buffer = render_resource_context.create_buffer(BufferInfo {
size: total_size,
buffer_usage: BufferUsage::COPY_DST | BufferUsage::UNIFORM,
..Default::default()
});
buffer_array_status.current_item_capacity = new_capacity;
log::trace!(
"creating buffer for uniform {}. size: {} item_capacity: {} item_size: {}",
std::any::type_name::<T>(),
total_size,
new_capacity,
item_size
);
buffer_array_status.buffer = Some(buffer);
}
}
fn update_staging_buffer(&mut self, render_resource_context: &dyn RenderResourceContext) {
let mut size = 0;
for dynamic_buffer_array_status in self.uniform_arrays.iter_mut() {
if let Some((_name, ref mut buffer_array_status)) = dynamic_buffer_array_status {
buffer_array_status.staging_buffer_offset = size;
size += buffer_array_status.changed_size;
}
}
if self.staging_buffer_size != size {
if let Some(staging_buffer) = self.staging_buffer { if let Some(staging_buffer) = self.staging_buffer {
render_resource_context.remove_buffer(staging_buffer); render_resource_context.remove_buffer(staging_buffer);
} }
if size > 0 { if self.required_staging_buffer_size > 0 {
let staging_buffer = render_resource_context.create_buffer(BufferInfo { let staging_buffer = render_resource_context.create_buffer(BufferInfo {
buffer_usage: BufferUsage::COPY_SRC | BufferUsage::MAP_WRITE, buffer_usage: BufferUsage::COPY_SRC | BufferUsage::MAP_WRITE,
size, size: self.required_staging_buffer_size,
..Default::default() ..Default::default()
}); });
self.staging_buffer = Some(staging_buffer); self.staging_buffer = Some(staging_buffer);
@ -214,40 +222,47 @@ where
self.staging_buffer = None; self.staging_buffer = None;
} }
self.staging_buffer_size = size; self.staging_buffer_size = self.required_staging_buffer_size;
} }
} }
fn setup_uniform_buffer_resources( 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, &mut self,
id: I,
uniforms: &T, uniforms: &T,
dynamic_uniforms: bool, dynamic_uniforms: bool,
render_resource_context: &dyn RenderResourceContext, render_resource_context: &dyn RenderResourceContext,
render_resource_bindings: &mut RenderResourceBindings, render_resource_bindings: &mut RenderResourceBindings,
staging_buffer: &mut [u8], staging_buffer: &mut [u8],
) { ) {
for (i, render_resource) in uniforms.iter_render_resources().enumerate() { for (i, render_resource) in uniforms.iter().enumerate() {
match render_resource.resource_type() { match render_resource.resource_type() {
Some(RenderResourceType::Buffer) => { Some(RenderResourceType::Buffer) => {
let size = render_resource.buffer_byte_len().unwrap(); let size = render_resource.buffer_byte_len().unwrap();
let render_resource_name = uniforms.get_render_resource_name(i).unwrap(); let render_resource_name = uniforms.get_render_resource_name(i).unwrap();
let (_name, uniform_buffer_status) = self.uniform_arrays[i].as_mut().unwrap(); let buffer_array = self.buffer_arrays[i].as_mut().unwrap();
let range = 0..size as u64; let range = 0..size as u64;
let (target_buffer, target_offset) = if dynamic_uniforms { let (target_buffer, target_offset) = if dynamic_uniforms {
let buffer = uniform_buffer_status.buffer.unwrap(); let binding = buffer_array.get_binding(id).unwrap();
let index = let dynamic_index = if let RenderResourceBinding::Buffer {
uniform_buffer_status.get_or_assign_index(render_resource_bindings.id); dynamic_index: Some(dynamic_index),
render_resource_bindings.set( ..
render_resource_name, } = binding
RenderResourceBinding::Buffer { {
buffer, dynamic_index
dynamic_index: Some( } else {
(index * uniform_buffer_status.aligned_size) as u32, panic!("dynamic index should always be set");
), };
range, render_resource_bindings.set(render_resource_name, binding);
}, (buffer_array.buffer.unwrap(), dynamic_index)
);
(buffer, index * uniform_buffer_status.aligned_size)
} else { } else {
let mut matching_buffer = None; let mut matching_buffer = None;
if let Some(binding) = render_resource_bindings.get(render_resource_name) { if let Some(binding) = render_resource_bindings.get(render_resource_name) {
@ -296,22 +311,18 @@ where
(resource, 0) (resource, 0)
}; };
let staging_buffer_start = uniform_buffer_status.staging_buffer_offset
+ uniform_buffer_status.current_offset;
render_resource.write_buffer_bytes( render_resource.write_buffer_bytes(
&mut staging_buffer[staging_buffer_start..(staging_buffer_start + size)], &mut staging_buffer[self.current_staging_buffer_offset
..(self.current_staging_buffer_offset + size)],
); );
uniform_buffer_status self.queued_buffer_writes.push(QueuedBufferWrite {
.queued_buffer_writes buffer: target_buffer,
.push(QueuedBufferWrite { target_offset: target_offset as usize,
buffer: target_buffer, source_offset: self.current_staging_buffer_offset,
target_offset, size,
source_offset: uniform_buffer_status.current_offset, });
size, self.current_staging_buffer_offset += size;
});
uniform_buffer_status.current_offset += size;
} }
Some(RenderResourceType::Texture) => { /* ignore textures */ } Some(RenderResourceType::Texture) => { /* ignore textures */ }
Some(RenderResourceType::Sampler) => { /* ignore samplers */ } Some(RenderResourceType::Sampler) => { /* ignore samplers */ }
@ -325,19 +336,14 @@ where
command_queue: &mut CommandQueue, command_queue: &mut CommandQueue,
staging_buffer: BufferId, staging_buffer: BufferId,
) { ) {
for uniform_buffer_status in self.uniform_arrays.iter_mut() { for queued_buffer_write in self.queued_buffer_writes.drain(..) {
if let Some((_name, buffer_array_status)) = uniform_buffer_status { command_queue.copy_buffer_to_buffer(
let start = buffer_array_status.staging_buffer_offset; staging_buffer,
for queued_buffer_write in buffer_array_status.queued_buffer_writes.drain(..) { queued_buffer_write.source_offset as u64,
command_queue.copy_buffer_to_buffer( queued_buffer_write.buffer,
staging_buffer, queued_buffer_write.target_offset as u64,
(start + queued_buffer_write.source_offset) as u64, queued_buffer_write.size as u64,
queued_buffer_write.buffer, )
queued_buffer_write.target_offset as u64,
queued_buffer_write.size as u64,
)
}
}
} }
} }
} }
@ -391,7 +397,7 @@ where
system.id(), system.id(),
RenderResourcesNodeState { RenderResourcesNodeState {
command_queue: self.command_queue.clone(), command_queue: self.command_queue.clone(),
uniform_buffer_arrays: UniformBufferArrays::<T>::default(), uniform_buffer_arrays: UniformBufferArrays::<Entity, T>::default(),
dynamic_uniforms: self.dynamic_uniforms, dynamic_uniforms: self.dynamic_uniforms,
}, },
); );
@ -400,13 +406,13 @@ where
} }
} }
struct RenderResourcesNodeState<T: RenderResources> { struct RenderResourcesNodeState<I, T: RenderResources> {
command_queue: CommandQueue, command_queue: CommandQueue,
uniform_buffer_arrays: UniformBufferArrays<T>, uniform_buffer_arrays: UniformBufferArrays<I, T>,
dynamic_uniforms: bool, dynamic_uniforms: bool,
} }
impl<T: RenderResources> Default for RenderResourcesNodeState<T> { impl<I, T: RenderResources> Default for RenderResourcesNodeState<I, T> {
fn default() -> Self { fn default() -> Self {
Self { Self {
command_queue: Default::default(), command_queue: Default::default(),
@ -417,35 +423,29 @@ impl<T: RenderResources> Default for RenderResourcesNodeState<T> {
} }
fn render_resources_node_system<T: RenderResources>( fn render_resources_node_system<T: RenderResources>(
mut state: Local<RenderResourcesNodeState<T>>, mut state: Local<RenderResourcesNodeState<Entity, T>>,
render_resource_context: Res<Box<dyn RenderResourceContext>>, render_resource_context: Res<Box<dyn RenderResourceContext>>,
mut query: Query<(&T, &Draw, &mut RenderPipelines)>, mut query: Query<(Entity, &T, &Draw, &mut RenderPipelines)>,
) { ) {
let state = state.deref_mut(); let state = state.deref_mut();
let uniform_buffer_arrays = &mut state.uniform_buffer_arrays;
let render_resource_context = &**render_resource_context; let render_resource_context = &**render_resource_context;
state.uniform_buffer_arrays.reset_changed_item_counts(); uniform_buffer_arrays.begin_update();
// update uniforms info // initialize uniform buffer arrays using the first RenderResources
for (uniforms, draw, _render_pipelines) in &mut query.iter() { if let Some((_, first, _, _)) = query.iter().iter().next() {
if !draw.is_visible { uniform_buffer_arrays.initialize(first);
continue;
}
state
.uniform_buffer_arrays
.increment_changed_item_counts(&uniforms);
} }
state
.uniform_buffer_arrays
.setup_buffer_arrays(render_resource_context, state.dynamic_uniforms);
state
.uniform_buffer_arrays
.update_staging_buffer(render_resource_context);
for (uniforms, draw, mut render_pipelines) in &mut query.iter() { for entity in query.removed::<T>() {
uniform_buffer_arrays.remove_bindings(*entity);
}
for (entity, uniforms, draw, mut render_pipelines) in &mut query.iter() {
if !draw.is_visible { if !draw.is_visible {
continue; continue;
} }
uniform_buffer_arrays.prepare_uniform_buffers(entity, uniforms);
setup_uniform_texture_resources::<T>( setup_uniform_texture_resources::<T>(
&uniforms, &uniforms,
render_resource_context, render_resource_context,
@ -453,18 +453,22 @@ fn render_resources_node_system<T: RenderResources>(
) )
} }
uniform_buffer_arrays.resize_buffer_arrays(render_resource_context);
uniform_buffer_arrays.resize_staging_buffer(render_resource_context);
if let Some(staging_buffer) = state.uniform_buffer_arrays.staging_buffer { if let Some(staging_buffer) = state.uniform_buffer_arrays.staging_buffer {
render_resource_context.map_buffer(staging_buffer); render_resource_context.map_buffer(staging_buffer);
render_resource_context.write_mapped_buffer( render_resource_context.write_mapped_buffer(
staging_buffer, staging_buffer,
0..state.uniform_buffer_arrays.staging_buffer_size as u64, 0..state.uniform_buffer_arrays.staging_buffer_size as u64,
&mut |mut staging_buffer, _render_resource_context| { &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 { if !draw.is_visible {
continue; continue;
} }
state.uniform_buffer_arrays.setup_uniform_buffer_resources( state.uniform_buffer_arrays.write_uniform_buffers(
entity,
&uniforms, &uniforms,
state.dynamic_uniforms, state.dynamic_uniforms,
render_resource_context, render_resource_context,
@ -482,12 +486,13 @@ fn render_resources_node_system<T: RenderResources>(
} else { } else {
// TODO: can we just remove this? // TODO: can we just remove this?
let mut staging_buffer: [u8; 0] = []; 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 { if !draw.is_visible {
continue; continue;
} }
state.uniform_buffer_arrays.setup_uniform_buffer_resources( state.uniform_buffer_arrays.write_uniform_buffers(
entity,
&uniforms, &uniforms,
state.dynamic_uniforms, state.dynamic_uniforms,
render_resource_context, render_resource_context,
@ -549,7 +554,7 @@ where
system.id(), system.id(),
RenderResourcesNodeState { RenderResourcesNodeState {
command_queue: self.command_queue.clone(), command_queue: self.command_queue.clone(),
uniform_buffer_arrays: UniformBufferArrays::<T>::default(), uniform_buffer_arrays: UniformBufferArrays::<Handle<T>, T>::default(),
dynamic_uniforms: self.dynamic_uniforms, dynamic_uniforms: self.dynamic_uniforms,
}, },
); );
@ -559,64 +564,38 @@ where
} }
fn asset_render_resources_node_system<T: RenderResources>( fn asset_render_resources_node_system<T: RenderResources>(
mut state: Local<RenderResourcesNodeState<T>>, mut state: Local<RenderResourcesNodeState<Handle<T>, T>>,
assets: Res<Assets<T>>, assets: Res<Assets<T>>,
// asset_events: Res<Events<AssetEvent<T>>>,
mut asset_render_resource_bindings: ResMut<AssetRenderResourceBindings>, mut asset_render_resource_bindings: ResMut<AssetRenderResourceBindings>,
render_resource_context: Res<Box<dyn RenderResourceContext>>, render_resource_context: Res<Box<dyn RenderResourceContext>>,
mut query: Query<(&Handle<T>, &Draw, &mut RenderPipelines)>, mut query: Query<(&Handle<T>, &Draw, &mut RenderPipelines)>,
) { ) {
let state = state.deref_mut(); let state = state.deref_mut();
let uniform_buffer_arrays = &mut state.uniform_buffer_arrays;
let render_resource_context = &**render_resource_context; let render_resource_context = &**render_resource_context;
state.uniform_buffer_arrays.reset_changed_item_counts();
let modified_assets = assets let modified_assets = assets
.iter() .iter()
.map(|(handle, _)| handle) .map(|(handle, _)| handle)
.collect::<Vec<Handle<T>>>(); .collect::<Vec<Handle<T>>>();
// TODO: uncomment this when asset dependency events are added https://github.com/bevyengine/bevy/issues/26
// let mut modified_assets = HashSet::new();
// for event in asset_event_reader.iter(&asset_events) {
// match event {
// AssetEvent::Created { handle } => {
// modified_assets.insert(*handle);
// }
// AssetEvent::Modified { handle } => {
// modified_assets.insert(*handle);
// }
// AssetEvent::Removed { handle } => {
// // TODO: handle removals
// modified_assets.remove(handle);
// }
// }
// }
// update uniform handles info uniform_buffer_arrays.begin_update();
for asset_handle in modified_assets.iter() { // initialize uniform buffer arrays using the first RenderResources
let asset = assets.get(&asset_handle).expect(EXPECT_ASSET_MESSAGE); if let Some(first_handle) = modified_assets.get(0) {
state let asset = assets.get(first_handle).expect(EXPECT_ASSET_MESSAGE);
.uniform_buffer_arrays uniform_buffer_arrays.initialize(asset);
.increment_changed_item_counts(&asset);
} }
state
.uniform_buffer_arrays
.setup_buffer_arrays(render_resource_context, state.dynamic_uniforms);
state
.uniform_buffer_arrays
.update_staging_buffer(render_resource_context);
for asset_handle in modified_assets.iter() { for asset_handle in modified_assets.iter() {
let asset = assets.get(&asset_handle).expect(EXPECT_ASSET_MESSAGE); let asset = assets.get(&asset_handle).expect(EXPECT_ASSET_MESSAGE);
let mut render_resource_bindings = uniform_buffer_arrays.prepare_uniform_buffers(*asset_handle, asset);
asset_render_resource_bindings.get_or_insert_mut(*asset_handle); let mut bindings = asset_render_resource_bindings.get_or_insert_mut(*asset_handle);
setup_uniform_texture_resources::<T>( setup_uniform_texture_resources::<T>(&asset, render_resource_context, &mut bindings);
&asset,
render_resource_context,
&mut render_resource_bindings,
);
} }
uniform_buffer_arrays.resize_buffer_arrays(render_resource_context);
uniform_buffer_arrays.resize_staging_buffer(render_resource_context);
if let Some(staging_buffer) = state.uniform_buffer_arrays.staging_buffer { if let Some(staging_buffer) = state.uniform_buffer_arrays.staging_buffer {
render_resource_context.map_buffer(staging_buffer); render_resource_context.map_buffer(staging_buffer);
render_resource_context.write_mapped_buffer( render_resource_context.write_mapped_buffer(
@ -628,7 +607,8 @@ fn asset_render_resources_node_system<T: RenderResources>(
let mut render_resource_bindings = let mut render_resource_bindings =
asset_render_resource_bindings.get_or_insert_mut(*asset_handle); asset_render_resource_bindings.get_or_insert_mut(*asset_handle);
// TODO: only setup buffer if we haven't seen this handle before // TODO: only setup buffer if we haven't seen this handle before
state.uniform_buffer_arrays.setup_uniform_buffer_resources( state.uniform_buffer_arrays.write_uniform_buffers(
*asset_handle,
&asset, &asset,
state.dynamic_uniforms, state.dynamic_uniforms,
render_resource_context, render_resource_context,
@ -650,7 +630,8 @@ fn asset_render_resources_node_system<T: RenderResources>(
let mut render_resource_bindings = let mut render_resource_bindings =
asset_render_resource_bindings.get_or_insert_mut(*asset_handle); asset_render_resource_bindings.get_or_insert_mut(*asset_handle);
// TODO: only setup buffer if we haven't seen this handle before // TODO: only setup buffer if we haven't seen this handle before
state.uniform_buffer_arrays.setup_uniform_buffer_resources( state.uniform_buffer_arrays.write_uniform_buffers(
*asset_handle,
&asset, &asset,
state.dynamic_uniforms, state.dynamic_uniforms,
render_resource_context, render_resource_context,
@ -677,7 +658,7 @@ fn setup_uniform_texture_resources<T>(
) where ) where
T: renderer::RenderResources, T: renderer::RenderResources,
{ {
for (i, render_resource) in uniforms.iter_render_resources().enumerate() { for (i, render_resource) in uniforms.iter().enumerate() {
if let Some(RenderResourceType::Texture) = render_resource.resource_type() { if let Some(RenderResourceType::Texture) = render_resource.resource_type() {
let render_resource_name = uniforms.get_render_resource_name(i).unwrap(); let render_resource_name = uniforms.get_render_resource_name(i).unwrap();
let sampler_name = format!("{}_sampler", render_resource_name); let sampler_name = format!("{}_sampler", render_resource_name);

View File

@ -86,7 +86,7 @@ pub trait RenderResources: Send + Sync + 'static {
fn get_render_resource_hints(&self, _index: usize) -> Option<RenderResourceHints> { fn get_render_resource_hints(&self, _index: usize) -> Option<RenderResourceHints> {
None None
} }
fn iter_render_resources(&self) -> RenderResourceIterator; fn iter(&self) -> RenderResourceIterator;
} }
pub struct RenderResourceIterator<'a> { pub struct RenderResourceIterator<'a> {
@ -200,7 +200,7 @@ impl RenderResources for bevy_transform::prelude::Transform {
} }
} }
fn iter_render_resources(&self) -> RenderResourceIterator { fn iter(&self) -> RenderResourceIterator {
RenderResourceIterator::new(self) RenderResourceIterator::new(self)
} }
} }