use super::VulkanCommandBuffer;
use crate::{IVulkanPlatformGraphicsContext, VulkanException, VulkanResultExtensions};
use ash::vk;
use std::cell::{Cell, RefCell};
use std::collections::VecDeque;
use std::rc::{Rc, Weak};
pub(crate) struct VulkanCommandBufferPool {
context: Rc<dyn IVulkanPlatformGraphicsContext>,
auto_free: bool,
command_buffers: RefCell<VecDeque<Rc<VulkanCommandBuffer>>>,
handle: Cell<vk::CommandPool>,
this: Weak<VulkanCommandBufferPool>,
}
impl VulkanCommandBufferPool {
pub fn new(context: Rc<dyn IVulkanPlatformGraphicsContext>, auto_free: bool) -> Result<Rc<Self>, VulkanException> {
let create_info = vk::CommandPoolCreateInfo::default()
.flags(vk::CommandPoolCreateFlags::RESET_COMMAND_BUFFER)
.queue_family_index(context.graphics_queue_family_index());
let handle = context
.device_api()
.create_command_pool(context.device_handle(), &create_info)
.throw_on_error("vkCreateCommandPool")?;
Ok(Rc::new_cyclic(|this| Self {
context,
auto_free,
command_buffers: RefCell::new(VecDeque::new()),
handle: Cell::new(handle),
this: this.clone(),
}))
}
pub fn handle(&self) -> vk::CommandPool {
self.handle.get()
}
pub fn free_used_command_buffers(&self) {
loop {
let next = self.command_buffers.borrow_mut().pop_front();
match next {
Some(buffer) => buffer.dispose(),
None => break,
}
}
}
pub fn free_finished_command_buffers(&self) {
loop {
let next = {
let mut command_buffers = self.command_buffers.borrow_mut();
match command_buffers.front() {
Some(next) if next.is_finished() => command_buffers.pop_front(),
_ => None,
}
};
match next {
Some(buffer) => buffer.dispose(),
None => return,
}
}
}
pub fn dispose(&self) {
self.free_used_command_buffers();
if self.handle.get() != vk::CommandPool::null() {
self.context.device_api().destroy_command_pool(self.context.device_handle(), self.handle.get());
}
self.handle.set(vk::CommandPool::null());
}
pub fn create_command_buffer(&self) -> Result<Rc<VulkanCommandBuffer>, VulkanException> {
if self.auto_free {
self.free_finished_command_buffers();
}
let command_buffer_allocate_info = vk::CommandBufferAllocateInfo::default()
.command_pool(self.handle.get())
.command_buffer_count(1)
.level(vk::CommandBufferLevel::PRIMARY);
let buffer_handle = self
.context
.device_api()
.allocate_command_buffers(self.context.device_handle(), &command_buffer_allocate_info)
.throw_on_error("vkAllocateCommandBuffers")?[0];
let this = self.this.upgrade().expect("a pool that is called is alive");
VulkanCommandBuffer::new(&this, buffer_handle, self.context.clone())
}
pub fn add_submitted_command_buffer(&self, buffer: Rc<VulkanCommandBuffer>) {
self.command_buffers.borrow_mut().push_back(buffer);
}
}