bevy/crates/bevy_render/src/render_resource/shared_buffers.rs
2020-06-16 22:23:33 -07:00

88 lines
3.0 KiB
Rust

use super::{BufferId, BufferInfo, RenderResource, RenderResourceBinding};
use crate::{
render_graph::CommandQueue, render_resource::BufferUsage, renderer::RenderResourceContext,
};
use legion::systems::Res;
use std::sync::{Arc, RwLock};
// TODO: Instead of allocating small "exact size" buffers each frame, this should use multiple large shared buffers and probably
// a long-living "cpu mapped" staging buffer. Im punting that for now because I don't know the best way to use wgpu's new async
// buffer mapping yet.
pub struct SharedBuffers {
render_resource_context: Box<dyn RenderResourceContext>,
buffers: Arc<RwLock<Vec<BufferId>>>,
command_queue: Arc<RwLock<CommandQueue>>,
}
impl SharedBuffers {
pub fn new(render_resource_context: Box<dyn RenderResourceContext>) -> Self {
Self {
render_resource_context,
buffers: Default::default(),
command_queue: Default::default(),
}
}
pub fn get_buffer<T: RenderResource>(
&self,
render_resource: &T,
buffer_usage: BufferUsage,
) -> Option<RenderResourceBinding> {
if let Some(size) = render_resource.buffer_byte_len() {
// PERF: this buffer will be slow
let staging_buffer = self.render_resource_context.create_buffer_mapped(
BufferInfo {
size,
buffer_usage: BufferUsage::COPY_SRC,
},
&mut |data, _renderer| {
render_resource.write_buffer_bytes(data);
},
);
let destination_buffer = self.render_resource_context.create_buffer(BufferInfo {
size,
buffer_usage: BufferUsage::COPY_DST | buffer_usage,
});
let mut command_queue = self.command_queue.write().unwrap();
command_queue.copy_buffer_to_buffer(
staging_buffer,
0,
destination_buffer,
0,
size as u64,
);
let mut buffers = self.buffers.write().unwrap();
buffers.push(staging_buffer);
buffers.push(destination_buffer);
Some(RenderResourceBinding::Buffer {
buffer: destination_buffer,
range: 0..size as u64,
dynamic_index: None,
})
} else {
None
}
}
// TODO: remove this when this actually uses shared buffers
pub fn free_buffers(&self) {
let mut buffers = self.buffers.write().unwrap();
for buffer in buffers.drain(..) {
self.render_resource_context.remove_buffer(buffer)
}
}
pub fn reset_command_queue(&self) -> CommandQueue {
let mut command_queue = self.command_queue.write().unwrap();
std::mem::replace(&mut *command_queue, CommandQueue::default())
}
}
// TODO: remove this when this actually uses shared buffers
pub fn free_shared_buffers_system(shared_buffers: Res<SharedBuffers>) {
shared_buffers.free_buffers();
}