use ash::vk;
use concinnity_core::render::error::{RenderError, RenderResult};
use std::sync::Mutex;
use crate::vulkan::descriptor_layout::PoolSizes;
use crate::vulkan::error::map_vk_result;
use crate::vulkan::owned::{OwnedDescriptorPool, VkDevice};
use crate::vulkan::resources::source_set_bindings;
const SETS_PER_FRAME: u32 = 48;
const SOURCES_PER_SET: u32 = 8;
pub(in crate::vulkan) struct PostSetArena {
slots: Vec<Mutex<PoolSlot>>,
}
struct PoolSlot {
pool: OwnedDescriptorPool,
}
impl PostSetArena {
pub(in crate::vulkan) fn new(device: &VkDevice, frames: usize) -> RenderResult<Self> {
let sizes = PoolSizes::default()
.sets(&source_set_bindings(SOURCES_PER_SET), SETS_PER_FRAME)
.build();
let mut slots = Vec::with_capacity(frames.max(1));
for _ in 0..frames.max(1) {
let pool = device
.create_descriptor_pool(
&vk::DescriptorPoolCreateInfo::default()
.pool_sizes(&sizes)
.max_sets(SETS_PER_FRAME),
)
.map_err(|e| map_vk_result(e, "post descriptor pool"))?;
slots.push(Mutex::new(PoolSlot { pool }));
}
Ok(Self { slots })
}
pub(in crate::vulkan) fn begin_frame(&self, device: &VkDevice, frame: usize) {
let Ok(slot) = self.slots[frame % self.slots.len()].lock() else {
tracing::error!("post descriptor arena poisoned");
return;
};
let reset = unsafe {
device.reset_descriptor_pool(slot.pool.handle(), vk::DescriptorPoolResetFlags::empty())
};
if let Err(e) = reset {
tracing::error!("post descriptor pool reset: {e}");
}
}
pub(in crate::vulkan) fn alloc(
&self,
device: &VkDevice,
frame: usize,
layout: vk::DescriptorSetLayout,
) -> RenderResult<vk::DescriptorSet> {
let slot = self.slots[frame % self.slots.len()]
.lock()
.map_err(|_| RenderError::Other("post descriptor arena poisoned".to_string()))?;
let layouts = [layout];
let sets =
crate::vulkan::resources::alloc_descriptor_sets(device, slot.pool.handle(), &layouts)?;
sets.into_iter()
.next()
.ok_or_else(|| RenderError::Other("post descriptor arena returned no set".to_string()))
}
}