render: support arbitrary RenderResource byte lengths and temporarily disable RenderResource asset change events

This commit is contained in:
Carter Anderson 2020-06-13 18:34:50 -07:00
parent 8803bcd92e
commit 6362b2a516

View File

@ -9,20 +9,18 @@ use crate::{
texture, texture,
}; };
use bevy_app::{EventReader, Events}; use bevy_asset::{Assets, Handle};
use bevy_asset::{AssetEvent, Assets, Handle};
use legion::prelude::*; use legion::prelude::*;
use render_resource::ResourceInfo; use render_resource::ResourceInfo;
use std::{ use std::{collections::HashMap, marker::PhantomData};
collections::{HashMap, HashSet},
marker::PhantomData,
};
pub const BIND_BUFFER_ALIGNMENT: usize = 256; pub const BIND_BUFFER_ALIGNMENT: usize = 256;
#[derive(Debug)] #[derive(Debug)]
struct QueuedBufferWrite { struct QueuedBufferWrite {
buffer: RenderResourceId, buffer: RenderResourceId,
offset: usize, target_offset: usize,
source_offset: usize,
size: usize,
} }
#[derive(Debug)] #[derive(Debug)]
@ -37,6 +35,9 @@ struct BufferArrayStatus {
current_item_capacity: usize, current_item_capacity: usize,
indices: HashMap<RenderResourceAssignmentsId, usize>, indices: HashMap<RenderResourceAssignmentsId, usize>,
current_index: 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 BufferArrayStatus {
@ -84,6 +85,8 @@ where
for buffer_status in self.uniform_arrays.iter_mut() { for buffer_status in self.uniform_arrays.iter_mut() {
if let Some((_name, buffer_status)) = buffer_status { if let Some((_name, buffer_status)) = buffer_status {
buffer_status.changed_item_count = 0; buffer_status.changed_item_count = 0;
buffer_status.current_offset = 0;
buffer_status.changed_size = 0;
} }
} }
} }
@ -99,6 +102,7 @@ where
let size = render_resource.buffer_byte_len().unwrap(); let size = render_resource.buffer_byte_len().unwrap();
if let Some((ref _name, ref mut buffer_array_status)) = self.uniform_arrays[i] { 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_item_count += 1;
buffer_array_status.changed_size += size;
} else { } else {
self.uniform_arrays[i] = Some(( self.uniform_arrays[i] = Some((
render_resource_name.to_string(), render_resource_name.to_string(),
@ -113,6 +117,8 @@ where
current_item_count: 0, current_item_count: 0,
current_item_capacity: 0, current_item_capacity: 0,
indices: HashMap::new(), indices: HashMap::new(),
changed_size: size,
current_offset: 0,
}, },
)) ))
} }
@ -179,7 +185,7 @@ where
for dynamic_buffer_array_status in self.uniform_arrays.iter_mut() { for dynamic_buffer_array_status in self.uniform_arrays.iter_mut() {
if let Some((_name, ref mut buffer_array_status)) = dynamic_buffer_array_status { if let Some((_name, ref mut buffer_array_status)) = dynamic_buffer_array_status {
buffer_array_status.staging_buffer_offset = size; buffer_array_status.staging_buffer_offset = size;
size += buffer_array_status.item_size * buffer_array_status.changed_item_count; size += buffer_array_status.changed_size;
} }
} }
@ -217,12 +223,36 @@ where
); );
(buffer, index * uniform_buffer_status.aligned_size) (buffer, index * uniform_buffer_status.aligned_size)
} else { } else {
let resource = match render_resource_assignments.get(render_resource_name) { let mut matching_buffer = None;
Some(assignment) => assignment.get_resource(), let mut buffer_to_remove = None;
None => { if let Some(assignment) =
// TODO: RE-ADD support for BufferUsage::STORAGE type render_resource_assignments.get(render_resource_name)
let mut usage = BufferUsage::UNIFORM; {
let resource = assignment.get_resource();
render_resources.get_resource_info(resource, &mut |info| {
if let Some(ResourceInfo::Buffer(Some(BufferInfo {
size: current_size,
..
}))) = info
{
if size == *current_size {
matching_buffer = Some(resource);
} else {
// TODO: if get_resource_info returns a type instead of taking a closure, move buffer free here
buffer_to_remove = Some(resource);
}
}
})
}
if let Some(buffer) = buffer_to_remove {
render_resources.remove_buffer(buffer);
}
let resource = if let Some(matching_buffer) = matching_buffer {
matching_buffer
} else {
let mut usage = BufferUsage::UNIFORM;
if let Some(render_resource_hints) = if let Some(render_resource_hints) =
uniforms.get_render_resource_hints(i) uniforms.get_render_resource_hints(i)
{ {
@ -246,15 +276,14 @@ where
}, },
); );
resource resource
}
}; };
(resource, 0) (resource, 0)
}; };
let staging_buffer_start = uniform_buffer_status.staging_buffer_offset let staging_buffer_start = uniform_buffer_status.staging_buffer_offset
+ (uniform_buffer_status.queued_buffer_writes.len() + uniform_buffer_status.current_offset;
* uniform_buffer_status.item_size);
render_resource.write_buffer_bytes( render_resource.write_buffer_bytes(
&mut staging_buffer[staging_buffer_start..(staging_buffer_start + size)], &mut staging_buffer[staging_buffer_start..(staging_buffer_start + size)],
); );
@ -263,8 +292,11 @@ where
.queued_buffer_writes .queued_buffer_writes
.push(QueuedBufferWrite { .push(QueuedBufferWrite {
buffer: target_buffer, buffer: target_buffer,
offset: target_offset, target_offset,
source_offset: uniform_buffer_status.current_offset,
size,
}); });
uniform_buffer_status.current_offset += size;
} }
Some(ResourceInfo::Texture(_)) => { /* ignore textures */ } Some(ResourceInfo::Texture(_)) => { /* ignore textures */ }
Some(ResourceInfo::Sampler) => { /* ignore samplers */ } Some(ResourceInfo::Sampler) => { /* ignore samplers */ }
@ -281,17 +313,13 @@ where
for uniform_buffer_status in self.uniform_arrays.iter_mut() { for uniform_buffer_status in self.uniform_arrays.iter_mut() {
if let Some((_name, buffer_array_status)) = uniform_buffer_status { if let Some((_name, buffer_array_status)) = uniform_buffer_status {
let start = buffer_array_status.staging_buffer_offset; let start = buffer_array_status.staging_buffer_offset;
for (i, queued_buffer_write) in buffer_array_status for queued_buffer_write in buffer_array_status.queued_buffer_writes.drain(..) {
.queued_buffer_writes
.drain(..)
.enumerate()
{
command_queue.copy_buffer_to_buffer( command_queue.copy_buffer_to_buffer(
staging_buffer, staging_buffer,
(start + (i * buffer_array_status.item_size)) as u64, (start + queued_buffer_write.source_offset) as u64,
queued_buffer_write.buffer, queued_buffer_write.buffer,
queued_buffer_write.offset as u64, queued_buffer_write.target_offset as u64,
buffer_array_status.item_size as u64, queued_buffer_write.size as u64,
) )
} }
} }
@ -473,33 +501,38 @@ where
fn get_system(&self) -> Box<dyn Schedulable> { fn get_system(&self) -> Box<dyn Schedulable> {
let mut command_queue = self.command_queue.clone(); let mut command_queue = self.command_queue.clone();
let mut uniform_buffer_arrays = UniformBufferArrays::<T>::default(); let mut uniform_buffer_arrays = UniformBufferArrays::<T>::default();
let mut asset_event_reader = EventReader::<AssetEvent<T>>::default(); // let mut asset_event_reader = EventReader::<AssetEvent<T>>::default();
let mut asset_render_resource_assignments = let mut asset_render_resource_assignments =
HashMap::<Handle<T>, RenderResourceAssignments>::default(); HashMap::<Handle<T>, RenderResourceAssignments>::default();
let dynamic_uniforms = self.dynamic_uniforms; let dynamic_uniforms = self.dynamic_uniforms;
(move |world: &mut SubWorld, (move |world: &mut SubWorld,
assets: Res<Assets<T>>, assets: Res<Assets<T>>,
asset_events: Res<Events<AssetEvent<T>>>, // asset_events: Res<Events<AssetEvent<T>>>,
render_resources: Res<RenderResources>, render_resources: Res<RenderResources>,
query: &mut Query<(Read<Handle<T>>, Read<Draw>, Write<RenderPipelines>)>| { query: &mut Query<(Read<Handle<T>>, Read<Draw>, Write<RenderPipelines>)>| {
let render_resource_context = &*render_resources.context; let render_resource_context = &*render_resources.context;
uniform_buffer_arrays.reset_changed_item_counts(); uniform_buffer_arrays.reset_changed_item_counts();
let mut modified_assets = HashSet::new(); let modified_assets = assets
for event in asset_event_reader.iter(&asset_events) { .iter()
match event { .map(|(handle, _)| handle)
AssetEvent::Created { handle } => { .collect::<Vec<Handle<T>>>();
modified_assets.insert(*handle); // TODO: uncomment this when asset dependency events are added https://github.com/bevyengine/bevy/issues/26
} // let mut modified_assets = HashSet::new();
AssetEvent::Modified { handle } => { // for event in asset_event_reader.iter(&asset_events) {
modified_assets.insert(*handle); // match event {
} // AssetEvent::Created { handle } => {
AssetEvent::Removed { handle } => { // modified_assets.insert(*handle);
// TODO: handle removals // }
modified_assets.remove(handle); // AssetEvent::Modified { handle } => {
} // modified_assets.insert(*handle);
} // }
} // AssetEvent::Removed { handle } => {
// // TODO: handle removals
// modified_assets.remove(handle);
// }
// }
// }
// update uniform handles info // update uniform handles info
for asset_handle in modified_assets.iter() { for asset_handle in modified_assets.iter() {
@ -569,8 +602,12 @@ where
} }
for (asset_handle, _draw, mut render_pipelines) in query.iter_mut(world) { for (asset_handle, _draw, mut render_pipelines) in query.iter_mut(world) {
if let Some(asset_assignments) = asset_render_resource_assignments.get(&asset_handle) { if let Some(asset_assignments) =
render_pipelines.render_resource_assignments.extend(asset_assignments); asset_render_resource_assignments.get(&asset_handle)
{
render_pipelines
.render_resource_assignments
.extend(asset_assignments);
} }
} }
}) })
@ -596,6 +633,7 @@ fn setup_uniform_texture_resources<T>(
let sampler_resource = render_resource_context let sampler_resource = render_resource_context
.get_asset_resource(texture_handle, texture::SAMPLER_ASSET_INDEX) .get_asset_resource(texture_handle, texture::SAMPLER_ASSET_INDEX)
.unwrap(); .unwrap();
render_resource_assignments.set( render_resource_assignments.set(
render_resource_name, render_resource_name,
RenderResourceAssignment::Texture(texture_resource), RenderResourceAssignment::Texture(texture_resource),