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},
12 },
13 log::debug,
14 std::{collections::HashMap, sync::Arc},
15};
16
17#[derive(Debug)]
44pub struct FifoPool {
45 accel_struct_cache: Cache<AccelerationStructure>,
46 buffer_cache: Cache<Buffer>,
47 command_buffer_cache: HashMap<u32, Cache<CommandBuffer>>,
48 descriptor_pool_cache: Cache<DescriptorPool>,
49 device: Arc<Device>,
50 image_cache: Cache<Image>,
51 info: PoolInfo,
52 render_pass_cache: HashMap<RenderPassInfo, Cache<RenderPass>>,
53}
54
55impl FifoPool {
56 pub fn new(device: &Arc<Device>) -> Self {
58 Self::with_capacity(device, PoolInfo::default())
59 }
60
61 pub fn with_capacity(device: &Arc<Device>, info: impl Into<PoolInfo>) -> Self {
63 let info: PoolInfo = info.into();
64 let device = Arc::clone(device);
65
66 Self {
67 accel_struct_cache: PoolInfo::explicit_cache(info.accel_struct_capacity),
68 buffer_cache: PoolInfo::explicit_cache(info.buffer_capacity),
69 command_buffer_cache: Default::default(),
70 descriptor_pool_cache: PoolInfo::default_cache(),
71 device,
72 image_cache: PoolInfo::explicit_cache(info.image_capacity),
73 info,
74 render_pass_cache: Default::default(),
75 }
76 }
77
78 pub fn clear(&mut self) {
80 self.clear_accel_structs();
81 self.clear_buffers();
82 self.clear_images();
83 }
84
85 pub fn clear_accel_structs(&mut self) {
87 self.accel_struct_cache = PoolInfo::explicit_cache(self.info.accel_struct_capacity);
88 }
89
90 pub fn clear_buffers(&mut self) {
92 self.buffer_cache = PoolInfo::explicit_cache(self.info.buffer_capacity);
93 }
94
95 pub fn clear_images(&mut self) {
97 self.image_cache = PoolInfo::explicit_cache(self.info.image_capacity);
98 }
99}
100
101impl Pool<AccelerationStructureInfo, AccelerationStructure> for FifoPool {
102 #[profiling::function]
103 fn lease(
104 &mut self,
105 info: AccelerationStructureInfo,
106 ) -> Result<Lease<AccelerationStructure>, DriverError> {
107 let cache_ref = Arc::downgrade(&self.accel_struct_cache);
108
109 {
110 profiling::scope!("check cache");
111
112 #[cfg_attr(not(feature = "parking_lot"), allow(unused_mut))]
113 let mut cache = self.accel_struct_cache.lock();
114
115 #[cfg(not(feature = "parking_lot"))]
116 let mut cache = cache.unwrap();
117
118 for idx in 0..cache.len() {
120 let item = unsafe { cache.get_unchecked(idx) };
121 if item.info.size >= info.size && item.info.ty == info.ty {
122 let item = cache.swap_remove(idx);
123
124 return Ok(Lease::new(cache_ref, item));
125 }
126 }
127 }
128
129 debug!("Creating new {}", stringify!(AccelerationStructure));
130
131 let item = AccelerationStructure::create(&self.device, info)?;
132
133 Ok(Lease::new(cache_ref, item))
134 }
135}
136
137impl Pool<BufferInfo, Buffer> for FifoPool {
138 #[profiling::function]
139 fn lease(&mut self, info: BufferInfo) -> Result<Lease<Buffer>, DriverError> {
140 let cache_ref = Arc::downgrade(&self.buffer_cache);
141
142 {
143 profiling::scope!("check cache");
144
145 #[cfg_attr(not(feature = "parking_lot"), allow(unused_mut))]
146 let mut cache = self.buffer_cache.lock();
147
148 #[cfg(not(feature = "parking_lot"))]
149 let mut cache = cache.unwrap();
150
151 for idx in 0..cache.len() {
154 let item = unsafe { cache.get_unchecked(idx) };
155 if item.info.alignment >= info.alignment
156 && item.info.mappable == info.mappable
157 && item.info.size >= info.size
158 && item.info.usage.contains(info.usage)
159 {
160 let item = cache.swap_remove(idx);
161
162 return Ok(Lease::new(cache_ref, item));
163 }
164 }
165 }
166
167 debug!("Creating new {}", stringify!(Buffer));
168
169 let item = Buffer::create(&self.device, info)?;
170
171 Ok(Lease::new(cache_ref, item))
172 }
173}
174
175impl Pool<CommandBufferInfo, CommandBuffer> for FifoPool {
176 #[profiling::function]
177 fn lease(&mut self, info: CommandBufferInfo) -> Result<Lease<CommandBuffer>, DriverError> {
178 let cache_ref = self
179 .command_buffer_cache
180 .entry(info.queue_family_index)
181 .or_insert_with(PoolInfo::default_cache);
182
183 let mut item = {
184 #[cfg_attr(not(feature = "parking_lot"), allow(unused_mut))]
185 let mut cache = cache_ref.lock();
186
187 #[cfg(not(feature = "parking_lot"))]
188 let mut cache = cache.unwrap();
189
190 lease_command_buffer(&mut cache)
191 }
192 .map(Ok)
193 .unwrap_or_else(|| {
194 debug!("Creating new {}", stringify!(CommandBuffer));
195
196 CommandBuffer::create(&self.device, info)
197 })?;
198
199 CommandBuffer::drop_fenced(&mut item);
201
202 Ok(Lease::new(Arc::downgrade(cache_ref), item))
203 }
204}
205
206impl Pool<DescriptorPoolInfo, DescriptorPool> for FifoPool {
207 #[profiling::function]
208 fn lease(&mut self, info: DescriptorPoolInfo) -> Result<Lease<DescriptorPool>, DriverError> {
209 let cache_ref = Arc::downgrade(&self.descriptor_pool_cache);
210
211 {
212 profiling::scope!("check cache");
213
214 #[cfg_attr(not(feature = "parking_lot"), allow(unused_mut))]
215 let mut cache = self.descriptor_pool_cache.lock();
216
217 #[cfg(not(feature = "parking_lot"))]
218 let mut cache = cache.unwrap();
219
220 for idx in 0..cache.len() {
222 let item = unsafe { cache.get_unchecked(idx) };
223 if item.info.max_sets >= info.max_sets
224 && item.info.acceleration_structure_count >= info.acceleration_structure_count
225 && item.info.combined_image_sampler_count >= info.combined_image_sampler_count
226 && item.info.input_attachment_count >= info.input_attachment_count
227 && item.info.sampled_image_count >= info.sampled_image_count
228 && item.info.sampler_count >= info.sampler_count
229 && item.info.storage_buffer_count >= info.storage_buffer_count
230 && item.info.storage_buffer_dynamic_count >= info.storage_buffer_dynamic_count
231 && item.info.storage_image_count >= info.storage_image_count
232 && item.info.storage_texel_buffer_count >= info.storage_texel_buffer_count
233 && item.info.uniform_buffer_count >= info.uniform_buffer_count
234 && item.info.uniform_buffer_dynamic_count >= info.uniform_buffer_dynamic_count
235 && item.info.uniform_texel_buffer_count >= info.uniform_texel_buffer_count
236 {
237 let item = cache.swap_remove(idx);
238
239 return Ok(Lease::new(cache_ref, item));
240 }
241 }
242 }
243
244 debug!("Creating new {}", stringify!(DescriptorPool));
245
246 let item = DescriptorPool::create(&self.device, info)?;
247
248 Ok(Lease::new(cache_ref, item))
249 }
250}
251
252impl Pool<ImageInfo, Image> for FifoPool {
253 #[profiling::function]
254 fn lease(&mut self, info: ImageInfo) -> Result<Lease<Image>, DriverError> {
255 let cache_ref = Arc::downgrade(&self.image_cache);
256
257 {
258 profiling::scope!("check cache");
259
260 #[cfg_attr(not(feature = "parking_lot"), allow(unused_mut))]
261 let mut cache = self.image_cache.lock();
262
263 #[cfg(not(feature = "parking_lot"))]
264 let mut cache = cache.unwrap();
265
266 for idx in 0..cache.len() {
269 let item = unsafe { cache.get_unchecked(idx) };
270 if item.info.array_layer_count == info.array_layer_count
271 && item.info.depth == info.depth
272 && item.info.fmt == info.fmt
273 && item.info.height == info.height
274 && item.info.mip_level_count == info.mip_level_count
275 && item.info.sample_count == info.sample_count
276 && item.info.tiling == info.tiling
277 && item.info.ty == info.ty
278 && item.info.width == info.width
279 && item.info.flags.contains(info.flags)
280 && item.info.usage.contains(info.usage)
281 {
282 let item = cache.swap_remove(idx);
283
284 return Ok(Lease::new(cache_ref, item));
285 }
286 }
287 }
288
289 debug!("Creating new {}", stringify!(Image));
290
291 let item = Image::create(&self.device, info)?;
292
293 Ok(Lease::new(cache_ref, item))
294 }
295}
296
297impl Pool<RenderPassInfo, RenderPass> for FifoPool {
298 #[profiling::function]
299 fn lease(&mut self, info: RenderPassInfo) -> Result<Lease<RenderPass>, DriverError> {
300 let cache_ref = if let Some(cache) = self.render_pass_cache.get(&info) {
301 cache
302 } else {
303 self.render_pass_cache
305 .entry(info.clone())
306 .or_insert_with(PoolInfo::default_cache)
307 };
308 let item = {
309 #[cfg_attr(not(feature = "parking_lot"), allow(unused_mut))]
310 let mut cache = cache_ref.lock();
311
312 #[cfg(not(feature = "parking_lot"))]
313 let mut cache = cache.unwrap();
314
315 cache.pop()
316 }
317 .map(Ok)
318 .unwrap_or_else(|| {
319 debug!("Creating new {}", stringify!(RenderPass));
320
321 RenderPass::create(&self.device, info)
322 })?;
323
324 Ok(Lease::new(Arc::downgrade(cache_ref), item))
325 }
326}