1use {
4 super::{Cache, Lease, Pool, PoolInfo, lease_command_buffer},
5 crate::driver::{
6 CommandBuffer, CommandBufferInfo, DescriptorPool, DescriptorPoolInfo, DriverError,
7 RenderPass, RenderPassInfo,
8 accel_struct::{AccelerationStructure, AccelerationStructureInfo},
9 buffer::{Buffer, BufferInfo},
10 device::Device,
11 image::{Image, ImageInfo, SampleCount},
12 },
13 ash::vk,
14 log::debug,
15 std::{collections::HashMap, sync::Arc},
16};
17
18#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
19struct ImageKey {
20 array_layer_count: u32,
21 depth: u32,
22 fmt: vk::Format,
23 height: u32,
24 mip_level_count: u32,
25 sample_count: SampleCount,
26 tiling: vk::ImageTiling,
27 ty: vk::ImageType,
28 width: u32,
29}
30
31impl From<ImageInfo> for ImageKey {
32 fn from(info: ImageInfo) -> Self {
33 Self {
34 array_layer_count: info.array_layer_count,
35 depth: info.depth,
36 fmt: info.fmt,
37 height: info.height,
38 mip_level_count: info.mip_level_count,
39 sample_count: info.sample_count,
40 tiling: info.tiling,
41 ty: info.ty,
42 width: info.width,
43 }
44 }
45}
46
47#[derive(Debug)]
74pub struct LazyPool {
75 accel_struct_cache: HashMap<vk::AccelerationStructureTypeKHR, Cache<AccelerationStructure>>,
76 buffer_cache: HashMap<(bool, vk::DeviceSize), Cache<Buffer>>,
77 command_buffer_cache: HashMap<u32, Cache<CommandBuffer>>,
78 descriptor_pool_cache: Cache<DescriptorPool>,
79 device: Arc<Device>,
80 image_cache: HashMap<ImageKey, Cache<Image>>,
81 info: PoolInfo,
82 render_pass_cache: HashMap<RenderPassInfo, Cache<RenderPass>>,
83}
84
85impl LazyPool {
86 pub fn new(device: &Arc<Device>) -> Self {
88 Self::with_capacity(device, PoolInfo::default())
89 }
90
91 pub fn with_capacity(device: &Arc<Device>, info: impl Into<PoolInfo>) -> Self {
93 let info: PoolInfo = info.into();
94 let device = Arc::clone(device);
95
96 Self {
97 accel_struct_cache: Default::default(),
98 buffer_cache: Default::default(),
99 command_buffer_cache: Default::default(),
100 descriptor_pool_cache: PoolInfo::default_cache(),
101 device,
102 image_cache: Default::default(),
103 info,
104 render_pass_cache: Default::default(),
105 }
106 }
107
108 pub fn clear(&mut self) {
110 self.clear_accel_structs();
111 self.clear_buffers();
112 self.clear_images();
113 }
114
115 pub fn clear_accel_structs(&mut self) {
117 self.accel_struct_cache.clear();
118 }
119
120 pub fn clear_accel_structs_by_ty(&mut self, ty: vk::AccelerationStructureTypeKHR) {
122 self.accel_struct_cache.remove(&ty);
123 }
124
125 pub fn clear_buffers(&mut self) {
127 self.buffer_cache.clear();
128 }
129
130 pub fn clear_images(&mut self) {
132 self.image_cache.clear();
133 }
134
135 pub fn clear_images_by_info(&mut self, info: impl Into<ImageInfo>) {
137 self.image_cache.remove(&info.into().into());
138 }
139
140 pub fn retain_accel_structs<F>(&mut self, mut f: F)
152 where
153 F: FnMut(vk::AccelerationStructureTypeKHR) -> bool,
154 {
155 self.accel_struct_cache.retain(|&ty, _| f(ty))
156 }
157}
158
159impl Pool<AccelerationStructureInfo, AccelerationStructure> for LazyPool {
160 #[profiling::function]
161 fn lease(
162 &mut self,
163 info: AccelerationStructureInfo,
164 ) -> Result<Lease<AccelerationStructure>, DriverError> {
165 let cache = self
166 .accel_struct_cache
167 .entry(info.ty)
168 .or_insert_with(|| PoolInfo::explicit_cache(self.info.accel_struct_capacity));
169 let cache_ref = Arc::downgrade(cache);
170
171 {
172 profiling::scope!("check cache");
173
174 #[cfg_attr(not(feature = "parking_lot"), allow(unused_mut))]
175 let mut cache = cache.lock();
176
177 #[cfg(not(feature = "parking_lot"))]
178 let mut cache = cache.unwrap();
179
180 for idx in 0..cache.len() {
182 let item = unsafe { cache.get_unchecked(idx) };
183 if item.info.size >= info.size {
184 let item = cache.swap_remove(idx);
185
186 return Ok(Lease::new(cache_ref, item));
187 }
188 }
189 }
190
191 debug!("Creating new {}", stringify!(AccelerationStructure));
192
193 let item = AccelerationStructure::create(&self.device, info)?;
194
195 Ok(Lease::new(cache_ref, item))
196 }
197}
198
199impl Pool<BufferInfo, Buffer> for LazyPool {
200 #[profiling::function]
201 fn lease(&mut self, info: BufferInfo) -> Result<Lease<Buffer>, DriverError> {
202 let cache = self
203 .buffer_cache
204 .entry((info.mappable, info.alignment))
205 .or_insert_with(|| PoolInfo::explicit_cache(self.info.buffer_capacity));
206 let cache_ref = Arc::downgrade(cache);
207
208 {
209 profiling::scope!("check cache");
210
211 #[cfg_attr(not(feature = "parking_lot"), allow(unused_mut))]
212 let mut cache = cache.lock();
213
214 #[cfg(not(feature = "parking_lot"))]
215 let mut cache = cache.unwrap();
216
217 for idx in 0..cache.len() {
219 let item = unsafe { cache.get_unchecked(idx) };
220 if item.info.size >= info.size && item.info.usage.contains(info.usage) {
221 let item = cache.swap_remove(idx);
222
223 return Ok(Lease::new(cache_ref, item));
224 }
225 }
226 }
227
228 debug!("Creating new {}", stringify!(Buffer));
229
230 let item = Buffer::create(&self.device, info)?;
231
232 Ok(Lease::new(cache_ref, item))
233 }
234}
235
236impl Pool<CommandBufferInfo, CommandBuffer> for LazyPool {
237 #[profiling::function]
238 fn lease(&mut self, info: CommandBufferInfo) -> Result<Lease<CommandBuffer>, DriverError> {
239 let cache_ref = self
240 .command_buffer_cache
241 .entry(info.queue_family_index)
242 .or_insert_with(PoolInfo::default_cache);
243 let mut item = {
244 #[cfg_attr(not(feature = "parking_lot"), allow(unused_mut))]
245 let mut cache = cache_ref.lock();
246
247 #[cfg(not(feature = "parking_lot"))]
248 let mut cache = cache.unwrap();
249
250 lease_command_buffer(&mut cache)
251 }
252 .map(Ok)
253 .unwrap_or_else(|| {
254 debug!("Creating new {}", stringify!(CommandBuffer));
255
256 CommandBuffer::create(&self.device, info)
257 })?;
258
259 CommandBuffer::drop_fenced(&mut item);
261
262 Ok(Lease::new(Arc::downgrade(cache_ref), item))
263 }
264}
265
266impl Pool<DescriptorPoolInfo, DescriptorPool> for LazyPool {
267 #[profiling::function]
268 fn lease(&mut self, info: DescriptorPoolInfo) -> Result<Lease<DescriptorPool>, DriverError> {
269 let cache_ref = Arc::downgrade(&self.descriptor_pool_cache);
270
271 {
272 profiling::scope!("check cache");
273
274 #[cfg_attr(not(feature = "parking_lot"), allow(unused_mut))]
275 let mut cache = self.descriptor_pool_cache.lock();
276
277 #[cfg(not(feature = "parking_lot"))]
278 let mut cache = cache.unwrap();
279
280 for idx in 0..cache.len() {
282 let item = unsafe { cache.get_unchecked(idx) };
283 if item.info.max_sets >= info.max_sets
284 && item.info.acceleration_structure_count >= info.acceleration_structure_count
285 && item.info.combined_image_sampler_count >= info.combined_image_sampler_count
286 && item.info.input_attachment_count >= info.input_attachment_count
287 && item.info.sampled_image_count >= info.sampled_image_count
288 && item.info.sampler_count >= info.sampled_image_count
289 && item.info.storage_buffer_count >= info.storage_buffer_count
290 && item.info.storage_buffer_dynamic_count >= info.storage_buffer_dynamic_count
291 && item.info.storage_image_count >= info.storage_image_count
292 && item.info.storage_texel_buffer_count >= info.storage_texel_buffer_count
293 && item.info.uniform_buffer_count >= info.uniform_buffer_count
294 && item.info.uniform_buffer_dynamic_count >= info.uniform_buffer_dynamic_count
295 && item.info.uniform_texel_buffer_count >= info.uniform_texel_buffer_count
296 {
297 let item = cache.swap_remove(idx);
298
299 return Ok(Lease::new(cache_ref, item));
300 }
301 }
302 }
303
304 debug!("Creating new {}", stringify!(DescriptorPool));
305
306 let item = DescriptorPool::create(&self.device, info)?;
307
308 Ok(Lease::new(cache_ref, item))
309 }
310}
311
312impl Pool<ImageInfo, Image> for LazyPool {
313 #[profiling::function]
314 fn lease(&mut self, info: ImageInfo) -> Result<Lease<Image>, DriverError> {
315 let cache = self
316 .image_cache
317 .entry(info.into())
318 .or_insert_with(|| PoolInfo::explicit_cache(self.info.image_capacity));
319 let cache_ref = Arc::downgrade(cache);
320
321 {
322 profiling::scope!("check cache");
323
324 #[cfg_attr(not(feature = "parking_lot"), allow(unused_mut))]
325 let mut cache = cache.lock();
326
327 #[cfg(not(feature = "parking_lot"))]
328 let mut cache = cache.unwrap();
329
330 for idx in 0..cache.len() {
332 let item = unsafe { cache.get_unchecked(idx) };
333 if item.info.flags.contains(info.flags) && item.info.usage.contains(info.usage) {
334 let item = cache.swap_remove(idx);
335
336 return Ok(Lease::new(cache_ref, item));
337 }
338 }
339 }
340
341 debug!("Creating new {}", stringify!(Image));
342
343 let item = Image::create(&self.device, info)?;
344
345 Ok(Lease::new(cache_ref, item))
346 }
347}
348
349impl Pool<RenderPassInfo, RenderPass> for LazyPool {
350 #[profiling::function]
351 fn lease(&mut self, info: RenderPassInfo) -> Result<Lease<RenderPass>, DriverError> {
352 let cache_ref = if let Some(cache) = self.render_pass_cache.get(&info) {
353 cache
354 } else {
355 self.render_pass_cache
357 .entry(info.clone())
358 .or_insert_with(PoolInfo::default_cache)
359 };
360 let item = {
361 #[cfg_attr(not(feature = "parking_lot"), allow(unused_mut))]
362 let mut cache = cache_ref.lock();
363
364 #[cfg(not(feature = "parking_lot"))]
365 let mut cache = cache.unwrap();
366
367 cache.pop()
368 }
369 .map(Ok)
370 .unwrap_or_else(|| {
371 debug!("Creating new {}", stringify!(RenderPass));
372
373 RenderPass::create(&self.device, info)
374 })?;
375
376 Ok(Lease::new(Arc::downgrade(cache_ref), item))
377 }
378}