1use crate::binding::{BindingRequirements, BindingUtil};
2use bit_set::BitSet;
3use librashader_common::map::FastHashMap;
4use librashader_common::Size;
5use librashader_reflect::reflect::semantics::BindingMeta;
6use std::collections::VecDeque;
7use std::ops::{Index, IndexMut};
8use num_traits::AsPrimitive;
9
10#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
11pub(crate) struct Slot(i32);
12
13impl Slot {
14 pub const NONE: Slot = Slot(-1);
15
16 const fn new(index: usize) -> Slot {
17 Slot(index as i32)
18 }
19
20 const fn get(self) -> Option<usize> {
22 if self.0 < 0 {
23 None
24 } else {
25 Some(self.0 as usize)
26 }
27 }
28}
29
30pub struct FramebufferPool<F> {
32 pool: Box<[F]>,
33 slots: Box<[Slot]>,
34
35 last_use: Box<[usize]>,
37}
38
39impl<F> FramebufferPool<F> {
40 pub(crate) fn prepare(&mut self, sizes: &[Size<u32>]) {
42 struct Event {
43 slot: usize,
44 size: u64,
45 next_slot: usize,
46 }
47
48 let n = sizes.len();
49
50 let mut free: FastHashMap<u64, Vec<usize>> = FastHashMap::default();
52
53 let mut freed_at = vec![usize::MAX; n + 1];
54 let mut events: Vec<Event> = Vec::with_capacity(n);
55 let mut slot_count = 0;
56
57 for pass in 0..n {
58 let mut event = freed_at[pass];
59 while event != usize::MAX {
60 let Event { slot, size, next_slot } = events[event];
61 free.entry(size).or_default().push(slot);
62 event = next_slot;
63 }
64
65 let size = sizes[pass].as_();
66 let slot = free.get_mut(&size).and_then(Vec::pop).unwrap_or_else(|| {
67 let slot = slot_count;
68 slot_count += 1;
69 slot
70 });
71
72 self.slots[pass] = Slot::new(slot);
73 let free_at = self.last_use[pass] + 1;
74 events.push(Event { slot, size, next_slot: freed_at[free_at] });
75 freed_at[free_at] = events.len() - 1;
76 }
77 }
78
79 pub fn contains(&self, pass: usize) -> bool {
81 self.slots.get(pass).and_then(|s| s.get()).is_some()
82 }
83}
84
85impl<F> Index<usize> for FramebufferPool<F> {
86 type Output = F;
87
88 fn index(&self, pass: usize) -> &F {
89 &self.pool[self.slots[pass].get().expect("pass has no framebuffer")]
90 }
91}
92
93impl<F> IndexMut<usize> for FramebufferPool<F> {
94 fn index_mut(&mut self, pass: usize) -> &mut F {
95 &mut self.pool[self.slots[pass].get().expect("pass has no framebuffer")]
96 }
97}
98
99pub struct FramebufferInit<'a, F, I, E> {
101 owned_generator: &'a dyn Fn() -> Result<F, E>,
102 input_generator: &'a dyn Fn() -> I,
103 requirements: BindingRequirements,
104 filters_count: usize,
105}
106
107impl<'a, F, I, E> FramebufferInit<'a, F, I, E> {
108 pub fn new(
111 filters: impl Iterator<Item = &'a BindingMeta> + ExactSizeIterator,
112 owned_generator: &'a dyn Fn() -> Result<F, E>,
113 input_generator: &'a dyn Fn() -> I,
114 ) -> Self {
115 let filters_count = filters.len();
116 let requirements = BindingMeta::calculate_requirements(filters);
117
118 Self {
119 owned_generator,
120 input_generator,
121 filters_count,
122 requirements,
123 }
124 }
125
126 pub fn init_history(&self) -> Result<(VecDeque<F>, Box<[I]>), E> {
128 init_history(
129 self.requirements.required_history,
130 self.owned_generator,
131 self.input_generator,
132 )
133 }
134
135 pub fn init_output_framebuffers(&self) -> Result<(FramebufferPool<F>, Box<[I]>), E> {
137 init_output_framebuffers(
138 self.filters_count,
139 &self.requirements.last_use,
140 self.owned_generator,
141 self.input_generator,
142 )
143 }
144
145 pub fn init_feedback_framebuffers(&self) -> Result<(FramebufferPool<F>, Box<[I]>), E> {
148 init_feedback_framebuffers(
149 self.filters_count,
150 &self.requirements.feedback_mask,
151 self.owned_generator,
152 self.input_generator,
153 )
154 }
155
156 pub const fn uses_final_pass_as_feedback(&self) -> bool {
158 self.requirements.uses_final_pass_as_feedback
159 }
160}
161
162fn init_history<'a, F, I, E>(
163 required_images: usize,
164 owned_generator: impl Fn() -> Result<F, E>,
165 input_generator: impl Fn() -> I,
166) -> Result<(VecDeque<F>, Box<[I]>), E> {
167 if required_images < 1 {
171 return Ok((VecDeque::new(), Box::new([])));
172 }
173
174 let mut framebuffers = VecDeque::with_capacity(required_images);
175 framebuffers.resize_with(required_images, owned_generator);
176
177 let framebuffers = framebuffers
178 .into_iter()
179 .collect::<Result<VecDeque<F>, E>>()?;
180
181 let mut history_textures = Vec::new();
182 history_textures.resize_with(required_images, input_generator);
183
184 Ok((framebuffers, history_textures.into_boxed_slice()))
185}
186
187fn init_output_framebuffers<F, I, E>(
188 filters_count: usize,
189 last_use: &[usize],
190 owned_generator: impl Fn() -> Result<F, E>,
191 input_generator: impl Fn() -> I,
192) -> Result<(FramebufferPool<F>, Box<[I]>), E> {
193 let mut pool = Vec::with_capacity(filters_count);
194 pool.resize_with(filters_count, &owned_generator);
195 let pool = pool
196 .into_iter()
197 .collect::<Result<Vec<F>, E>>()?
198 .into_boxed_slice();
199
200 let mut textures = Vec::new();
201 textures.resize_with(filters_count, input_generator);
202
203 Ok((
204 FramebufferPool {
205 pool,
206 last_use: last_use.to_vec().into_boxed_slice(),
207 slots: (0..filters_count).map(Slot::new).collect(),
208 },
209 textures.into_boxed_slice(),
210 ))
211}
212
213fn init_feedback_framebuffers<F, I, E>(
214 filters_count: usize,
215 feedback_mask: &BitSet,
216 owned_generator: impl Fn() -> Result<F, E>,
217 input_generator: impl Fn() -> I,
218) -> Result<(FramebufferPool<F>, Box<[I]>), E> {
219
220 fn assign_slots(mask: &BitSet, filters_count: usize) -> (usize, Box<[Slot]>) {
222 let mut slot_of_pass = vec![Slot::NONE; filters_count];
223 let mut count = 0;
224 for pass in mask.iter() {
225 if pass < filters_count {
226 slot_of_pass[pass] = Slot::new(count);
227 count += 1;
228 }
229 }
230 (count, slot_of_pass.into_boxed_slice())
231 }
232
233 let (count, slots) = assign_slots(feedback_mask, filters_count);
234
235 let mut pool = Vec::with_capacity(count);
236 pool.resize_with(count, owned_generator);
237 let pool = pool
238 .into_iter()
239 .collect::<Result<Vec<F>, E>>()?
240 .into_boxed_slice();
241
242 let mut textures = Vec::new();
243 textures.resize_with(filters_count, input_generator);
244
245 Ok((
246 FramebufferPool {
247 pool,
248 last_use: Box::new([]),
249 slots,
250 },
251 textures.into_boxed_slice(),
252 ))
253}
254
255#[cfg(test)]
256mod tests {
257 use super::{FramebufferPool, Slot};
258 use librashader_common::Size;
259 use std::collections::HashSet;
260
261 fn fb(last_use: Vec<usize>) -> FramebufferPool<()> {
262 let n = last_use.len();
263 FramebufferPool {
264 pool: vec![(); n].into_boxed_slice(),
265 last_use: last_use.into_boxed_slice(),
266 slots: vec![Slot::new(0); n].into_boxed_slice(),
267 }
268 }
269
270 fn distinct(slots: &[Slot]) -> usize {
271 slots.iter().copied().collect::<HashSet<_>>().len()
272 }
273
274 #[test]
275 fn liveness_pools_chain() {
276 let size = |w, h| Size::<u32>::new(w, h);
277 let last_use = vec![1, 2, 10, 4, 5, 6, 7, 8, 9, 10, 10];
278 let sizes = vec![
279 size(1280, 960), size(1280, 960), size(1280, 3360), size(1280, 1680), size(1280, 1680), size(1280, 1680), size(1280, 1680), size(1280, 1680), size(1280, 1680), size(3840, 1680), size(1280, 720), ];
291
292 let mut output = fb(last_use);
293 output.prepare(&sizes);
294
295 assert_eq!(distinct(&output.slots[3..=8]), 2);
298
299 assert_eq!(distinct(&output.slots), 7);
302 let mut seen: std::collections::HashMap<Slot, Size<u32>> = Default::default();
303 for (pass, &slot) in output.slots.iter().enumerate() {
304 assert_eq!(*seen.entry(slot).or_insert(sizes[pass]), sizes[pass]);
305 }
306 }
307
308 #[test]
310 fn liveness_pools_uniform_chain() {
311 let sizes = vec![Size::<u32>::new(1920, 1080); 8];
312 let mut output = fb(vec![1, 2, 3, 4, 5, 6, 7, 7]);
313 output.prepare(&sizes);
314 assert_eq!(distinct(&output.slots), 2);
315 }
316}