pub mod cache;
pub mod fifo;
pub mod hash;
pub mod lazy;
use {
crate::driver::{
DriverError,
accel_struct::{
AccelerationStructure, AccelerationStructureInfo, AccelerationStructureInfoBuilder,
},
buffer::{Buffer, BufferInfo, BufferInfoBuilder},
cmd_buf::CommandBuffer,
image::{Image, ImageInfo, ImageInfoBuilder},
},
derive_builder::{Builder, UninitializedFieldError},
std::{
fmt::Debug,
mem::ManuallyDrop,
ops::{Deref, DerefMut},
sync::{Arc, Weak},
thread::panicking,
},
};
#[cfg(feature = "parking_lot")]
use parking_lot::Mutex;
#[cfg(not(feature = "parking_lot"))]
use std::sync::Mutex;
type Cache<T> = Arc<Mutex<Vec<T>>>;
type CacheRef<T> = Weak<Mutex<Vec<T>>>;
fn lease_command_buffer(cache: &mut Vec<CommandBuffer>) -> Option<CommandBuffer> {
for idx in 0..cache.len() {
if unsafe {
let cmd = cache.get_unchecked(idx);
cmd.device.get_fence_status(cmd.fence).unwrap_or_default()
} {
return Some(cache.swap_remove(idx));
}
}
None
}
fn with_cache<T, R>(cache: &Cache<T>, f: impl FnOnce(&mut Vec<T>) -> R) -> R {
let cache = cache.lock();
#[cfg(not(feature = "parking_lot"))]
let cache = cache.expect("poisoned cache lock");
let mut cache = cache;
f(&mut cache)
}
#[derive(Debug)]
pub struct Lease<T> {
cache_ref: CacheRef<T>,
item: ManuallyDrop<T>,
}
impl Lease<AccelerationStructure> {
pub fn debug_name(mut self, name: impl Into<String>) -> Self {
self.name = Some(name.into());
self
}
}
impl Lease<Buffer> {
pub fn debug_name(mut self, name: impl Into<String>) -> Self {
self.name = Some(name.into());
self
}
}
impl Lease<Image> {
pub fn debug_name(mut self, name: impl Into<String>) -> Self {
self.name = Some(name.into());
self
}
}
impl<T> Lease<T> {
fn new(cache_ref: CacheRef<T>, item: T) -> Self {
Self {
cache_ref,
item: ManuallyDrop::new(item),
}
}
}
impl<T> Deref for Lease<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.item
}
}
impl<T> DerefMut for Lease<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.item
}
}
impl<T> Drop for Lease<T> {
#[profiling::function]
fn drop(&mut self) {
if panicking() {
return;
}
if let Some(cache) = self.cache_ref.upgrade() {
with_cache(&cache, |cache| {
if cache.len() >= cache.capacity() {
cache.pop();
}
cache.push(unsafe { ManuallyDrop::take(&mut self.item) });
});
} else {
unsafe {
ManuallyDrop::drop(&mut self.item);
}
}
}
}
pub trait Pool<I, T> {
#[deprecated = "use resource function"]
#[doc(hidden)]
fn lease(&mut self, info: I) -> Result<Lease<T>, DriverError> {
self.resource(info)
}
fn resource(&mut self, info: I) -> Result<Lease<T>, DriverError>;
}
macro_rules! lease_builder {
($info:ident => $item:ident) => {
paste::paste! {
impl<T> Pool<[<$info Builder>], $item> for T where T: Pool<$info, $item> {
fn resource(
&mut self,
builder: [<$info Builder>],
) -> Result<Lease<$item>, DriverError> {
let info = builder.build();
self.resource(info)
}
}
}
};
}
lease_builder!(AccelerationStructureInfo => AccelerationStructure);
lease_builder!(BufferInfo => Buffer);
lease_builder!(ImageInfo => Image);
#[derive(Builder, Clone, Copy, Debug, Eq, PartialEq)]
#[builder(
build_fn(private, name = "fallible_build", error = "UninitializedFieldError"),
derive(Clone, Copy, Debug),
pattern = "owned"
)]
pub struct PoolConfig {
#[builder(
default = "PoolConfig::DEFAULT_RESOURCE_CAPACITY",
setter(strip_option)
)]
pub accel_struct_capacity: usize,
#[builder(
default = "PoolConfig::DEFAULT_RESOURCE_CAPACITY",
setter(strip_option)
)]
pub buffer_capacity: usize,
#[builder(
default = "PoolConfig::DEFAULT_RESOURCE_CAPACITY",
setter(strip_option)
)]
pub image_capacity: usize,
}
impl PoolConfig {
pub const DEFAULT_RESOURCE_CAPACITY: usize = 16;
pub fn builder() -> PoolConfigBuilder {
Default::default()
}
fn default_cache<T>() -> Cache<T> {
Cache::new(Mutex::new(Vec::with_capacity(
Self::DEFAULT_RESOURCE_CAPACITY,
)))
}
fn explicit_cache<T>(capacity: usize) -> Cache<T> {
Cache::new(Mutex::new(Vec::with_capacity(capacity)))
}
pub fn into_builder(self) -> PoolConfigBuilder {
PoolConfigBuilder {
accel_struct_capacity: Some(self.accel_struct_capacity),
buffer_capacity: Some(self.buffer_capacity),
image_capacity: Some(self.image_capacity),
}
}
#[deprecated = "use into_builder function"]
#[doc(hidden)]
pub fn to_builder(self) -> PoolConfigBuilder {
self.into_builder()
}
pub const fn with_capacity(resource_capacity: usize) -> Self {
Self {
accel_struct_capacity: resource_capacity,
buffer_capacity: resource_capacity,
image_capacity: resource_capacity,
}
}
}
impl Default for PoolConfig {
fn default() -> Self {
PoolConfigBuilder::default().into()
}
}
impl From<PoolConfigBuilder> for PoolConfig {
fn from(info: PoolConfigBuilder) -> Self {
info.build()
}
}
impl From<usize> for PoolConfig {
fn from(value: usize) -> Self {
Self {
accel_struct_capacity: value,
buffer_capacity: value,
image_capacity: value,
}
}
}
impl PoolConfigBuilder {
pub fn build(self) -> PoolConfig {
self.fallible_build().expect("invalid pool config")
}
}
#[doc(hidden)]
#[deprecated = "use PoolConfig instead"]
pub type PoolInfo = PoolConfig;
#[doc(hidden)]
#[deprecated = "use PoolConfigBuilder instead"]
pub type PoolInfoBuilder = PoolConfigBuilder;
mod deprecated {
use {
crate::pool::Lease,
std::convert::{AsMut, AsRef},
};
impl<T> Lease<T> {
#[allow(clippy::should_implement_trait)]
#[deprecated = "use Deref impl"]
#[doc(hidden)]
pub fn as_ref(&self) -> &T {
&self.item
}
#[allow(clippy::should_implement_trait)]
#[deprecated = "use DerefMut impl"]
#[doc(hidden)]
pub fn as_mut(&mut self) -> &mut T {
&mut self.item
}
}
impl<T> AsRef<T> for Lease<T> {
fn as_ref(&self) -> &T {
&self.item
}
}
impl<T> AsMut<T> for Lease<T> {
fn as_mut(&mut self) -> &mut T {
&mut self.item
}
}
}
#[cfg(test)]
mod test {
use super::*;
type Info = PoolConfig;
type Builder = PoolConfigBuilder;
#[test]
pub fn pool_info() {
let info = Info::default();
let builder = info.into_builder().build();
assert_eq!(info, builder);
}
#[test]
pub fn pool_info_builder() {
let info = Info {
accel_struct_capacity: 1,
buffer_capacity: 2,
image_capacity: 3,
};
let builder = Builder::default()
.accel_struct_capacity(1)
.buffer_capacity(2)
.image_capacity(3)
.build();
assert_eq!(info, builder);
}
}