use super::{BufferId, BufferInfo, RenderResource, RenderResourceBinding};
use crate::{
render_graph::CommandQueue,
renderer::{BufferUsage, RenderResourceContext},
};
use bevy_ecs::Res;
use std::sync::{Arc, RwLock};
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() {
let staging_buffer = self.render_resource_context.create_buffer(BufferInfo {
size,
buffer_usage: BufferUsage::COPY_SRC | BufferUsage::MAP_WRITE,
mapped_at_creation: true,
});
self.render_resource_context.write_mapped_buffer(
staging_buffer,
0..size as u64,
&mut |data, _renderer| {
render_resource.write_buffer_bytes(data);
},
);
self.render_resource_context.unmap_buffer(staging_buffer);
let destination_buffer = self.render_resource_context.create_buffer(BufferInfo {
size,
buffer_usage: BufferUsage::COPY_DST | buffer_usage,
..Default::default()
});
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
}
}
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())
}
}
pub fn free_shared_buffers_system(shared_buffers: Res<SharedBuffers>) {
shared_buffers.free_buffers();
}