Skip to content

Commit

Permalink
Add FifoPool and configurable pool bucket sizes
Browse files Browse the repository at this point in the history
  • Loading branch information
attackgoat committed Jan 28, 2024
1 parent a334604 commit 0aa680f
Show file tree
Hide file tree
Showing 6 changed files with 429 additions and 97 deletions.
2 changes: 1 addition & 1 deletion examples/msaa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ fn main() -> anyhow::Result<()> {
let mesh_msaa_pipeline = create_mesh_pipeline(&event_loop.device, sample_count)?;
let mesh_noaa_pipeline = create_mesh_pipeline(&event_loop.device, SampleCount::X1)?;
let cube_mesh = load_cube_mesh(&event_loop.device)?;
let mut pool = HashPool::new(&event_loop.device);
let mut pool = FifoPool::new(&event_loop.device);

let mut angle = 0f32;

Expand Down
5 changes: 4 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,10 @@ pub mod prelude {
input::{
update_input, update_keyboard, update_mouse, KeyBuf, KeyMap, MouseBuf, MouseButton,
},
pool::{hash::HashPool, lazy::LazyPool, Lease, Pool},
pool::{
fifo::FifoPool, hash::HashPool, lazy::LazyPool, Lease, Pool, PoolInfo,
PoolInfoBuilder,
},
},
ash::vk,
log::{debug, error, info, logger, trace, warn}, // Everyone wants a log
Expand Down
227 changes: 227 additions & 0 deletions src/pool/fifo.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
//! TODO
use {
super::{can_lease_command_buffer, Cache, Lease, Pool, PoolInfo},
crate::driver::{
accel_struct::{AccelerationStructure, AccelerationStructureInfo},
buffer::{Buffer, BufferInfo},
device::Device,
image::{Image, ImageInfo},
CommandBuffer, CommandBufferInfo, DescriptorPool, DescriptorPoolInfo, DriverError,
RenderPass, RenderPassInfo,
},
std::{collections::HashMap, sync::Arc},
};

/// A space-efficient resource allocator.
#[derive(Debug)]
pub struct FifoPool {
accel_struct_cache: Cache<AccelerationStructure>,
buffer_cache: Cache<Buffer>,
command_buffer_cache: HashMap<u32, Cache<CommandBuffer>>,
descriptor_pool_cache: Cache<DescriptorPool>,
device: Arc<Device>,
image_cache: Cache<Image>,
render_pass_cache: HashMap<RenderPassInfo, Cache<RenderPass>>,
}

impl FifoPool {
/// Constructs a new `FifoPool`.
pub fn new(device: &Arc<Device>) -> Self {
Self::with_capacity(device, PoolInfo::default())
}

/// Constructs a new `FifoPool` with the given capacity information.
pub fn with_capacity(device: &Arc<Device>, info: impl Into<PoolInfo>) -> Self {
let info: PoolInfo = info.into();
let device = Arc::clone(device);

Self {
accel_struct_cache: PoolInfo::explicit_cache(info.accel_struct_capacity),
buffer_cache: PoolInfo::explicit_cache(info.buffer_capacity),
command_buffer_cache: Default::default(),
descriptor_pool_cache: PoolInfo::default_cache(),
device,
image_cache: PoolInfo::explicit_cache(info.image_capacity),
render_pass_cache: Default::default(),
}
}
}

impl Pool<AccelerationStructureInfo, AccelerationStructure> for FifoPool {
#[profiling::function]
fn lease(
&mut self,
info: AccelerationStructureInfo,
) -> Result<Lease<AccelerationStructure>, DriverError> {
let cache_ref = Arc::downgrade(&self.accel_struct_cache);
let mut cache = self.accel_struct_cache.lock();

{
profiling::scope!("Check cache");

// Look for a compatible acceleration structure (big enough and same type)
for idx in 0..cache.len() {
let item = &cache[idx];
if item.info.size >= info.size && item.info.ty == info.ty {
let item = cache.remove(idx).unwrap();

return Ok(Lease::new(cache_ref, item));
}
}
}

let item = AccelerationStructure::create(&self.device, info)?;

Ok(Lease::new(cache_ref, item))
}
}

impl Pool<BufferInfo, Buffer> for FifoPool {
#[profiling::function]
fn lease(&mut self, info: BufferInfo) -> Result<Lease<Buffer>, DriverError> {
let cache_ref = Arc::downgrade(&self.buffer_cache);
let mut cache = self.buffer_cache.lock();

{
profiling::scope!("Check cache");

// Look for a compatible buffer (compatible alignment, same mapping mode, big enough and
// superset of usage flags)
for idx in 0..cache.len() {
let item = &cache[idx];
if item.info.alignment >= info.alignment
&& item.info.can_map == info.can_map
&& item.info.size >= info.size
&& item.info.usage.contains(info.usage)
{
let item = cache.remove(idx).unwrap();

return Ok(Lease::new(cache_ref, item));
}
}
}

let item = Buffer::create(&self.device, info)?;

Ok(Lease::new(cache_ref, item))
}
}

impl Pool<CommandBufferInfo, CommandBuffer> for FifoPool {
#[profiling::function]
fn lease(&mut self, info: CommandBufferInfo) -> Result<Lease<CommandBuffer>, DriverError> {
let cache = self
.command_buffer_cache
.entry(info.queue_family_index)
.or_insert_with(PoolInfo::default_cache);
let mut item = cache
.lock()
.pop_front()
.filter(can_lease_command_buffer)
.map(Ok)
.unwrap_or_else(|| CommandBuffer::create(&self.device, info))?;

// Drop anything we were holding from the last submission
CommandBuffer::drop_fenced(&mut item);

Ok(Lease::new(Arc::downgrade(cache), item))
}
}

impl Pool<DescriptorPoolInfo, DescriptorPool> for FifoPool {
#[profiling::function]
fn lease(&mut self, info: DescriptorPoolInfo) -> Result<Lease<DescriptorPool>, DriverError> {
let cache_ref = Arc::downgrade(&self.descriptor_pool_cache);
let mut cache = self.descriptor_pool_cache.lock();

{
profiling::scope!("Check cache");

// Look for a compatible descriptor pool (has enough sets and descriptors)
for idx in 0..cache.len() {
let item = &cache[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.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.remove(idx).unwrap();

return Ok(Lease::new(cache_ref, item));
}
}
}

let item = DescriptorPool::create(&self.device, info)?;

Ok(Lease::new(cache_ref, item))
}
}

impl Pool<ImageInfo, Image> for FifoPool {
#[profiling::function]
fn lease(&mut self, info: ImageInfo) -> Result<Lease<Image>, DriverError> {
let cache_ref = Arc::downgrade(&self.image_cache);
let mut cache = self.image_cache.lock();

{
profiling::scope!("Check cache");

// Look for a compatible image (same properties, superset of creation flags and usage
// flags)
for idx in 0..cache.len() {
let item = &cache[idx];
if item.info.array_elements == info.array_elements
&& item.info.depth == info.depth
&& item.info.fmt == info.fmt
&& item.info.height == info.height
&& item.info.linear_tiling == info.linear_tiling
&& item.info.mip_level_count == info.mip_level_count
&& item.info.sample_count == info.sample_count
&& 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.remove(idx).unwrap();

return Ok(Lease::new(cache_ref, item));
}
}
}

let item = Image::create(&self.device, info)?;

Ok(Lease::new(cache_ref, item))
}
}

impl Pool<RenderPassInfo, RenderPass> for FifoPool {
#[profiling::function]
fn lease(&mut self, info: RenderPassInfo) -> Result<Lease<RenderPass>, DriverError> {
let cache = if let Some(cache) = self.render_pass_cache.get(&info) {
cache
} else {
// We tried to get the cache first in order to avoid this clone
self.render_pass_cache
.entry(info.clone())
.or_insert_with(PoolInfo::default_cache)
};
let item = cache
.lock()
.pop_front()
.map(Ok)
.unwrap_or_else(|| RenderPass::create(&self.device, info))?;

Ok(Lease::new(Arc::downgrade(cache), item))
}
}
70 changes: 38 additions & 32 deletions src/pool/hash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,12 @@
//! the exact information provided then a new resource is created and returned.
use {
super::{can_lease_command_buffer, Cache, Lease, Pool},
super::{can_lease_command_buffer, Cache, Lease, Pool, PoolInfo},
crate::driver::{
accel_struct::{
AccelerationStructure, AccelerationStructureInfo, AccelerationStructureInfoBuilder,
},
buffer::{Buffer, BufferInfo, BufferInfoBuilder},
accel_struct::{AccelerationStructure, AccelerationStructureInfo},
buffer::{Buffer, BufferInfo},
device::Device,
image::{Image, ImageInfo, ImageInfoBuilder},
image::{Image, ImageInfo},
CommandBuffer, CommandBufferInfo, DescriptorPool, DescriptorPoolInfo, DriverError,
RenderPass, RenderPassInfo,
},
Expand All @@ -32,12 +30,19 @@ pub struct HashPool {
descriptor_pool_cache: HashMap<DescriptorPoolInfo, Cache<DescriptorPool>>,
device: Arc<Device>,
image_cache: HashMap<ImageInfo, Cache<Image>>,
info: PoolInfo,
render_pass_cache: HashMap<RenderPassInfo, Cache<RenderPass>>,
}

impl HashPool {
/// Constructs a new `HashPool`.
pub fn new(device: &Arc<Device>) -> Self {
Self::with_capacity(device, PoolInfo::default())
}

/// Constructs a new `HashPool` with the given capacity information.
pub fn with_capacity(device: &Arc<Device>, info: impl Into<PoolInfo>) -> Self {
let info: PoolInfo = info.into();
let device = Arc::clone(device);

Self {
Expand All @@ -47,6 +52,7 @@ impl HashPool {
descriptor_pool_cache: Default::default(),
device,
image_cache: Default::default(),
info,
render_pass_cache: Default::default(),
}
}
Expand Down Expand Up @@ -111,7 +117,7 @@ impl Pool<CommandBufferInfo, CommandBuffer> for HashPool {
let cache = self
.command_buffer_cache
.entry(info.queue_family_index)
.or_default();
.or_insert_with(PoolInfo::default_cache);
let mut item = cache
.lock()
.pop_front()
Expand All @@ -126,14 +132,33 @@ impl Pool<CommandBufferInfo, CommandBuffer> for HashPool {
}
}

impl Pool<DescriptorPoolInfo, DescriptorPool> for HashPool {
#[profiling::function]
fn lease(&mut self, info: DescriptorPoolInfo) -> Result<Lease<DescriptorPool>, DriverError> {
let cache = self
.descriptor_pool_cache
.entry(info.clone())
.or_insert_with(PoolInfo::default_cache);
let item = cache
.lock()
.pop_front()
.map(Ok)
.unwrap_or_else(|| DescriptorPool::create(&self.device, info))?;

Ok(Lease::new(Arc::downgrade(cache), item))
}
}

impl Pool<RenderPassInfo, RenderPass> for HashPool {
#[profiling::function]
fn lease(&mut self, info: RenderPassInfo) -> Result<Lease<RenderPass>, DriverError> {
let cache = if let Some(cache) = self.render_pass_cache.get(&info) {
cache
} else {
// We tried to get the cache first in order to avoid this clone
self.render_pass_cache.entry(info.clone()).or_default()
self.render_pass_cache
.entry(info.clone())
.or_insert_with(PoolInfo::default_cache)
};
let item = cache
.lock()
Expand All @@ -147,14 +172,14 @@ impl Pool<RenderPassInfo, RenderPass> for HashPool {

// Enable leasing items using their basic info
macro_rules! lease {
($info:ident => $item:ident) => {
($info:ident => $item:ident, $capacity: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()))
Cache::new(Mutex::new(VecDeque::with_capacity(self.info.$capacity)))
});
let item = cache.lock().pop_front().map(Ok).unwrap_or_else(|| $item::create(&self.device, info))?;

Expand All @@ -165,25 +190,6 @@ macro_rules! lease {
};
}

lease!(DescriptorPoolInfo => DescriptorPool);

// Enable leasing items as above, but also using their info builder type for convenience
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);
lease!(AccelerationStructureInfo => AccelerationStructure, accel_struct_capacity);
lease!(BufferInfo => Buffer, buffer_capacity);
lease!(ImageInfo => Image, image_capacity);
Loading

0 comments on commit 0aa680f

Please sign in to comment.