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