1use {
4 super::{Cache, Lease, Pool, PoolConfig, lease_command_buffer},
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 paste::paste,
17 std::{collections::HashMap, sync::Arc},
18};
19
20#[cfg(feature = "parking_lot")]
21use parking_lot::Mutex;
22
23#[cfg(not(feature = "parking_lot"))]
24use std::sync::Mutex;
25
26#[derive(Debug)]
42#[read_only::cast]
43pub struct HashPool {
44 acceleration_structure_cache: HashMap<AccelerationStructureInfo, Cache<AccelerationStructure>>,
45 buffer_cache: HashMap<BufferInfo, Cache<Buffer>>,
46 command_buffer_cache: HashMap<u32, Cache<CommandBuffer>>,
47 descriptor_pool_cache: HashMap<DescriptorPoolInfo, Cache<DescriptorPool>>,
48
49 #[readonly]
53 pub device: Device,
54
55 image_cache: HashMap<ImageInfo, Cache<Image>>,
56
57 #[readonly]
61 pub info: PoolConfig,
62
63 render_pass_cache: HashMap<RenderPassInfo, Cache<RenderPass>>,
64}
65
66impl HashPool {
67 pub fn new(device: &Device) -> Self {
69 Self::with_capacity(device, PoolConfig::default())
70 }
71
72 pub fn with_capacity(device: &Device, info: impl Into<PoolConfig>) -> Self {
74 let info: PoolConfig = info.into();
75 let device = device.clone();
76
77 Self {
78 acceleration_structure_cache: Default::default(),
79 buffer_cache: Default::default(),
80 command_buffer_cache: Default::default(),
81 descriptor_pool_cache: Default::default(),
82 device,
83 image_cache: Default::default(),
84 info,
85 render_pass_cache: Default::default(),
86 }
87 }
88
89 pub fn clear(&mut self) {
91 self.clear_accel_structs();
92 self.clear_buffers();
93 self.clear_images();
94 }
95}
96
97macro_rules! resource_mgmt_fns {
98 ($fn_plural:literal, $doc_singular:literal, $ty:ty, $field:ident) => {
99 paste! {
100 impl HashPool {
101 #[doc = "Clears the pool of " $doc_singular " resources."]
102 pub fn [<clear_ $fn_plural>](&mut self) {
103 self.$field.clear();
104 }
105
106 #[doc = "Clears the pool of all " $doc_singular " resources matching the given
107information."]
108 pub fn [<clear_ $fn_plural _by_info>](
109 &mut self,
110 info: impl Into<$ty>,
111 ) {
112 self.$field.remove(&info.into());
113 }
114
115 #[doc = "Retains only the " $doc_singular " resources specified by the predicate.\n
116\nIn other words, remove all " $doc_singular " resources for which `f(" $ty ")` returns `false`.\n
117\n"]
118 pub fn [<retain_ $fn_plural>]<F>(&mut self, mut f: F)
125 where
126 F: FnMut($ty) -> bool,
127 {
128 self.$field.retain(|&info, _| f(info))
129 }
130 }
131 }
132 };
133}
134
135resource_mgmt_fns!(
136 "accel_structs",
137 "acceleration structure",
138 AccelerationStructureInfo,
139 acceleration_structure_cache
140);
141resource_mgmt_fns!("buffers", "buffer", BufferInfo, buffer_cache);
142resource_mgmt_fns!("images", "image", ImageInfo, image_cache);
143
144impl Pool<CommandBufferInfo, CommandBuffer> for HashPool {
145 #[profiling::function]
146 fn resource(&mut self, info: CommandBufferInfo) -> Result<Lease<CommandBuffer>, DriverError> {
147 let cache_ref = self
148 .command_buffer_cache
149 .entry(info.queue_family_index)
150 .or_insert_with(PoolConfig::default_cache);
151 let item = {
152 #[cfg_attr(not(feature = "parking_lot"), allow(unused_mut))]
153 let mut cache = cache_ref.lock();
154
155 #[cfg(not(feature = "parking_lot"))]
156 let mut cache = cache.expect("poisoned cache lock");
157
158 lease_command_buffer(&mut cache)
159 }
160 .map(Ok)
161 .unwrap_or_else(|| {
162 debug!("Creating new {}", stringify!(CommandBuffer));
163
164 CommandBuffer::create(&self.device, info)
165 })?;
166
167 Ok(Lease::new(Arc::downgrade(cache_ref), item))
171 }
172}
173
174impl Pool<DescriptorPoolInfo, DescriptorPool> for HashPool {
175 #[profiling::function]
176 fn resource(&mut self, info: DescriptorPoolInfo) -> Result<Lease<DescriptorPool>, DriverError> {
177 let cache_ref = self
178 .descriptor_pool_cache
179 .entry(info.clone())
180 .or_insert_with(PoolConfig::default_cache);
181 let item = {
182 #[cfg_attr(not(feature = "parking_lot"), allow(unused_mut))]
183 let mut cache = cache_ref.lock();
184
185 #[cfg(not(feature = "parking_lot"))]
186 let mut cache = cache.expect("poisoned cache lock");
187
188 cache.pop()
189 }
190 .map(Ok)
191 .unwrap_or_else(|| {
192 debug!("Creating new {}", stringify!(DescriptorPool));
193
194 DescriptorPool::create(&self.device, info)
195 })?;
196
197 Ok(Lease::new(Arc::downgrade(cache_ref), item))
198 }
199}
200
201impl Pool<RenderPassInfo, RenderPass> for HashPool {
202 #[profiling::function]
203 fn resource(&mut self, info: RenderPassInfo) -> Result<Lease<RenderPass>, DriverError> {
204 let cache_ref = if let Some(cache) = self.render_pass_cache.get(&info) {
205 cache
206 } else {
207 self.render_pass_cache
209 .entry(info.clone())
210 .or_insert_with(PoolConfig::default_cache)
211 };
212 let item = {
213 #[cfg_attr(not(feature = "parking_lot"), allow(unused_mut))]
214 let mut cache = cache_ref.lock();
215
216 #[cfg(not(feature = "parking_lot"))]
217 let mut cache = cache.expect("poisoned cache lock");
218
219 cache.pop()
220 }
221 .map(Ok)
222 .unwrap_or_else(|| {
223 debug!("Creating new {}", stringify!(RenderPass));
224
225 RenderPass::create(&self.device, info)
226 })?;
227
228 Ok(Lease::new(Arc::downgrade(cache_ref), item))
229 }
230}
231
232macro_rules! lease {
234 ($info:ident => $item:ident, $capacity:ident) => {
235 paste::paste! {
236 impl Pool<$info, $item> for HashPool {
237 #[profiling::function]
238 fn resource(&mut self, info: $info) -> Result<Lease<$item>, DriverError> {
239 let cache_ref = self.[<$item:snake _cache>].entry(info)
240 .or_insert_with(|| {
241 Cache::new(Mutex::new(Vec::with_capacity(self.info.$capacity)))
242 });
243 let 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.expect("poisoned cache lock");
249
250 cache.pop()
251 }
252 .map(Ok)
253 .unwrap_or_else(|| {
254 debug!("Creating new {}", stringify!($item));
255
256 $item::create(&self.device, info)
257 })?;
258
259 Ok(Lease::new(Arc::downgrade(cache_ref), item))
260 }
261 }
262 }
263 };
264}
265
266lease!(AccelerationStructureInfo => AccelerationStructure, accel_struct_capacity);
267lease!(BufferInfo => Buffer, buffer_capacity);
268lease!(ImageInfo => Image, image_capacity);