use {
super::{Cache, Lease, Pool, PoolConfig, lease_command_buffer, with_cache},
crate::driver::{
DriverError,
accel_struct::{AccelerationStructure, AccelerationStructureInfo},
buffer::{Buffer, BufferInfo},
cmd_buf::{CommandBuffer, CommandBufferInfo},
descriptor_set::{DescriptorPool, DescriptorPoolInfo},
device::Device,
image::{Image, ImageInfo},
render_pass::{RenderPass, RenderPassInfo},
},
log::debug,
std::{collections::HashMap, sync::Arc},
};
#[derive(Debug)]
#[read_only::cast]
pub struct FifoPool {
accel_struct_cache: Cache<AccelerationStructure>,
buffer_cache: Cache<Buffer>,
command_buffer_cache: HashMap<u32, Cache<CommandBuffer>>,
descriptor_pool_cache: Cache<DescriptorPool>,
#[readonly]
pub device: Device,
image_cache: Cache<Image>,
#[readonly]
pub info: PoolConfig,
render_pass_cache: HashMap<RenderPassInfo, Cache<RenderPass>>,
}
impl FifoPool {
pub fn new(device: &Device) -> Self {
Self::with_capacity(device, PoolConfig::default())
}
pub fn with_capacity(device: &Device, info: impl Into<PoolConfig>) -> Self {
let info: PoolConfig = info.into();
let device = device.clone();
Self {
accel_struct_cache: PoolConfig::explicit_cache(info.accel_struct_capacity),
buffer_cache: PoolConfig::explicit_cache(info.buffer_capacity),
command_buffer_cache: Default::default(),
descriptor_pool_cache: PoolConfig::default_cache(),
device,
image_cache: PoolConfig::explicit_cache(info.image_capacity),
info,
render_pass_cache: Default::default(),
}
}
pub fn clear(&mut self) {
self.clear_accel_structs();
self.clear_buffers();
self.clear_images();
}
pub fn clear_accel_structs(&mut self) {
self.accel_struct_cache = PoolConfig::explicit_cache(self.info.accel_struct_capacity);
}
pub fn clear_buffers(&mut self) {
self.buffer_cache = PoolConfig::explicit_cache(self.info.buffer_capacity);
}
pub fn clear_images(&mut self) {
self.image_cache = PoolConfig::explicit_cache(self.info.image_capacity);
}
}
impl Pool<AccelerationStructureInfo, AccelerationStructure> for FifoPool {
#[profiling::function]
fn resource(
&mut self,
info: AccelerationStructureInfo,
) -> Result<Lease<AccelerationStructure>, DriverError> {
let cache_ref = Arc::downgrade(&self.accel_struct_cache);
{
profiling::scope!("check cache");
if let Some(item) = with_cache(&self.accel_struct_cache, |cache| {
for idx in 0..cache.len() {
let item = unsafe { cache.get_unchecked(idx) };
if item.info.size >= info.size && item.info.ty == info.ty {
let item = cache.swap_remove(idx);
return Some(Lease::new(cache_ref.clone(), item));
}
}
None
}) {
return Ok(item);
}
}
debug!("Creating new {}", stringify!(AccelerationStructure));
let item = AccelerationStructure::create(&self.device, info)?;
Ok(Lease::new(cache_ref, item))
}
}
impl Pool<BufferInfo, Buffer> for FifoPool {
#[profiling::function]
fn resource(&mut self, info: BufferInfo) -> Result<Lease<Buffer>, DriverError> {
let cache_ref = Arc::downgrade(&self.buffer_cache);
{
profiling::scope!("check cache");
if let Some(item) = with_cache(&self.buffer_cache, |cache| {
for idx in 0..cache.len() {
let item = unsafe { cache.get_unchecked(idx) };
if (item.info.dedicated & info.dedicated) == info.dedicated
&& item.info.host_read == info.host_read
&& item.info.host_write == info.host_write
&& item.info.alignment >= info.alignment
&& item.info.size >= info.size
&& item.info.usage.contains(info.usage)
{
let item = cache.swap_remove(idx);
return Some(Lease::new(cache_ref.clone(), item));
}
}
None
}) {
return Ok(item);
}
}
debug!("Creating new {}", stringify!(Buffer));
let item = Buffer::create(&self.device, info)?;
Ok(Lease::new(cache_ref, item))
}
}
impl Pool<CommandBufferInfo, CommandBuffer> for FifoPool {
#[profiling::function]
fn resource(&mut self, info: CommandBufferInfo) -> Result<Lease<CommandBuffer>, DriverError> {
let cache_ref = self
.command_buffer_cache
.entry(info.queue_family_index)
.or_insert_with(PoolConfig::default_cache);
let item = with_cache(cache_ref, lease_command_buffer)
.map(Ok)
.unwrap_or_else(|| {
debug!("Creating new {}", stringify!(CommandBuffer));
CommandBuffer::create(&self.device, info)
})?;
Ok(Lease::new(Arc::downgrade(cache_ref), item))
}
}
impl Pool<DescriptorPoolInfo, DescriptorPool> for FifoPool {
#[profiling::function]
fn resource(&mut self, info: DescriptorPoolInfo) -> Result<Lease<DescriptorPool>, DriverError> {
let cache_ref = Arc::downgrade(&self.descriptor_pool_cache);
{
profiling::scope!("check cache");
if let Some(item) = with_cache(&self.descriptor_pool_cache, |cache| {
for idx in 0..cache.len() {
let item = unsafe { cache.get_unchecked(idx) };
if item.info.max_sets >= info.max_sets
&& item.info.acceleration_structure_count
>= info.acceleration_structure_count
&& item.info.combined_image_sampler_count
>= info.combined_image_sampler_count
&& item.info.input_attachment_count >= info.input_attachment_count
&& item.info.sampled_image_count >= info.sampled_image_count
&& item.info.sampler_count >= info.sampler_count
&& item.info.storage_buffer_count >= info.storage_buffer_count
&& item.info.storage_buffer_dynamic_count
>= info.storage_buffer_dynamic_count
&& item.info.storage_image_count >= info.storage_image_count
&& item.info.storage_texel_buffer_count >= info.storage_texel_buffer_count
&& item.info.uniform_buffer_count >= info.uniform_buffer_count
&& item.info.uniform_buffer_dynamic_count
>= info.uniform_buffer_dynamic_count
&& item.info.uniform_texel_buffer_count >= info.uniform_texel_buffer_count
{
let item = cache.swap_remove(idx);
return Some(Lease::new(cache_ref.clone(), item));
}
}
None
}) {
return Ok(item);
}
}
debug!("Creating new {}", stringify!(DescriptorPool));
let item = DescriptorPool::create(&self.device, info)?;
Ok(Lease::new(cache_ref, item))
}
}
impl Pool<ImageInfo, Image> for FifoPool {
#[profiling::function]
fn resource(&mut self, info: ImageInfo) -> Result<Lease<Image>, DriverError> {
let cache_ref = Arc::downgrade(&self.image_cache);
{
profiling::scope!("check cache");
if let Some(item) = with_cache(&self.image_cache, |cache| {
for idx in 0..cache.len() {
let item = unsafe { cache.get_unchecked(idx) };
if item.info.array_layer_count == info.array_layer_count
&& item.info.dedicated == info.dedicated
&& item.info.depth == info.depth
&& item.info.fmt == info.fmt
&& item.info.height == info.height
&& item.info.mip_level_count == info.mip_level_count
&& item.info.sample_count == info.sample_count
&& item.info.tiling == info.tiling
&& item.info.ty == info.ty
&& item.info.width == info.width
&& item.info.flags.contains(info.flags)
&& item.info.usage.contains(info.usage)
{
let item = cache.swap_remove(idx);
return Some(Lease::new(cache_ref.clone(), item));
}
}
None
}) {
return Ok(item);
}
}
debug!("Creating new {}", stringify!(Image));
let item = Image::create(&self.device, info)?;
Ok(Lease::new(cache_ref, item))
}
}
impl Pool<RenderPassInfo, RenderPass> for FifoPool {
#[profiling::function]
fn resource(&mut self, info: RenderPassInfo) -> Result<Lease<RenderPass>, DriverError> {
let cache_ref = if let Some(cache) = self.render_pass_cache.get(&info) {
cache
} else {
self.render_pass_cache
.entry(info.clone())
.or_insert_with(PoolConfig::default_cache)
};
let item = with_cache(cache_ref, |cache| cache.pop())
.map(Ok)
.unwrap_or_else(|| {
debug!("Creating new {}", stringify!(RenderPass));
RenderPass::create(&self.device, info)
})?;
Ok(Lease::new(Arc::downgrade(cache_ref), item))
}
}