vk_graph/pool/
garbage_collector.rs1use {
4 super::{Lease, Pool},
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 image::{Image, ImageInfo},
12 render_pass::{RenderPass, RenderPassInfo},
13 },
14 std::{
15 collections::HashSet,
16 ops::{Deref, DerefMut},
17 },
18};
19
20#[derive(Default)]
21pub(super) struct ResourceRequests {
22 pub(super) accel_structs: HashSet<AccelerationStructureInfo>,
23 pub(super) buffers: HashSet<BufferInfo>,
24 pub(super) images: HashSet<ImageInfo>,
25}
26
27impl ResourceRequests {
28 fn clear(&mut self) {
29 self.accel_structs.clear();
30 self.buffers.clear();
31 self.images.clear();
32 }
33}
34
35pub(super) trait CollectResources {
36 fn collect_resources(&mut self, requests: &ResourceRequests);
37}
38
39pub struct GarbageCollector<T> {
75 pool: T,
76 requests: ResourceRequests,
77}
78
79impl<T> GarbageCollector<T> {
80 pub fn new(pool: T) -> Self {
82 Self {
83 pool,
84 requests: Default::default(),
85 }
86 }
87}
88
89#[allow(private_bounds)]
90impl<T> GarbageCollector<T>
91where
92 T: CollectResources,
93{
94 pub fn collect_resources(&mut self) {
100 self.pool.collect_resources(&self.requests);
101 self.requests.clear();
102 }
103}
104
105macro_rules! tracked_pool {
106 ($info:ty => $item:ty, $requests:ident) => {
107 impl<T> Pool<$info, $item> for GarbageCollector<T>
108 where
109 T: Pool<$info, $item>,
110 {
111 fn resource(&mut self, info: $info) -> Result<Lease<$item>, DriverError> {
112 let item = self.pool.resource(info)?;
113 self.requests.$requests.insert(info);
114
115 Ok(item)
116 }
117 }
118 };
119}
120
121tracked_pool!(AccelerationStructureInfo => AccelerationStructure, accel_structs);
122tracked_pool!(BufferInfo => Buffer, buffers);
123tracked_pool!(ImageInfo => Image, images);
124
125macro_rules! forwarded_pool {
126 ($info:ty => $item:ty) => {
127 impl<T> Pool<$info, $item> for GarbageCollector<T>
128 where
129 T: Pool<$info, $item>,
130 {
131 fn resource(&mut self, info: $info) -> Result<Lease<$item>, DriverError> {
132 self.pool.resource(info)
133 }
134 }
135 };
136}
137
138forwarded_pool!(CommandBufferInfo => CommandBuffer);
139forwarded_pool!(DescriptorPoolInfo => DescriptorPool);
140forwarded_pool!(RenderPassInfo => RenderPass);
141
142impl<T> Deref for GarbageCollector<T> {
143 type Target = T;
144
145 fn deref(&self) -> &Self::Target {
146 &self.pool
147 }
148}
149
150impl<T> DerefMut for GarbageCollector<T> {
151 fn deref_mut(&mut self) -> &mut Self::Target {
152 &mut self.pool
153 }
154}
155
156#[cfg(test)]
157mod test {
158 use {
159 super::*,
160 crate::{
161 driver::{
162 accel_struct::AccelerationStructureInfoBuilder, buffer::BufferInfoBuilder,
163 image::ImageInfoBuilder,
164 },
165 pool::{SubmissionPool, fifo::FifoPool, hash::HashPool, lazy::LazyPool},
166 },
167 ash::vk,
168 };
169
170 #[derive(Default)]
171 struct CollectSpy {
172 calls: Vec<(usize, usize, usize)>,
173 }
174
175 impl CollectResources for CollectSpy {
176 fn collect_resources(&mut self, requests: &ResourceRequests) {
177 self.calls.push((
178 requests.accel_structs.len(),
179 requests.buffers.len(),
180 requests.images.len(),
181 ));
182 }
183 }
184
185 struct FailingPool;
186
187 impl Pool<BufferInfo, Buffer> for FailingPool {
188 fn resource(&mut self, _: BufferInfo) -> Result<Lease<Buffer>, DriverError> {
189 Err(DriverError::Unsupported)
190 }
191 }
192
193 fn assert_pool_capabilities<T>()
194 where
195 T: Pool<AccelerationStructureInfo, AccelerationStructure>
196 + Pool<AccelerationStructureInfoBuilder, AccelerationStructure>
197 + Pool<BufferInfo, Buffer>
198 + Pool<BufferInfoBuilder, Buffer>
199 + Pool<ImageInfo, Image>
200 + Pool<ImageInfoBuilder, Image>
201 + Pool<CommandBufferInfo, CommandBuffer>
202 + SubmissionPool,
203 {
204 }
205
206 fn assert_collect_resources<T: CollectResources>() {}
207
208 #[test]
209 fn collect_resources_sweeps_and_resets_observed_requests() {
210 let mut collector = GarbageCollector::new(CollectSpy::default());
211 let info = BufferInfo::device_mem(64, vk::BufferUsageFlags::STORAGE_BUFFER);
212
213 collector.requests.buffers.insert(info);
214 collector.requests.buffers.insert(info);
215 collector.collect_resources();
216 collector.collect_resources();
217
218 assert_eq!(collector.pool.calls, [(0, 1, 0), (0, 0, 0)]);
219 }
220
221 #[test]
222 fn failed_requests_are_not_observed() {
223 let mut collector = GarbageCollector::new(FailingPool);
224 let info = BufferInfo::device_mem(64, vk::BufferUsageFlags::STORAGE_BUFFER);
225
226 assert!(matches!(
227 Pool::<BufferInfo, Buffer>::resource(&mut collector, info),
228 Err(DriverError::Unsupported)
229 ));
230 assert!(collector.requests.buffers.is_empty());
231 }
232
233 #[test]
234 fn built_in_pools_support_collection_and_pool_capabilities() {
235 assert_collect_resources::<FifoPool>();
236 assert_collect_resources::<HashPool>();
237 assert_collect_resources::<LazyPool>();
238 assert_pool_capabilities::<GarbageCollector<FifoPool>>();
239 assert_pool_capabilities::<GarbageCollector<HashPool>>();
240 assert_pool_capabilities::<GarbageCollector<LazyPool>>();
241 }
242}