1use crate::binding::{BindingRequirements, BindingUtil};
2use bit_set::BitSet;
3use librashader_common::map::FastHashMap;
4use librashader_common::{ImageFormat, Size};
5use librashader_reflect::reflect::semantics::BindingMeta;
6use std::collections::VecDeque;
7use std::ops::{Index, IndexMut};
8
9#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
10pub(crate) struct FramebufferKey {
11 pub size: Size<u32>,
12 pub format: ImageFormat,
13 pub mipmap: bool,
14}
15
16#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
17pub(crate) struct Slot(i32);
18
19impl Slot {
20 pub const NONE: Slot = Slot(-1);
21
22 const fn new(index: usize) -> Slot {
23 Slot(index as i32)
24 }
25
26 const fn get(self) -> Option<usize> {
28 if self.0 < 0 {
29 None
30 } else {
31 Some(self.0 as usize)
32 }
33 }
34}
35
36pub struct FramebufferPool<F> {
38 pool: Box<[F]>,
39 slots: Box<[Slot]>,
40
41 last_use: Box<[usize]>,
43}
44
45impl<F> FramebufferPool<F> {
46 pub(crate) fn prepare(&mut self, keys: &[FramebufferKey]) {
48 struct Event {
49 slot: usize,
50 key: FramebufferKey,
51 next_slot: usize,
52 }
53
54 let n = keys.len();
55
56 let mut free: FastHashMap<FramebufferKey, Vec<usize>> = FastHashMap::default();
58
59 let mut freed_at = vec![usize::MAX; n + 1];
60 let mut events: Vec<Event> = Vec::with_capacity(n);
61 let mut slot_count = 0;
62
63 for pass in 0..n {
64 let mut event = freed_at[pass];
65 while event != usize::MAX {
66 let Event { slot, key, next_slot } = events[event];
67 free.entry(key).or_default().push(slot);
68 event = next_slot;
69 }
70
71 let key = keys[pass];
72 let slot = free.get_mut(&key).and_then(Vec::pop).unwrap_or_else(|| {
73 let slot = slot_count;
74 slot_count += 1;
75 slot
76 });
77
78 self.slots[pass] = Slot::new(slot);
79 let free_at = self.last_use[pass] + 1;
80 events.push(Event { slot, key, next_slot: freed_at[free_at] });
81 freed_at[free_at] = events.len() - 1;
82 }
83 }
84
85 pub fn contains(&self, pass: usize) -> bool {
87 self.slots.get(pass).and_then(|s| s.get()).is_some()
88 }
89}
90
91impl<F> Index<usize> for FramebufferPool<F> {
92 type Output = F;
93
94 fn index(&self, pass: usize) -> &F {
95 &self.pool[self.slots[pass].get().expect("pass has no framebuffer")]
96 }
97}
98
99impl<F> IndexMut<usize> for FramebufferPool<F> {
100 fn index_mut(&mut self, pass: usize) -> &mut F {
101 &mut self.pool[self.slots[pass].get().expect("pass has no framebuffer")]
102 }
103}
104
105pub struct FramebufferInit<'a, F, I, E> {
107 owned_generator: &'a dyn Fn() -> Result<F, E>,
108 input_generator: &'a dyn Fn() -> I,
109 requirements: BindingRequirements,
110 filters_count: usize,
111}
112
113impl<'a, F, I, E> FramebufferInit<'a, F, I, E> {
114 pub fn new(
117 filters: impl Iterator<Item = &'a BindingMeta> + ExactSizeIterator,
118 owned_generator: &'a dyn Fn() -> Result<F, E>,
119 input_generator: &'a dyn Fn() -> I,
120 ) -> Self {
121 let filters_count = filters.len();
122 let requirements = BindingMeta::calculate_requirements(filters);
123
124 Self {
125 owned_generator,
126 input_generator,
127 filters_count,
128 requirements,
129 }
130 }
131
132 pub fn init_history(&self) -> Result<(VecDeque<F>, Box<[I]>), E> {
134 init_history(
135 self.requirements.required_history,
136 self.owned_generator,
137 self.input_generator,
138 )
139 }
140
141 pub fn init_output_framebuffers(&self) -> Result<(FramebufferPool<F>, Box<[I]>), E> {
143 init_output_framebuffers(
144 self.filters_count,
145 &self.requirements.last_use,
146 self.owned_generator,
147 self.input_generator,
148 )
149 }
150
151 pub fn init_feedback_framebuffers(&self) -> Result<(FramebufferPool<F>, Box<[I]>), E> {
154 init_feedback_framebuffers(
155 self.filters_count,
156 &self.requirements.feedback_mask,
157 self.owned_generator,
158 self.input_generator,
159 )
160 }
161
162 pub const fn uses_final_pass_as_feedback(&self) -> bool {
164 self.requirements.uses_final_pass_as_feedback
165 }
166}
167
168fn init_history<'a, F, I, E>(
169 required_images: usize,
170 owned_generator: impl Fn() -> Result<F, E>,
171 input_generator: impl Fn() -> I,
172) -> Result<(VecDeque<F>, Box<[I]>), E> {
173 if required_images < 1 {
177 return Ok((VecDeque::new(), Box::new([])));
178 }
179
180 let mut framebuffers = VecDeque::with_capacity(required_images);
181 framebuffers.resize_with(required_images, owned_generator);
182
183 let framebuffers = framebuffers
184 .into_iter()
185 .collect::<Result<VecDeque<F>, E>>()?;
186
187 let mut history_textures = Vec::new();
188 history_textures.resize_with(required_images, input_generator);
189
190 Ok((framebuffers, history_textures.into_boxed_slice()))
191}
192
193fn init_output_framebuffers<F, I, E>(
194 filters_count: usize,
195 last_use: &[usize],
196 owned_generator: impl Fn() -> Result<F, E>,
197 input_generator: impl Fn() -> I,
198) -> Result<(FramebufferPool<F>, Box<[I]>), E> {
199 let mut pool = Vec::with_capacity(filters_count);
200 pool.resize_with(filters_count, &owned_generator);
201 let pool = pool
202 .into_iter()
203 .collect::<Result<Vec<F>, E>>()?
204 .into_boxed_slice();
205
206 let mut textures = Vec::new();
207 textures.resize_with(filters_count, input_generator);
208
209 Ok((
210 FramebufferPool {
211 pool,
212 last_use: last_use.to_vec().into_boxed_slice(),
213 slots: (0..filters_count).map(Slot::new).collect(),
214 },
215 textures.into_boxed_slice(),
216 ))
217}
218
219fn init_feedback_framebuffers<F, I, E>(
220 filters_count: usize,
221 feedback_mask: &BitSet,
222 owned_generator: impl Fn() -> Result<F, E>,
223 input_generator: impl Fn() -> I,
224) -> Result<(FramebufferPool<F>, Box<[I]>), E> {
225
226 fn assign_slots(mask: &BitSet, filters_count: usize) -> (usize, Box<[Slot]>) {
228 let mut slot_of_pass = vec![Slot::NONE; filters_count];
229 let mut count = 0;
230 for pass in mask.iter() {
231 if pass < filters_count {
232 slot_of_pass[pass] = Slot::new(count);
233 count += 1;
234 }
235 }
236 (count, slot_of_pass.into_boxed_slice())
237 }
238
239 let (count, slots) = assign_slots(feedback_mask, filters_count);
240
241 let mut pool = Vec::with_capacity(count);
242 pool.resize_with(count, owned_generator);
243 let pool = pool
244 .into_iter()
245 .collect::<Result<Vec<F>, E>>()?
246 .into_boxed_slice();
247
248 let mut textures = Vec::new();
249 textures.resize_with(filters_count, input_generator);
250
251 Ok((
252 FramebufferPool {
253 pool,
254 last_use: Box::new([]),
255 slots,
256 },
257 textures.into_boxed_slice(),
258 ))
259}
260
261#[cfg(test)]
262mod tests {
263 use super::{FramebufferKey, FramebufferPool, Slot};
264 use librashader_common::{ImageFormat, Size};
265 use std::collections::HashSet;
266
267 fn fb(last_use: Vec<usize>) -> FramebufferPool<()> {
268 let n = last_use.len();
269 FramebufferPool {
270 pool: vec![(); n].into_boxed_slice(),
271 last_use: last_use.into_boxed_slice(),
272 slots: vec![Slot::new(0); n].into_boxed_slice(),
273 }
274 }
275
276 fn key(size: Size<u32>) -> FramebufferKey {
277 FramebufferKey {
278 size,
279 format: ImageFormat::R8G8B8A8Unorm,
280 mipmap: false,
281 }
282 }
283
284 fn distinct(slots: &[Slot]) -> usize {
285 slots.iter().copied().collect::<HashSet<_>>().len()
286 }
287
288 #[test]
289 fn liveness_pools_chain() {
290 let size = |w, h| Size::<u32>::new(w, h);
291 let last_use = vec![1, 2, 10, 4, 5, 6, 7, 8, 9, 10, 10];
292 let keys = vec![
293 key(size(1280, 960)), key(size(1280, 960)), key(size(1280, 3360)), key(size(1280, 1680)), key(size(1280, 1680)), key(size(1280, 1680)), key(size(1280, 1680)), key(size(1280, 1680)), key(size(1280, 1680)), key(size(3840, 1680)), key(size(1280, 720)), ];
305
306 let mut output = fb(last_use);
307 output.prepare(&keys);
308
309 assert_eq!(distinct(&output.slots[3..=8]), 2);
312
313 assert_eq!(distinct(&output.slots), 7);
316 let mut seen: std::collections::HashMap<Slot, FramebufferKey> = Default::default();
317 for (pass, &slot) in output.slots.iter().enumerate() {
318 assert_eq!(*seen.entry(slot).or_insert(keys[pass]), keys[pass]);
319 }
320 }
321
322 #[test]
324 fn liveness_pools_uniform_chain() {
325 let keys = vec![key(Size::<u32>::new(1920, 1080)); 8];
326 let mut output = fb(vec![1, 2, 3, 4, 5, 6, 7, 7]);
327 output.prepare(&keys);
328 assert_eq!(distinct(&output.slots), 2);
329 }
330
331 #[test]
335 fn liveness_respects_format_and_mipmap() {
336 let size = Size::<u32>::new(960, 540);
337 let keys = vec![
338 FramebufferKey {
339 size,
340 format: ImageFormat::R8G8B8A8Unorm,
341 mipmap: false,
342 },
343 FramebufferKey {
344 size,
345 format: ImageFormat::R8G8B8A8Unorm,
346 mipmap: true,
347 },
348 FramebufferKey {
349 size,
350 format: ImageFormat::R16G16B16A16Sfloat,
351 mipmap: false,
352 },
353 FramebufferKey {
354 size,
355 format: ImageFormat::R8G8B8A8Unorm,
356 mipmap: false,
357 },
358 ];
359
360 let mut output = fb(vec![1, 2, 3, 3]);
361 output.prepare(&keys);
362
363 assert_eq!(output.slots[3], output.slots[0]);
365 assert_eq!(distinct(&output.slots), 3);
366 }
367}