1use crate::filter_pass::FilterPassMeta;
2use crate::framebuffer::FramebufferPool;
3use crate::scaling;
4use librashader_common::{ImageFormat, Size};
5use librashader_presets::{Scale2D, ScaleFactor, ScaleType, Scaling};
6use num_traits::AsPrimitive;
7use std::ops::Mul;
8
9pub const MAX_TEXEL_SIZE: f32 = 16384f32;
10
11pub trait ViewportSize<T>
13where
14 T: Mul<ScaleFactor, Output = f32> + Copy + Ord + 'static,
15 f32: AsPrimitive<T>,
16{
17 fn scale_viewport(
21 self,
22 scaling: Scale2D,
23 viewport: Size<T>,
24 original: Size<T>,
25 clamp: Option<T>,
26 ) -> Size<T>;
27}
28
29impl<T> ViewportSize<T> for Size<T>
30where
31 T: Mul<ScaleFactor, Output = f32> + Copy + Ord + 'static,
32 f32: AsPrimitive<T>,
33{
34 fn scale_viewport(
35 self,
36 scaling: Scale2D,
37 viewport: Size<T>,
38 original: Size<T>,
39 clamp: Option<T>,
40 ) -> Size<T>
41 where
42 T: Mul<ScaleFactor, Output = f32> + Copy + Ord + 'static,
43 f32: AsPrimitive<T>,
44 {
45 scaling::scale(scaling, self, viewport, original, clamp)
46 }
47}
48
49pub trait MipmapSize<T> {
51 fn calculate_miplevels(self) -> T;
53
54 fn scale_mipmap(self, miplevel: T) -> Size<T>;
57}
58
59impl MipmapSize<u32> for Size<u32> {
60 fn calculate_miplevels(self) -> u32 {
61 let mut size = std::cmp::max(self.width, self.height);
62 let mut levels = 0;
63 while size != 0 {
64 levels += 1;
65 size >>= 1;
66 }
67
68 levels
69 }
70
71 fn scale_mipmap(self, miplevel: u32) -> Size<u32> {
72 let scaled_width = std::cmp::max(self.width >> miplevel, 1);
73 let scaled_height = std::cmp::max(self.height >> miplevel, 1);
74 Size::new(scaled_width, scaled_height)
75 }
76}
77
78fn scale<T>(
79 scaling: Scale2D,
80 source: Size<T>,
81 viewport: Size<T>,
82 original: Size<T>,
83 clamp: Option<T>,
84) -> Size<T>
85where
86 T: Mul<ScaleFactor, Output = f32> + Copy + Ord + 'static,
87 f32: AsPrimitive<T>,
88{
89 let width = match scaling.x {
90 Scaling {
91 scale_type: ScaleType::Input,
92 factor,
93 } => source.width * factor,
94 Scaling {
95 scale_type: ScaleType::Absolute,
96 factor,
97 } => factor.into(),
98 Scaling {
99 scale_type: ScaleType::Viewport,
100 factor,
101 } => viewport.width * factor,
102 Scaling {
103 scale_type: ScaleType::Original,
104 factor,
105 } => original.width * factor,
106 };
107
108 let height = match scaling.y {
109 Scaling {
110 scale_type: ScaleType::Input,
111 factor,
112 } => source.height * factor,
113 Scaling {
114 scale_type: ScaleType::Absolute,
115 factor,
116 } => factor.into(),
117 Scaling {
118 scale_type: ScaleType::Viewport,
119 factor,
120 } => viewport.height * factor,
121 Scaling {
122 scale_type: ScaleType::Original,
123 factor,
124 } => original.height * factor,
125 };
126
127 Size {
128 width: std::cmp::min(
129 std::cmp::max(width.round().as_(), 1f32.as_()),
130 clamp.unwrap_or(MAX_TEXEL_SIZE.as_()),
131 ),
132 height: std::cmp::min(
133 std::cmp::max(height.round().as_(), 1f32.as_()),
134 clamp.unwrap_or(MAX_TEXEL_SIZE.as_()),
135 ),
136 }
137}
138
139pub trait ScaleFramebuffer<T = ()> {
141 type Error;
142 type Context;
143 fn scale(
145 &mut self,
146 scaling: Scale2D,
147 format: ImageFormat,
148 viewport_size: &Size<u32>,
149 source_size: &Size<u32>,
150 original_size: &Size<u32>,
151 should_mipmap: bool,
152 context: &Self::Context,
153 ) -> Result<Size<u32>, Self::Error>;
154
155 #[inline(always)]
158 fn scale_feedback_framebuffers<P>(
159 source_size: Size<u32>,
160 viewport_size: Size<u32>,
161 original_size: Size<u32>,
162 feedback: &mut FramebufferPool<Self>,
163 passes: &[P],
164 callback: impl FnMut(usize, &P, &Self) -> Result<(), Self::Error>,
165 ) -> Result<(), Self::Error>
166 where
167 Self: Sized,
168 Self::Context: Default,
169 P: FilterPassMeta,
170 {
171 Self::scale_feedback_framebuffers_with_context(
172 source_size,
173 viewport_size,
174 original_size,
175 feedback,
176 passes,
177 &Self::Context::default(),
178 callback,
179 )
180 }
181
182 #[inline(always)]
184 fn scale_feedback_framebuffers_with_context<P>(
185 source_size: Size<u32>,
186 viewport_size: Size<u32>,
187 original_size: Size<u32>,
188 feedback: &mut FramebufferPool<Self>,
189 passes: &[P],
190 context: &Self::Context,
191 callback: impl FnMut(usize, &P, &Self) -> Result<(), Self::Error>,
192 ) -> Result<(), Self::Error>
193 where
194 Self: Sized,
195 P: FilterPassMeta,
196 {
197 scale_feedback_framebuffers_callback::<T, Self, Self::Error, Self::Context, P, _>(
198 source_size,
199 viewport_size,
200 original_size,
201 feedback,
202 passes,
203 context,
204 callback,
205 )
206 }
207
208 #[inline(always)]
211 fn scale_output_framebuffers<P>(
212 source_size: Size<u32>,
213 viewport_size: Size<u32>,
214 original_size: Size<u32>,
215 output: &mut FramebufferPool<Self>,
216 passes: &mut [P],
217 callback: impl FnMut(usize, &mut P, &Self, Size<u32>) -> Result<(), Self::Error>,
218 ) -> Result<(), Self::Error>
219 where
220 Self: Sized,
221 Self::Context: Default,
222 P: FilterPassMeta,
223 {
224 Self::scale_output_framebuffers_with_context(
225 source_size,
226 viewport_size,
227 original_size,
228 output,
229 passes,
230 &Self::Context::default(),
231 callback,
232 )
233 }
234
235 #[inline(always)]
237 fn scale_output_framebuffers_with_context<P>(
238 source_size: Size<u32>,
239 viewport_size: Size<u32>,
240 original_size: Size<u32>,
241 output: &mut FramebufferPool<Self>,
242 passes: &mut [P],
243 context: &Self::Context,
244 callback: impl FnMut(usize, &mut P, &Self, Size<u32>) -> Result<(), Self::Error>,
245 ) -> Result<(), Self::Error>
246 where
247 Self: Sized,
248 P: FilterPassMeta,
249 {
250 scale_output_framebuffers_callback::<T, Self, Self::Error, Self::Context, P, _>(
251 source_size,
252 viewport_size,
253 original_size,
254 output,
255 passes,
256 context,
257 callback,
258 )
259 }
260}
261
262#[inline(always)]
263fn scale_feedback_framebuffers_callback<T, F, E, C, P, CB>(
264 source_size: Size<u32>,
265 viewport_size: Size<u32>,
266 original_size: Size<u32>,
267 feedback: &mut FramebufferPool<F>,
268 passes: &[P],
269 context: &C,
270 mut callback: CB,
271) -> Result<(), E>
272where
273 F: ScaleFramebuffer<T, Context = C, Error = E>,
274 P: FilterPassMeta,
275 CB: FnMut(usize, &P, &F) -> Result<(), E>,
276{
277 let mut iterator = passes.iter().enumerate().peekable();
278 let mut target_size = source_size;
279 while let Some((index, pass)) = iterator.next() {
280 let should_mipmap = iterator
281 .peek()
282 .map_or(false, |(_, p)| p.meta().mipmap_input);
283
284 let next_size = target_size.scale_viewport(
285 pass.meta().scaling.clone(),
286 viewport_size,
287 original_size,
288 None,
289 );
290
291 if feedback.contains(index) {
292 feedback[index].scale(
293 pass.meta().scaling.clone(),
294 pass.get_format(),
295 &viewport_size,
296 &target_size,
297 &original_size,
298 should_mipmap,
299 context,
300 )?;
301 callback(index, pass, &feedback[index])?;
302 }
303
304 target_size = next_size;
305 }
306
307 Ok(())
308}
309
310#[inline(always)]
311fn scale_output_framebuffers_callback<T, F, E, C, P, CB>(
312 source_size: Size<u32>,
313 viewport_size: Size<u32>,
314 original_size: Size<u32>,
315 output: &mut FramebufferPool<F>,
316 passes: &mut [P],
317 context: &C,
318 mut callback: CB,
319) -> Result<(), E>
320where
321 F: ScaleFramebuffer<T, Context = C, Error = E>,
322 P: FilterPassMeta,
323 CB: FnMut(usize, &mut P, &F, Size<u32>) -> Result<(), E>,
324{
325 let len = passes.len();
326
327 let mut sizes = Vec::with_capacity(len);
330 let mut target_size = source_size;
331 for pass in passes.iter() {
332 target_size = target_size.scale_viewport(
333 pass.meta().scaling.clone(),
334 viewport_size,
335 original_size,
336 None,
337 );
338 sizes.push(target_size);
339 }
340
341 output.prepare(&sizes);
342
343 for index in 0..len {
344 let scaling = passes[index].meta().scaling.clone();
345 let format = passes[index].get_format();
346 let should_mipmap = passes
347 .get(index + 1)
348 .map_or(false, |p| p.meta().mipmap_input);
349 let prev = if index == 0 {
350 source_size
351 } else {
352 sizes[index - 1]
353 };
354
355 let size = output[index].scale(
356 scaling,
357 format,
358 &viewport_size,
359 &prev,
360 &original_size,
361 should_mipmap,
362 context,
363 )?;
364
365 callback(index, &mut passes[index], &output[index], size)?;
366 }
367
368 Ok(())
369}