librashader_runtime/
framebuffer.rs

1use crate::binding::{BindingRequirements, BindingUtil};
2use librashader_reflect::reflect::semantics::BindingMeta;
3use std::collections::VecDeque;
4
5/// Helper to initialize framebuffers in a graphics API agnostic way.
6pub struct FramebufferInit<'a, F, I, E> {
7    owned_generator: &'a dyn Fn() -> Result<F, E>,
8    input_generator: &'a dyn Fn() -> I,
9    requirements: BindingRequirements,
10    filters_count: usize,
11}
12
13impl<'a, F, I, E> FramebufferInit<'a, F, I, E> {
14    /// Create a new framebuffer initializer with the given
15    /// closures to create owned framebuffers and image views.
16    pub fn new(
17        filters: impl Iterator<Item = &'a BindingMeta> + ExactSizeIterator,
18        owned_generator: &'a dyn Fn() -> Result<F, E>,
19        input_generator: &'a dyn Fn() -> I,
20    ) -> Self {
21        let filters_count = filters.len();
22        let requirements = BindingMeta::calculate_requirements(filters);
23
24        Self {
25            owned_generator,
26            input_generator,
27            filters_count,
28            requirements,
29        }
30    }
31
32    /// Initialize history framebuffers and views.
33    pub fn init_history(&self) -> Result<(VecDeque<F>, Box<[I]>), E> {
34        init_history(
35            self.requirements.required_history,
36            self.owned_generator,
37            self.input_generator,
38        )
39    }
40
41    /// Initialize output framebuffers and views.
42    pub fn init_output_framebuffers(&self) -> Result<(Box<[F]>, Box<[I]>), E> {
43        init_output_framebuffers(
44            self.filters_count,
45            self.owned_generator,
46            self.input_generator,
47        )
48    }
49
50    /// Get if the final pass is used as feedback.
51    pub const fn uses_final_pass_as_feedback(&self) -> bool {
52        self.requirements.uses_final_pass_as_feedback
53    }
54}
55
56fn init_history<'a, F, I, E>(
57    required_images: usize,
58    owned_generator: impl Fn() -> Result<F, E>,
59    input_generator: impl Fn() -> I,
60) -> Result<(VecDeque<F>, Box<[I]>), E> {
61    // Since OriginalHistory0 aliases source, it always gets bound if present, and we don't need to
62    // store it. However, if even OriginalHistory1 is used, then we need to store it, hence we check if
63    // required_images is less than 1, and only then do we return an empty history queue.
64    if required_images < 1 {
65        return Ok((VecDeque::new(), Box::new([])));
66    }
67
68    let mut framebuffers = VecDeque::with_capacity(required_images);
69    framebuffers.resize_with(required_images, owned_generator);
70
71    let framebuffers = framebuffers
72        .into_iter()
73        .collect::<Result<VecDeque<F>, E>>()?;
74
75    let mut history_textures = Vec::new();
76    history_textures.resize_with(required_images, input_generator);
77
78    Ok((framebuffers, history_textures.into_boxed_slice()))
79}
80
81fn init_output_framebuffers<F, I, E>(
82    len: usize,
83    owned_generator: impl Fn() -> Result<F, E>,
84    input_generator: impl Fn() -> I,
85) -> Result<(Box<[F]>, Box<[I]>), E> {
86    let mut output_framebuffers = Vec::new();
87    output_framebuffers.resize_with(len, owned_generator);
88
89    // resolve all results
90    let output_framebuffers = output_framebuffers
91        .into_iter()
92        .collect::<Result<Vec<F>, E>>()?;
93
94    let mut output_textures = Vec::new();
95    output_textures.resize_with(len, input_generator);
96
97    Ok((
98        output_framebuffers.into_boxed_slice(),
99        output_textures.into_boxed_slice(),
100    ))
101}