use std::sync::Arc;
use std::sync::Mutex;
use OomError;
use descriptor::descriptor_set::DescriptorPool;
use descriptor::descriptor_set::DescriptorPoolAlloc;
use descriptor::descriptor_set::DescriptorPoolAllocError;
use descriptor::descriptor_set::DescriptorsCount;
use descriptor::descriptor_set::UnsafeDescriptorPool;
use descriptor::descriptor_set::UnsafeDescriptorSet;
use descriptor::descriptor_set::UnsafeDescriptorSetLayout;
use device::Device;
use device::DeviceOwned;
pub struct StdDescriptorPool {
device: Arc<Device>,
pools: Mutex<Vec<Arc<Mutex<Pool>>>>,
}
struct Pool {
pool: UnsafeDescriptorPool,
remaining_capacity: DescriptorsCount,
remaining_sets_count: u32,
}
impl StdDescriptorPool {
pub fn new(device: Arc<Device>) -> StdDescriptorPool {
StdDescriptorPool {
device: device,
pools: Mutex::new(Vec::new()),
}
}
}
pub struct StdDescriptorPoolAlloc {
pool: Arc<Mutex<Pool>>,
set: Option<UnsafeDescriptorSet>,
descriptors: DescriptorsCount,
pool_parent: Arc<StdDescriptorPool>,
}
unsafe impl DescriptorPool for Arc<StdDescriptorPool> {
type Alloc = StdDescriptorPoolAlloc;
fn alloc(&mut self, layout: &UnsafeDescriptorSetLayout)
-> Result<StdDescriptorPoolAlloc, OomError> {
let mut pools = self.pools.lock().unwrap();
for pool_arc in pools.iter_mut() {
let mut pool = pool_arc.lock().unwrap();
if pool.remaining_sets_count == 0 {
continue;
}
if !(pool.remaining_capacity >= *layout.descriptors_count()) {
continue;
}
pool.remaining_sets_count -= 1;
pool.remaining_capacity -= *layout.descriptors_count();
let alloc = unsafe {
match pool.pool.alloc(Some(layout)) {
Ok(mut sets) => sets.next().unwrap(),
Err(_) => continue,
}
};
return Ok(StdDescriptorPoolAlloc {
pool: pool_arc.clone(),
set: Some(alloc),
descriptors: *layout.descriptors_count(),
pool_parent: self.clone(),
});
}
let count = layout.descriptors_count().clone() * 40;
let mut new_pool = UnsafeDescriptorPool::new(self.device.clone(), &count, 40, true)?;
let alloc = unsafe {
match new_pool.alloc(Some(layout)) {
Ok(mut sets) => sets.next().unwrap(),
Err(DescriptorPoolAllocError::OutOfHostMemory) => {
return Err(OomError::OutOfHostMemory);
},
Err(DescriptorPoolAllocError::OutOfDeviceMemory) => {
return Err(OomError::OutOfDeviceMemory);
},
Err(DescriptorPoolAllocError::FragmentedPool) => unreachable!(),
Err(DescriptorPoolAllocError::OutOfPoolMemory) => unreachable!(),
}
};
let pool_obj = Arc::new(Mutex::new(Pool {
pool: new_pool,
remaining_capacity: count -
*layout.descriptors_count(),
remaining_sets_count: 40 - 1,
}));
pools.push(pool_obj.clone());
Ok(StdDescriptorPoolAlloc {
pool: pool_obj,
set: Some(alloc),
descriptors: *layout.descriptors_count(),
pool_parent: self.clone(),
})
}
}
unsafe impl DeviceOwned for StdDescriptorPool {
#[inline]
fn device(&self) -> &Arc<Device> {
&self.device
}
}
impl DescriptorPoolAlloc for StdDescriptorPoolAlloc {
#[inline]
fn inner(&self) -> &UnsafeDescriptorSet {
self.set.as_ref().unwrap()
}
#[inline]
fn inner_mut(&mut self) -> &mut UnsafeDescriptorSet {
self.set.as_mut().unwrap()
}
}
impl Drop for StdDescriptorPoolAlloc {
fn drop(&mut self) {
unsafe {
let mut pool = self.pool.lock().unwrap();
pool.pool.free(self.set.take()).unwrap();
pool.remaining_sets_count += 1;
pool.remaining_capacity += self.descriptors;
}
}
}
#[cfg(test)]
mod tests {
use std::iter;
use std::sync::Arc;
use descriptor::descriptor::DescriptorDesc;
use descriptor::descriptor::DescriptorDescTy;
use descriptor::descriptor::ShaderStages;
use descriptor::descriptor_set::DescriptorPool;
use descriptor::descriptor_set::StdDescriptorPool;
use descriptor::descriptor_set::UnsafeDescriptorSetLayout;
#[test]
fn desc_pool_kept_alive() {
let (device, _) = gfx_dev_and_queue!();
let desc = DescriptorDesc {
ty: DescriptorDescTy::Sampler,
array_count: 1,
stages: ShaderStages::all(),
readonly: false,
};
let layout = UnsafeDescriptorSetLayout::new(device.clone(), iter::once(Some(desc))).unwrap();
let mut pool = Arc::new(StdDescriptorPool::new(device));
let pool_weak = Arc::downgrade(&pool);
let alloc = pool.alloc(&layout);
drop(pool);
assert!(pool_weak.upgrade().is_some());
}
}