use {
super::{Cache, Lease, Pool},
crate::driver::{
accel_struct::{
AccelerationStructure, AccelerationStructureInfo, AccelerationStructureInfoBuilder,
},
buffer::{Buffer, BufferInfo, BufferInfoBuilder},
device::Device,
image::{Image, ImageInfo, ImageInfoBuilder},
CommandBuffer, CommandBufferInfo, DescriptorPool, DescriptorPoolInfo, DriverError,
RenderPass, RenderPassInfo,
},
parking_lot::Mutex,
std::{
collections::{HashMap, VecDeque},
fmt::Debug,
sync::Arc,
},
};
#[derive(Debug)]
pub struct HashPool {
acceleration_structure_cache: HashMap<AccelerationStructureInfo, Cache<AccelerationStructure>>,
buffer_cache: HashMap<BufferInfo, Cache<Buffer>>,
command_buffer_cache: HashMap<u32, Cache<CommandBuffer>>,
descriptor_pool_cache: HashMap<DescriptorPoolInfo, Cache<DescriptorPool>>,
device: Arc<Device>,
image_cache: HashMap<ImageInfo, Cache<Image>>,
render_pass_cache: HashMap<RenderPassInfo, Cache<RenderPass>>,
}
impl HashPool {
pub fn new(device: &Arc<Device>) -> Self {
let device = Arc::clone(device);
Self {
acceleration_structure_cache: Default::default(),
buffer_cache: Default::default(),
command_buffer_cache: Default::default(),
descriptor_pool_cache: Default::default(),
device,
image_cache: Default::default(),
render_pass_cache: Default::default(),
}
}
}
impl HashPool {
fn can_lease_command_buffer(cmd_buf: &mut CommandBuffer) -> bool {
let can_lease = unsafe {
cmd_buf
.device
.get_fence_status(cmd_buf.fence)
.unwrap_or_default()
};
if can_lease {
CommandBuffer::drop_fenced(cmd_buf);
}
can_lease
}
}
impl Pool<CommandBufferInfo, CommandBuffer> for HashPool {
#[profiling::function]
fn lease(&mut self, info: CommandBufferInfo) -> Result<Lease<CommandBuffer>, DriverError> {
let command_buffer_cache = self
.command_buffer_cache
.entry(info.queue_family_index)
.or_default();
let cache_ref = Arc::downgrade(command_buffer_cache);
let mut cache = command_buffer_cache.lock();
if cache.is_empty() || !Self::can_lease_command_buffer(cache.front_mut().unwrap()) {
let item = CommandBuffer::create(&self.device, info)?;
return Ok(Lease {
cache: Some(cache_ref),
item: Some(item),
});
}
Ok(Lease {
cache: Some(cache_ref),
item: cache.pop_front(),
})
}
}
macro_rules! lease {
($info:ident => $item:ident) => {
paste::paste! {
impl Pool<$info, $item> for HashPool {
#[profiling::function]
fn lease(&mut self, info: $info) -> Result<Lease<$item>, DriverError> {
let cache = self.[<$item:snake _cache>].entry(info.clone())
.or_insert_with(|| {
Arc::new(Mutex::new(VecDeque::new()))
});
let cache_ref = Arc::downgrade(cache);
let mut cache = cache.lock();
if cache.is_empty() {
let item = $item::create(&self.device, info)?;
return Ok(Lease {
cache: Some(cache_ref),
item: Some(item),
});
}
Ok(Lease {
cache: Some(cache_ref),
item: cache.pop_front(),
})
}
}
}
};
}
lease!(RenderPassInfo => RenderPass);
lease!(DescriptorPoolInfo => DescriptorPool);
macro_rules! lease_builder {
($info:ident => $item:ident) => {
lease!($info => $item);
paste::paste! {
impl Pool<[<$info Builder>], $item> for HashPool {
fn lease(&mut self, builder: [<$info Builder>]) -> Result<Lease<$item>, DriverError> {
let info = builder.build();
self.lease(info)
}
}
}
};
}
lease_builder!(AccelerationStructureInfo => AccelerationStructure);
lease_builder!(BufferInfo => Buffer);
lease_builder!(ImageInfo => Image);