bevy_render: delegate buffer aligning to render_resource_context (#842)

This commit is contained in:
Mariusz Kryński 2020-11-11 23:08:27 +01:00 committed by GitHub
parent ec7ad4254c
commit fae628797f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 50 additions and 62 deletions

View file

@ -15,12 +15,6 @@ use bevy_utils::HashMap;
use renderer::{AssetRenderResourceBindings, BufferId, RenderResourceType, RenderResources}; use renderer::{AssetRenderResourceBindings, BufferId, RenderResourceType, RenderResources};
use std::{hash::Hash, marker::PhantomData, ops::DerefMut}; use std::{hash::Hash, marker::PhantomData, ops::DerefMut};
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,
@ -42,13 +36,9 @@ struct BufferArray<I> {
} }
impl<I: Hash + Eq> BufferArray<I> { impl<I: Hash + Eq> BufferArray<I> {
pub fn new(item_size: usize, min_capacity: usize, align: bool) -> Self { pub fn new(item_size: usize, min_capacity: usize) -> Self {
BufferArray { BufferArray {
item_size: if align { item_size,
get_aligned_dynamic_uniform_size(item_size)
} else {
item_size
},
len: 0, len: 0,
buffer_capacity: 0, buffer_capacity: 0,
min_capacity, min_capacity,
@ -158,13 +148,18 @@ where
T: renderer::RenderResources, T: renderer::RenderResources,
{ {
/// Initialize this UniformBufferArrays using information from a RenderResources value. /// Initialize this UniformBufferArrays using information from a RenderResources value.
fn initialize(&mut self, render_resources: &T) { fn initialize(
&mut self,
render_resources: &T,
render_resource_context: &dyn RenderResourceContext,
) {
if self.buffer_arrays.len() != render_resources.render_resources_len() { if self.buffer_arrays.len() != render_resources.render_resources_len() {
let mut buffer_arrays = Vec::with_capacity(render_resources.render_resources_len()); let mut buffer_arrays = Vec::with_capacity(render_resources.render_resources_len());
for render_resource in render_resources.iter() { for render_resource in render_resources.iter() {
if let Some(RenderResourceType::Buffer) = render_resource.resource_type() { if let Some(RenderResourceType::Buffer) = render_resource.resource_type() {
let size = render_resource.buffer_byte_len().unwrap(); let size = render_resource.buffer_byte_len().unwrap();
buffer_arrays.push(Some(BufferArray::new(size, 10, true))); let aligned_size = render_resource_context.get_aligned_uniform_size(size, true);
buffer_arrays.push(Some(BufferArray::new(aligned_size, 10)));
} else { } else {
buffer_arrays.push(None); buffer_arrays.push(None);
} }
@ -247,8 +242,10 @@ where
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 aligned_size =
render_resource_context.get_aligned_uniform_size(size, false);
let buffer_array = self.buffer_arrays[i].as_mut().unwrap(); let buffer_array = self.buffer_arrays[i].as_mut().unwrap();
let range = 0..size as u64; let range = 0..aligned_size as u64;
let (target_buffer, target_offset) = if dynamic_uniforms { let (target_buffer, target_offset) = if dynamic_uniforms {
let binding = buffer_array.get_binding(id).unwrap(); let binding = buffer_array.get_binding(id).unwrap();
let dynamic_index = if let RenderResourceBinding::Buffer { let dynamic_index = if let RenderResourceBinding::Buffer {
@ -270,7 +267,7 @@ where
size: current_size, .. size: current_size, ..
}) = render_resource_context.get_buffer_info(buffer_id) }) = render_resource_context.get_buffer_info(buffer_id)
{ {
if size == current_size { if aligned_size == current_size {
matching_buffer = Some(buffer_id); matching_buffer = Some(buffer_id);
} else { } else {
render_resource_context.remove_buffer(buffer_id); render_resource_context.remove_buffer(buffer_id);
@ -291,7 +288,7 @@ where
} }
let buffer = render_resource_context.create_buffer(BufferInfo { let buffer = render_resource_context.create_buffer(BufferInfo {
size, size: aligned_size,
buffer_usage: BufferUsage::COPY_DST | usage, buffer_usage: BufferUsage::COPY_DST | usage,
..Default::default() ..Default::default()
}); });
@ -432,7 +429,7 @@ fn render_resources_node_system<T: RenderResources>(
uniform_buffer_arrays.begin_update(); uniform_buffer_arrays.begin_update();
// initialize uniform buffer arrays using the first RenderResources // initialize uniform buffer arrays using the first RenderResources
if let Some((_, first, _, _)) = query.iter_mut().next() { if let Some((_, first, _, _)) = query.iter_mut().next() {
uniform_buffer_arrays.initialize(first); uniform_buffer_arrays.initialize(first, render_resource_context);
} }
for entity in query.removed::<T>() { for entity in query.removed::<T>() {
@ -482,23 +479,6 @@ fn render_resources_node_system<T: RenderResources>(
state state
.uniform_buffer_arrays .uniform_buffer_arrays
.copy_staging_buffer_to_final_buffers(&mut state.command_queue, staging_buffer); .copy_staging_buffer_to_final_buffers(&mut state.command_queue, staging_buffer);
} else {
// TODO: can we just remove this?
let mut staging_buffer: [u8; 0] = [];
for (entity, uniforms, draw, mut render_pipelines) in query.iter_mut() {
if !draw.is_visible {
continue;
}
state.uniform_buffer_arrays.write_uniform_buffers(
entity,
&uniforms,
state.dynamic_uniforms,
render_resource_context,
&mut render_pipelines.bindings,
&mut staging_buffer,
);
}
} }
} }
@ -579,7 +559,7 @@ fn asset_render_resources_node_system<T: RenderResources + Asset>(
// initialize uniform buffer arrays using the first RenderResources // initialize uniform buffer arrays using the first RenderResources
if let Some(first_handle) = modified_assets.get(0) { if let Some(first_handle) = modified_assets.get(0) {
let asset = assets.get(*first_handle).expect(EXPECT_ASSET_MESSAGE); let asset = assets.get(*first_handle).expect(EXPECT_ASSET_MESSAGE);
uniform_buffer_arrays.initialize(asset); uniform_buffer_arrays.initialize(asset, render_resource_context);
} }
for asset_handle in modified_assets.iter() { for asset_handle in modified_assets.iter() {
@ -620,22 +600,6 @@ fn asset_render_resources_node_system<T: RenderResources + Asset>(
state state
.uniform_buffer_arrays .uniform_buffer_arrays
.copy_staging_buffer_to_final_buffers(&mut state.command_queue, staging_buffer); .copy_staging_buffer_to_final_buffers(&mut state.command_queue, staging_buffer);
} else {
let mut staging_buffer: [u8; 0] = [];
for asset_handle in modified_assets.iter() {
let asset = assets.get(*asset_handle).expect(EXPECT_ASSET_MESSAGE);
let mut render_resource_bindings =
asset_render_resource_bindings.get_or_insert_mut(&Handle::<T>::weak(*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,
&mut render_resource_bindings,
&mut staging_buffer,
);
}
} }
for (asset_handle, draw, mut render_pipelines) in query.iter_mut() { for (asset_handle, draw, mut render_pipelines) in query.iter_mut() {

View file

@ -12,11 +12,6 @@ pub struct TextureCopyNode {
pub texture_event_reader: EventReader<AssetEvent<Texture>>, pub texture_event_reader: EventReader<AssetEvent<Texture>>,
} }
pub const ALIGNMENT: usize = 256;
fn get_aligned(data_size: f32) -> usize {
ALIGNMENT * ((data_size / ALIGNMENT as f32).ceil() as usize)
}
impl Node for TextureCopyNode { impl Node for TextureCopyNode {
fn update( fn update(
&mut self, &mut self,
@ -34,7 +29,9 @@ impl Node for TextureCopyNode {
if let Some(texture) = textures.get(handle) { if let Some(texture) = textures.get(handle) {
let texture_descriptor: TextureDescriptor = texture.into(); let texture_descriptor: TextureDescriptor = texture.into();
let width = texture.size.x() as usize; let width = texture.size.x() as usize;
let aligned_width = get_aligned(texture.size.x()); let aligned_width = render_context
.resources()
.get_aligned_texture_size(texture.size.x() as usize);
let format_size = texture.format.pixel_size(); let format_size = texture.format.pixel_size();
let mut aligned_data = let mut aligned_data =
vec![0; format_size * aligned_width * texture.size.y() as usize]; vec![0; format_size * aligned_width * texture.size.y() as usize];

View file

@ -140,4 +140,12 @@ impl RenderResourceContext for HeadlessRenderResourceContext {
) -> bool { ) -> bool {
false false
} }
fn get_aligned_uniform_size(&self, size: usize, _dynamic: bool) -> usize {
size
}
fn get_aligned_texture_size(&self, size: usize) -> usize {
size
}
} }

View file

@ -31,9 +31,12 @@ impl SharedBuffers {
buffer_usage: BufferUsage, buffer_usage: BufferUsage,
) -> Option<RenderResourceBinding> { ) -> Option<RenderResourceBinding> {
if let Some(size) = render_resource.buffer_byte_len() { if let Some(size) = render_resource.buffer_byte_len() {
let aligned_size = self
.render_resource_context
.get_aligned_uniform_size(size, false);
// PERF: this buffer will be slow // PERF: this buffer will be slow
let staging_buffer = self.render_resource_context.create_buffer(BufferInfo { let staging_buffer = self.render_resource_context.create_buffer(BufferInfo {
size, size: aligned_size,
buffer_usage: BufferUsage::COPY_SRC | BufferUsage::MAP_WRITE, buffer_usage: BufferUsage::COPY_SRC | BufferUsage::MAP_WRITE,
mapped_at_creation: true, mapped_at_creation: true,
}); });
@ -49,7 +52,7 @@ impl SharedBuffers {
self.render_resource_context.unmap_buffer(staging_buffer); self.render_resource_context.unmap_buffer(staging_buffer);
let destination_buffer = self.render_resource_context.create_buffer(BufferInfo { let destination_buffer = self.render_resource_context.create_buffer(BufferInfo {
size, size: aligned_size,
buffer_usage: BufferUsage::COPY_DST | buffer_usage, buffer_usage: BufferUsage::COPY_DST | buffer_usage,
..Default::default() ..Default::default()
}); });
@ -68,7 +71,7 @@ impl SharedBuffers {
buffers.push(destination_buffer); buffers.push(destination_buffer);
Some(RenderResourceBinding::Buffer { Some(RenderResourceBinding::Buffer {
buffer: destination_buffer, buffer: destination_buffer,
range: 0..size as u64, range: 0..aligned_size as u64,
dynamic_index: None, dynamic_index: None,
}) })
} else { } else {

View file

@ -33,7 +33,8 @@ pub trait RenderResourceContext: Downcast + Send + Sync + 'static {
fn remove_texture(&self, texture: TextureId); fn remove_texture(&self, texture: TextureId);
fn remove_sampler(&self, sampler: SamplerId); fn remove_sampler(&self, sampler: SamplerId);
fn get_buffer_info(&self, buffer: BufferId) -> Option<BufferInfo>; fn get_buffer_info(&self, buffer: BufferId) -> Option<BufferInfo>;
fn get_aligned_uniform_size(&self, size: usize, dynamic: bool) -> usize;
fn get_aligned_texture_size(&self, data_size: usize) -> usize;
fn set_asset_resource_untyped( fn set_asset_resource_untyped(
&self, &self,
handle: HandleUntyped, handle: HandleUntyped,

View file

@ -26,6 +26,9 @@ pub struct WgpuRenderResourceContext {
pub resources: WgpuResources, pub resources: WgpuResources,
} }
pub const BIND_BUFFER_ALIGNMENT: usize = 256;
pub const TEXTURE_ALIGNMENT: usize = 256;
impl WgpuRenderResourceContext { impl WgpuRenderResourceContext {
pub fn new(device: Arc<wgpu::Device>) -> Self { pub fn new(device: Arc<wgpu::Device>) -> Self {
WgpuRenderResourceContext { WgpuRenderResourceContext {
@ -553,4 +556,16 @@ impl RenderResourceContext for WgpuRenderResourceContext {
let buffer = buffers.get(&id).unwrap(); let buffer = buffers.get(&id).unwrap();
buffer.unmap(); buffer.unmap();
} }
fn get_aligned_texture_size(&self, size: usize) -> usize {
(size + TEXTURE_ALIGNMENT - 1) & !(TEXTURE_ALIGNMENT - 1)
}
fn get_aligned_uniform_size(&self, size: usize, dynamic: bool) -> usize {
if dynamic {
(size + BIND_BUFFER_ALIGNMENT - 1) & !(BIND_BUFFER_ALIGNMENT - 1)
} else {
size
}
}
} }