1use crate::filter_pass::FilterPassMeta;
2use crate::scaling;
3use librashader_common::{ImageFormat, Size};
4use librashader_presets::{Scale2D, ScaleFactor, ScaleType, Scaling};
5use num_traits::AsPrimitive;
6use std::ops::Mul;
7
8pub const MAX_TEXEL_SIZE: f32 = 16384f32;
9
10pub trait ViewportSize<T>
12where
13 T: Mul<ScaleFactor, Output = f32> + Copy + Ord + 'static,
14 f32: AsPrimitive<T>,
15{
16 fn scale_viewport(self, scaling: Scale2D, viewport: Size<T>, original: Size<T>) -> Size<T>;
19}
20
21impl<T> ViewportSize<T> for Size<T>
22where
23 T: Mul<ScaleFactor, Output = f32> + Copy + Ord + 'static,
24 f32: AsPrimitive<T>,
25{
26 fn scale_viewport(self, scaling: Scale2D, viewport: Size<T>, original: Size<T>) -> Size<T>
27 where
28 T: Mul<ScaleFactor, Output = f32> + Copy + Ord + 'static,
29 f32: AsPrimitive<T>,
30 {
31 scaling::scale(scaling, self, viewport, original)
32 }
33}
34
35pub trait MipmapSize<T> {
37 fn calculate_miplevels(self) -> T;
39
40 fn scale_mipmap(self, miplevel: T) -> Size<T>;
43}
44
45impl MipmapSize<u32> for Size<u32> {
46 fn calculate_miplevels(self) -> u32 {
47 let mut size = std::cmp::max(self.width, self.height);
48 let mut levels = 0;
49 while size != 0 {
50 levels += 1;
51 size >>= 1;
52 }
53
54 levels
55 }
56
57 fn scale_mipmap(self, miplevel: u32) -> Size<u32> {
58 let scaled_width = std::cmp::max(self.width >> miplevel, 1);
59 let scaled_height = std::cmp::max(self.height >> miplevel, 1);
60 Size::new(scaled_width, scaled_height)
61 }
62}
63
64fn scale<T>(scaling: Scale2D, source: Size<T>, viewport: Size<T>, original: Size<T>) -> Size<T>
65where
66 T: Mul<ScaleFactor, Output = f32> + Copy + Ord + 'static,
67 f32: AsPrimitive<T>,
68{
69 let width = match scaling.x {
70 Scaling {
71 scale_type: ScaleType::Input,
72 factor,
73 } => source.width * factor,
74 Scaling {
75 scale_type: ScaleType::Absolute,
76 factor,
77 } => factor.into(),
78 Scaling {
79 scale_type: ScaleType::Viewport,
80 factor,
81 } => viewport.width * factor,
82 Scaling {
83 scale_type: ScaleType::Original,
84 factor,
85 } => original.width * factor,
86 };
87
88 let height = match scaling.y {
89 Scaling {
90 scale_type: ScaleType::Input,
91 factor,
92 } => source.height * factor,
93 Scaling {
94 scale_type: ScaleType::Absolute,
95 factor,
96 } => factor.into(),
97 Scaling {
98 scale_type: ScaleType::Viewport,
99 factor,
100 } => viewport.height * factor,
101 Scaling {
102 scale_type: ScaleType::Original,
103 factor,
104 } => original.height * factor,
105 };
106
107 Size {
108 width: std::cmp::min(
109 std::cmp::max(width.round().as_(), 1f32.as_()),
110 MAX_TEXEL_SIZE.as_(),
111 ),
112 height: std::cmp::min(
113 std::cmp::max(height.round().as_(), 1f32.as_()),
114 MAX_TEXEL_SIZE.as_(),
115 ),
116 }
117}
118
119pub trait ScaleFramebuffer<T = ()> {
121 type Error;
122 type Context;
123 fn scale(
125 &mut self,
126 scaling: Scale2D,
127 format: ImageFormat,
128 viewport_size: &Size<u32>,
129 source_size: &Size<u32>,
130 original_size: &Size<u32>,
131 should_mipmap: bool,
132 context: &Self::Context,
133 ) -> Result<Size<u32>, Self::Error>;
134
135 #[inline(always)]
137 fn scale_framebuffers<P>(
138 source_size: Size<u32>,
139 viewport_size: Size<u32>,
140 original_size: Size<u32>,
141 output: &mut [Self],
142 feedback: &mut [Self],
143 passes: &[P],
144 callback: Option<&mut dyn FnMut(usize, &P, &Self, &Self) -> Result<(), Self::Error>>,
145 ) -> Result<(), Self::Error>
146 where
147 Self: Sized,
148 Self::Context: Default,
149 P: FilterPassMeta,
150 {
151 scale_framebuffers_with_context_callback::<T, Self, Self::Error, Self::Context, _>(
152 source_size,
153 viewport_size,
154 original_size,
155 output,
156 feedback,
157 passes,
158 &Self::Context::default(),
159 callback,
160 )
161 }
162
163 #[inline(always)]
165 fn scale_framebuffers_with_context<P>(
166 source_size: Size<u32>,
167 viewport_size: Size<u32>,
168 original_size: Size<u32>,
169 output: &mut [Self],
170 feedback: &mut [Self],
171 passes: &[P],
172 context: &Self::Context,
173 callback: Option<&mut dyn FnMut(usize, &P, &Self, &Self) -> Result<(), Self::Error>>,
174 ) -> Result<(), Self::Error>
175 where
176 Self: Sized,
177 P: FilterPassMeta,
178 {
179 scale_framebuffers_with_context_callback::<T, Self, Self::Error, Self::Context, _>(
180 source_size,
181 viewport_size,
182 original_size,
183 output,
184 feedback,
185 passes,
186 context,
187 callback,
188 )
189 }
190}
191
192#[inline(always)]
195fn scale_framebuffers_with_context_callback<T, F, E, C, P>(
196 source_size: Size<u32>,
197 viewport_size: Size<u32>,
198 original_size: Size<u32>,
199 output: &mut [F],
200 feedback: &mut [F],
201 passes: &[P],
202 context: &C,
203 mut callback: Option<&mut dyn FnMut(usize, &P, &F, &F) -> Result<(), E>>,
204) -> Result<(), E>
205where
206 F: ScaleFramebuffer<T, Context = C, Error = E>,
207 P: FilterPassMeta,
208{
209 assert_eq!(output.len(), feedback.len());
210 let mut iterator = passes.iter().enumerate().peekable();
211 let mut target_size = source_size;
212 while let Some((index, pass)) = iterator.next() {
213 let should_mipmap = iterator
214 .peek()
215 .map_or(false, |(_, p)| p.meta().mipmap_input);
216
217 let next_size = output[index].scale(
218 pass.meta().scaling.clone(),
219 pass.get_format(),
220 &viewport_size,
221 &target_size,
222 &original_size,
223 should_mipmap,
224 context,
225 )?;
226
227 feedback[index].scale(
228 pass.meta().scaling.clone(),
229 pass.get_format(),
230 &viewport_size,
231 &target_size,
232 &original_size,
233 should_mipmap,
234 context,
235 )?;
236
237 target_size = next_size;
238
239 if let Some(callback) = callback.as_mut() {
240 callback(index, pass, &output[index], &feedback[index])?;
241 }
242 }
243
244 Ok(())
245}