screen_13/pool/
alias.rs

1//! Pool wrapper which enables memory-efficient resource aliasing.
2
3use {
4    super::{Lease, Pool},
5    crate::driver::{
6        DriverError,
7        accel_struct::{
8            AccelerationStructure, AccelerationStructureInfo, AccelerationStructureInfoBuilder,
9        },
10        buffer::{Buffer, BufferInfo, BufferInfoBuilder},
11        image::{Image, ImageInfo, ImageInfoBuilder},
12    },
13    log::debug,
14    std::{
15        ops::{Deref, DerefMut},
16        sync::{Arc, Weak},
17    },
18};
19
20/// Allows aliasing of resources using driver information structures.
21pub trait Alias<I, T> {
22    /// Aliases a resource.
23    fn alias(&mut self, info: I) -> Result<Arc<Lease<T>>, DriverError>;
24}
25
26// Enable aliasing items using their info builder type for convenience
27macro_rules! alias_builder {
28    ($info:ident => $item:ident) => {
29        paste::paste! {
30            impl<T> Alias<[<$info Builder>], $item> for T where T: Alias<$info, $item> {
31                fn alias(&mut self, builder: [<$info Builder>]) -> Result<Arc<Lease<$item>>, DriverError> {
32                    let info = builder.build();
33
34                    self.alias(info)
35                }
36            }
37        }
38    };
39}
40
41alias_builder!(AccelerationStructureInfo => AccelerationStructure);
42alias_builder!(BufferInfo => Buffer);
43alias_builder!(ImageInfo => Image);
44
45/// A memory-efficient resource wrapper for any [`Pool`] type.
46///
47/// The information for each alias request is compared against the actively aliased resources for
48/// compatibility. If no acceptable resources are aliased for the information provided a new
49/// resource is leased and returned.
50///
51/// All regular leasing and other functionality of the wrapped pool is available through `Deref` and
52/// `DerefMut`.
53///
54/// **_NOTE:_** You must call `alias(..)` to use resource aliasing as regular `lease(..)` calls will
55/// not inspect or return aliased resources.
56///
57/// # Details
58///
59/// * Acceleration structures may be larger than requested
60/// * Buffers may be larger than requested or have additional usage flags
61/// * Images may have additional usage flags
62///
63/// # Examples
64///
65/// See [`aliasing.rs`](https://github.com/attackgoat/screen-13/blob/master/examples/aliasing.rs)
66pub struct AliasPool<T> {
67    accel_structs: Vec<(
68        AccelerationStructureInfo,
69        Weak<Lease<AccelerationStructure>>,
70    )>,
71    buffers: Vec<(BufferInfo, Weak<Lease<Buffer>>)>,
72    images: Vec<(ImageInfo, Weak<Lease<Image>>)>,
73    pool: T,
74}
75
76impl<T> AliasPool<T> {
77    /// Creates a new aliasable wrapper over the given pool.
78    pub fn new(pool: T) -> Self {
79        Self {
80            accel_structs: Default::default(),
81            buffers: Default::default(),
82            images: Default::default(),
83            pool,
84        }
85    }
86}
87
88// Enable aliasing items using their info builder type for convenience
89macro_rules! lease_pass_through {
90    ($info:ident => $item:ident) => {
91        paste::paste! {
92            impl<T> Pool<$info, $item> for AliasPool<T> where T: Pool<$info, $item> {
93                fn lease(&mut self, info: $info) -> Result<Lease<$item>, DriverError> {
94                    self.pool.lease(info)
95                }
96            }
97        }
98    };
99}
100
101lease_pass_through!(AccelerationStructureInfo => AccelerationStructure);
102lease_pass_through!(BufferInfo => Buffer);
103lease_pass_through!(ImageInfo => Image);
104
105impl<T> Alias<AccelerationStructureInfo, AccelerationStructure> for AliasPool<T>
106where
107    T: Pool<AccelerationStructureInfo, AccelerationStructure>,
108{
109    fn alias(
110        &mut self,
111        info: AccelerationStructureInfo,
112    ) -> Result<Arc<Lease<AccelerationStructure>>, DriverError> {
113        self.accel_structs
114            .retain(|(_, item)| item.strong_count() > 0);
115
116        {
117            profiling::scope!("check aliases");
118
119            for (item_info, item) in &self.accel_structs {
120                if item_info.ty == info.ty && item_info.size >= info.size {
121                    if let Some(item) = item.upgrade() {
122                        return Ok(item);
123                    } else {
124                        break;
125                    }
126                }
127            }
128        }
129
130        debug!("Leasing new {}", stringify!(AccelerationStructure));
131
132        let item = Arc::new(self.pool.lease(info)?);
133        self.accel_structs.push((info, Arc::downgrade(&item)));
134
135        Ok(item)
136    }
137}
138
139impl<T> Alias<BufferInfo, Buffer> for AliasPool<T>
140where
141    T: Pool<BufferInfo, Buffer>,
142{
143    fn alias(&mut self, info: BufferInfo) -> Result<Arc<Lease<Buffer>>, DriverError> {
144        self.buffers.retain(|(_, item)| item.strong_count() > 0);
145
146        {
147            profiling::scope!("check aliases");
148
149            for (item_info, item) in &self.buffers {
150                if item_info.mappable == info.mappable
151                    && item_info.alignment >= info.alignment
152                    && item_info.size >= info.size
153                    && item_info.usage.contains(info.usage)
154                {
155                    if let Some(item) = item.upgrade() {
156                        return Ok(item);
157                    } else {
158                        break;
159                    }
160                }
161            }
162        }
163
164        debug!("Leasing new {}", stringify!(Buffer));
165
166        let item = Arc::new(self.pool.lease(info)?);
167        self.buffers.push((info, Arc::downgrade(&item)));
168
169        Ok(item)
170    }
171}
172
173impl<T> Alias<ImageInfo, Image> for AliasPool<T>
174where
175    T: Pool<ImageInfo, Image>,
176{
177    fn alias(&mut self, info: ImageInfo) -> Result<Arc<Lease<Image>>, DriverError> {
178        self.images.retain(|(_, item)| item.strong_count() > 0);
179
180        {
181            profiling::scope!("check aliases");
182
183            for (item_info, item) in &self.images {
184                if item_info.array_layer_count == info.array_layer_count
185                    && item_info.depth == info.depth
186                    && item_info.fmt == info.fmt
187                    && item_info.height == info.height
188                    && item_info.mip_level_count == info.mip_level_count
189                    && item_info.sample_count == info.sample_count
190                    && item_info.tiling == info.tiling
191                    && item_info.ty == info.ty
192                    && item_info.width == info.width
193                    && item_info.flags.contains(info.flags)
194                    && item_info.usage.contains(info.usage)
195                {
196                    if let Some(item) = item.upgrade() {
197                        return Ok(item);
198                    } else {
199                        break;
200                    }
201                }
202            }
203        }
204
205        debug!("Leasing new {}", stringify!(Image));
206
207        let item = Arc::new(self.pool.lease(info)?);
208        self.images.push((info, Arc::downgrade(&item)));
209
210        Ok(item)
211    }
212}
213
214impl<T> Deref for AliasPool<T> {
215    type Target = T;
216
217    fn deref(&self) -> &Self::Target {
218        &self.pool
219    }
220}
221
222impl<T> DerefMut for AliasPool<T> {
223    fn deref_mut(&mut self) -> &mut Self::Target {
224        &mut self.pool
225    }
226}