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