1use {
4 super::{Lease, Pool},
5 crate::driver::{
6 DriverError,
7 accel_struct::{AccelerationStructure, AccelerationStructureInfo},
8 buffer::{Buffer, BufferInfo},
9 image::{Image, ImageInfo},
10 },
11 log::debug,
12 std::{
13 collections::HashMap,
14 hash::Hash,
15 ops::{Deref, DerefMut},
16 sync::{Arc, Weak},
17 },
18};
19
20#[derive(Default)]
21struct AliasSet {
22 accel_structs: Vec<(
23 AccelerationStructureInfo,
24 Weak<Lease<AccelerationStructure>>,
25 )>,
26 buffers: Vec<(BufferInfo, Weak<Lease<Buffer>>)>,
27 images: Vec<(ImageInfo, Weak<Lease<Image>>)>,
28}
29
30pub struct Cache<T, Tag = ()> {
58 aliases: HashMap<Tag, AliasSet>,
59 pool: T,
60}
61
62pub struct TaggedCache<'a, T, Tag> {
64 cache: &'a mut Cache<T, Tag>,
65 tag: Tag,
66}
67
68impl<T, Tag> Cache<T, Tag>
69where
70 Tag: Eq + Hash,
71{
72 pub fn new(pool: T) -> Self {
74 Self {
75 aliases: Default::default(),
76 pool,
77 }
78 }
79
80 pub fn tag(&mut self, tag: Tag) -> TaggedCache<'_, T, Tag> {
82 TaggedCache { cache: self, tag }
83 }
84
85 fn alias_set(&mut self, tag: Tag) -> &mut AliasSet {
86 self.aliases.entry(tag).or_default()
87 }
88
89 fn resource_accel_struct_tagged(
90 &mut self,
91 tag: Tag,
92 info: AccelerationStructureInfo,
93 ) -> Result<Arc<Lease<AccelerationStructure>>, DriverError>
94 where
95 Tag: Clone,
96 T: Pool<AccelerationStructureInfo, AccelerationStructure>,
97 {
98 let mut result = None;
99
100 {
101 let state = self.alias_set(tag.clone());
102 state
103 .accel_structs
104 .retain(|(_, item)| item.strong_count() > 0);
105
106 profiling::scope!("check aliases");
107
108 for (item_info, item) in &state.accel_structs {
109 if item_info.ty == info.ty
110 && item_info.size >= info.size
111 && let Some(item) = item.upgrade()
112 {
113 result = Some(item);
114 break;
115 }
116 }
117 }
118
119 if let Some(item) = result {
120 return Ok(item);
121 }
122
123 debug!("Leasing new {}", stringify!(AccelerationStructure));
124
125 let item = Arc::new(self.pool.resource(info)?);
126 self.alias_set(tag)
127 .accel_structs
128 .push((info, Arc::downgrade(&item)));
129
130 Ok(item)
131 }
132
133 fn resource_buffer_tagged(
134 &mut self,
135 tag: Tag,
136 info: BufferInfo,
137 ) -> Result<Arc<Lease<Buffer>>, DriverError>
138 where
139 Tag: Clone,
140 T: Pool<BufferInfo, Buffer>,
141 {
142 let mut result = None;
143
144 {
145 let state = self.alias_set(tag.clone());
146 state.buffers.retain(|(_, item)| item.strong_count() > 0);
147
148 profiling::scope!("check aliases");
149
150 for (item_info, item) in &state.buffers {
151 if (item_info.dedicated & info.dedicated) == info.dedicated
152 && item_info.host_read == info.host_read
153 && item_info.host_write == info.host_write
154 && item_info.alignment >= info.alignment
155 && item_info.size >= info.size
156 && item_info.usage.contains(info.usage)
157 && let Some(item) = item.upgrade()
158 {
159 result = Some(item);
160 break;
161 }
162 }
163 }
164
165 if let Some(item) = result {
166 return Ok(item);
167 }
168
169 debug!("Leasing new {}", stringify!(Buffer));
170
171 let item = Arc::new(self.pool.resource(info)?);
172 self.alias_set(tag)
173 .buffers
174 .push((info, Arc::downgrade(&item)));
175
176 Ok(item)
177 }
178
179 fn resource_image_tagged(
180 &mut self,
181 tag: Tag,
182 info: ImageInfo,
183 ) -> Result<Arc<Lease<Image>>, DriverError>
184 where
185 Tag: Clone,
186 T: Pool<ImageInfo, Image>,
187 {
188 let mut result = None;
189
190 {
191 let state = self.alias_set(tag.clone());
192 state.images.retain(|(_, item)| item.strong_count() > 0);
193
194 profiling::scope!("check aliases");
195
196 for (item_info, item) in &state.images {
197 if item_info.array_layer_count == info.array_layer_count
198 && item_info.dedicated == info.dedicated
199 && item_info.depth == info.depth
200 && item_info.fmt == info.fmt
201 && item_info.height == info.height
202 && item_info.mip_level_count == info.mip_level_count
203 && item_info.sample_count == info.sample_count
204 && item_info.tiling == info.tiling
205 && item_info.ty == info.ty
206 && item_info.width == info.width
207 && item_info.flags.contains(info.flags)
208 && item_info.usage.contains(info.usage)
209 && let Some(item) = item.upgrade()
210 {
211 result = Some(item);
212 break;
213 }
214 }
215 }
216
217 if let Some(item) = result {
218 return Ok(item);
219 }
220
221 debug!("Leasing new {}", stringify!(Image));
222
223 let item = Arc::new(self.pool.resource(info)?);
224 self.alias_set(tag)
225 .images
226 .push((info, Arc::downgrade(&item)));
227
228 Ok(item)
229 }
230}
231
232impl<T> Cache<T, ()>
233where
234 T: Pool<AccelerationStructureInfo, AccelerationStructure>
235 + Pool<BufferInfo, Buffer>
236 + Pool<ImageInfo, Image>,
237{
238 pub fn accel_struct(
240 &mut self,
241 info: AccelerationStructureInfo,
242 ) -> Result<Arc<Lease<AccelerationStructure>>, DriverError> {
243 self.resource_accel_struct_tagged((), info)
244 }
245
246 pub fn buffer(&mut self, info: BufferInfo) -> Result<Arc<Lease<Buffer>>, DriverError> {
248 self.resource_buffer_tagged((), info)
249 }
250
251 pub fn image(&mut self, info: ImageInfo) -> Result<Arc<Lease<Image>>, DriverError> {
253 self.resource_image_tagged((), info)
254 }
255}
256
257impl<'a, T, Tag> TaggedCache<'a, T, Tag>
258where
259 Tag: Eq + Hash + Clone,
260{
261 pub fn resource<I>(&mut self, info: I) -> Result<Arc<Lease<I::Item>>, DriverError>
263 where
264 I: TaggedCacheResource<Tag>,
265 T: Pool<I, I::Item>,
266 {
267 I::resource(self.cache, self.tag.clone(), info)
268 }
269}
270
271#[doc(hidden)]
272pub trait TaggedCacheResource<Tag>: Sized {
273 type Item;
274
275 fn resource<T>(
276 cache: &mut Cache<T, Tag>,
277 tag: Tag,
278 info: Self,
279 ) -> Result<Arc<Lease<Self::Item>>, DriverError>
280 where
281 Tag: Eq + Hash + Clone,
282 T: Pool<Self, Self::Item>;
283}
284
285impl<Tag> TaggedCacheResource<Tag> for AccelerationStructureInfo
286where
287 Tag: Eq + Hash + Clone,
288{
289 type Item = AccelerationStructure;
290
291 fn resource<T>(
292 cache: &mut Cache<T, Tag>,
293 tag: Tag,
294 info: Self,
295 ) -> Result<Arc<Lease<Self::Item>>, DriverError>
296 where
297 T: Pool<Self, Self::Item>,
298 {
299 cache.resource_accel_struct_tagged(tag, info)
300 }
301}
302
303impl<Tag> TaggedCacheResource<Tag> for BufferInfo
304where
305 Tag: Eq + Hash + Clone,
306{
307 type Item = Buffer;
308
309 fn resource<T>(
310 cache: &mut Cache<T, Tag>,
311 tag: Tag,
312 info: Self,
313 ) -> Result<Arc<Lease<Self::Item>>, DriverError>
314 where
315 T: Pool<Self, Self::Item>,
316 {
317 cache.resource_buffer_tagged(tag, info)
318 }
319}
320
321impl<Tag> TaggedCacheResource<Tag> for ImageInfo
322where
323 Tag: Eq + Hash + Clone,
324{
325 type Item = Image;
326
327 fn resource<T>(
328 cache: &mut Cache<T, Tag>,
329 tag: Tag,
330 info: Self,
331 ) -> Result<Arc<Lease<Self::Item>>, DriverError>
332 where
333 T: Pool<Self, Self::Item>,
334 {
335 cache.resource_image_tagged(tag, info)
336 }
337}
338
339impl<T, Tag> Deref for Cache<T, Tag> {
340 type Target = T;
341
342 fn deref(&self) -> &Self::Target {
343 &self.pool
344 }
345}
346
347impl<T, Tag> DerefMut for Cache<T, Tag> {
348 fn deref_mut(&mut self) -> &mut Self::Target {
349 &mut self.pool
350 }
351}