use super::{
layout::DescriptorSetLayout,
pool::{
DescriptorPoolAlloc, DescriptorPoolAllocError, DescriptorSetAllocateInfo,
UnsafeDescriptorPool, UnsafeDescriptorPoolCreateInfo,
},
sys::UnsafeDescriptorSet,
DescriptorSet, DescriptorSetCreationError, DescriptorSetInner, DescriptorSetResources,
WriteDescriptorSet,
};
use crate::{
device::{Device, DeviceOwned},
OomError, VulkanObject,
};
use crossbeam_queue::SegQueue;
use std::{
hash::{Hash, Hasher},
sync::Arc,
};
pub struct SingleLayoutDescSetPool {
inner: Option<Arc<SingleLayoutPool>>,
device: Arc<Device>,
set_count: usize,
layout: Arc<DescriptorSetLayout>,
}
impl SingleLayoutDescSetPool {
pub fn new(layout: Arc<DescriptorSetLayout>) -> Self {
assert!(
!layout.push_descriptor(),
"the provided descriptor set layout is for push descriptors, and cannot be used to build a descriptor set object"
);
assert!(
layout.variable_descriptor_count() == 0,
"the provided descriptor set layout has a binding with a variable descriptor count, which cannot be used with SingleLayoutDescSetPool"
);
Self {
inner: None,
device: layout.device().clone(),
set_count: 4,
layout,
}
}
#[inline]
pub fn next(
&mut self,
descriptor_writes: impl IntoIterator<Item = WriteDescriptorSet>,
) -> Result<Arc<SingleLayoutDescSet>, DescriptorSetCreationError> {
let alloc = self.next_alloc()?;
let inner = DescriptorSetInner::new(
alloc.inner().internal_object(),
self.layout.clone(),
0,
descriptor_writes,
)?;
Ok(Arc::new(SingleLayoutDescSet { alloc, inner }))
}
fn next_alloc(&mut self) -> Result<SingleLayoutPoolAlloc, OomError> {
loop {
let mut not_enough_sets = false;
if let Some(ref mut p_inner) = self.inner {
if let Some(existing) = p_inner.reserve.pop() {
return Ok(SingleLayoutPoolAlloc {
pool: p_inner.clone(),
inner: Some(existing),
});
} else {
not_enough_sets = true;
}
}
if not_enough_sets {
self.set_count *= 2;
}
let mut unsafe_pool = UnsafeDescriptorPool::new(
self.device.clone(),
UnsafeDescriptorPoolCreateInfo {
max_sets: self.set_count as u32,
pool_sizes: self
.layout
.descriptor_counts()
.iter()
.map(|(&ty, &count)| (ty, count * self.set_count as u32))
.collect(),
..Default::default()
},
)?;
let reserve = unsafe {
match unsafe_pool.allocate_descriptor_sets((0..self.set_count).map(|_| {
DescriptorSetAllocateInfo {
layout: self.layout.as_ref(),
variable_descriptor_count: 0,
}
})) {
Ok(alloc_iter) => {
let reserve = SegQueue::new();
for alloc in alloc_iter {
reserve.push(alloc);
}
reserve
}
Err(DescriptorPoolAllocError::OutOfHostMemory) => {
return Err(OomError::OutOfHostMemory);
}
Err(DescriptorPoolAllocError::OutOfDeviceMemory) => {
return Err(OomError::OutOfDeviceMemory);
}
Err(DescriptorPoolAllocError::FragmentedPool) => {
unreachable!()
}
Err(DescriptorPoolAllocError::OutOfPoolMemory) => unreachable!(),
}
};
self.inner = Some(Arc::new(SingleLayoutPool {
inner: unsafe_pool,
reserve,
}));
}
}
}
struct SingleLayoutPool {
inner: UnsafeDescriptorPool,
reserve: SegQueue<UnsafeDescriptorSet>,
}
struct SingleLayoutPoolAlloc {
pool: Arc<SingleLayoutPool>,
inner: Option<UnsafeDescriptorSet>,
}
impl DescriptorPoolAlloc for SingleLayoutPoolAlloc {
#[inline]
fn inner(&self) -> &UnsafeDescriptorSet {
self.inner.as_ref().unwrap()
}
#[inline]
fn inner_mut(&mut self) -> &mut UnsafeDescriptorSet {
self.inner.as_mut().unwrap()
}
}
impl Drop for SingleLayoutPoolAlloc {
fn drop(&mut self) {
let inner = self.inner.take().unwrap();
self.pool.reserve.push(inner);
}
}
pub struct SingleLayoutDescSet {
alloc: SingleLayoutPoolAlloc,
inner: DescriptorSetInner,
}
unsafe impl DescriptorSet for SingleLayoutDescSet {
#[inline]
fn inner(&self) -> &UnsafeDescriptorSet {
self.alloc.inner()
}
#[inline]
fn layout(&self) -> &Arc<DescriptorSetLayout> {
self.inner.layout()
}
#[inline]
fn resources(&self) -> &DescriptorSetResources {
self.inner.resources()
}
}
unsafe impl DeviceOwned for SingleLayoutDescSet {
#[inline]
fn device(&self) -> &Arc<Device> {
self.inner.layout().device()
}
}
impl PartialEq for SingleLayoutDescSet {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.inner().internal_object() == other.inner().internal_object()
&& self.device() == other.device()
}
}
impl Eq for SingleLayoutDescSet {}
impl Hash for SingleLayoutDescSet {
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
self.inner().internal_object().hash(state);
self.device().hash(state);
}
}