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