jxl_render/vardct/generic/
mod.rs

1use jxl_grid::{AlignedGrid, AllocTracker};
2
3mod dct;
4mod transform;
5#[allow(unused)]
6pub use dct::dct_2d;
7#[allow(unused)]
8pub use transform::*;
9
10#[inline(always)]
11pub fn adaptive_lf_smoothing_impl(
12    width: usize,
13    height: usize,
14    [in_x, in_y, in_b]: [&mut [f32]; 3],
15    [lf_x, lf_y, lf_b]: [f32; 3],
16    tracker: Option<&AllocTracker>,
17) -> crate::Result<()> {
18    const SCALE_SELF: f32 = 0.052262735;
19    const SCALE_SIDE: f32 = 0.2034514;
20    const SCALE_DIAG: f32 = 0.03348292;
21
22    if width <= 2 || height <= 2 {
23        // Nothing to do
24        return Ok(());
25    }
26
27    assert_eq!(in_x.len(), in_y.len());
28    assert_eq!(in_y.len(), in_b.len());
29    assert_eq!(in_x.len(), width * height);
30
31    let mut udsum_x = AlignedGrid::with_alloc_tracker(width, height - 2, tracker)?;
32    let mut udsum_y = AlignedGrid::with_alloc_tracker(width, height - 2, tracker)?;
33    let mut udsum_b = AlignedGrid::with_alloc_tracker(width, height - 2, tracker)?;
34
35    for (g, out) in [
36        (&mut *in_x, udsum_x.buf_mut()),
37        (&mut *in_y, udsum_y.buf_mut()),
38        (&mut *in_b, udsum_b.buf_mut()),
39    ] {
40        let up = g.chunks_exact(width);
41        let down = g[width * 2..].chunks_exact(width);
42        let out = out.chunks_exact_mut(width);
43        for ((up, down), out) in up.zip(down).zip(out) {
44            for ((&u, &d), out) in up.iter().zip(down).zip(out) {
45                *out = u + d;
46            }
47        }
48    }
49
50    let mut in_x_row = in_x.chunks_exact_mut(width).skip(1);
51    let mut in_y_row = in_y.chunks_exact_mut(width).skip(1);
52    let mut in_b_row = in_b.chunks_exact_mut(width).skip(1);
53
54    let mut udsum_x_row = udsum_x.buf_mut().chunks_exact(width);
55    let mut udsum_y_row = udsum_y.buf_mut().chunks_exact(width);
56    let mut udsum_b_row = udsum_b.buf_mut().chunks_exact(width);
57
58    loop {
59        let Some(udsum_x) = udsum_x_row.next() else {
60            break;
61        };
62        let udsum_y = udsum_y_row.next().unwrap();
63        let udsum_b = udsum_b_row.next().unwrap();
64        let in_x = in_x_row.next().unwrap();
65        let in_y = in_y_row.next().unwrap();
66        let in_b = in_b_row.next().unwrap();
67
68        let mut in_x_prev = in_x[0];
69        let mut in_y_prev = in_y[0];
70        let mut in_b_prev = in_b[0];
71        for x in 1..(width - 1) {
72            let x_self = in_x[x];
73            let x_side = in_x_prev + in_x[x + 1] + udsum_x[x];
74            let x_diag = udsum_x[x - 1] + udsum_x[x + 1];
75            let x_wa = x_self * SCALE_SELF + x_side * SCALE_SIDE + x_diag * SCALE_DIAG;
76            let x_gap_t = (x_wa - x_self).abs() / lf_x;
77
78            let y_self = in_y[x];
79            let y_side = in_y_prev + in_y[x + 1] + udsum_y[x];
80            let y_diag = udsum_y[x - 1] + udsum_y[x + 1];
81            let y_wa = y_self * SCALE_SELF + y_side * SCALE_SIDE + y_diag * SCALE_DIAG;
82            let y_gap_t = (y_wa - y_self).abs() / lf_y;
83
84            let b_self = in_b[x];
85            let b_side = in_b_prev + in_b[x + 1] + udsum_b[x];
86            let b_diag = udsum_b[x - 1] + udsum_b[x + 1];
87            let b_wa = b_self * SCALE_SELF + b_side * SCALE_SIDE + b_diag * SCALE_DIAG;
88            let b_gap_t = (b_wa - b_self).abs() / lf_b;
89
90            let gap = 0.5f32.max(x_gap_t).max(y_gap_t).max(b_gap_t);
91            let gap_scale = (3.0 - 4.0 * gap).max(0.0);
92
93            in_x[x] = (x_wa - x_self) * gap_scale + x_self;
94            in_y[x] = (y_wa - y_self) * gap_scale + y_self;
95            in_b[x] = (b_wa - b_self) * gap_scale + b_self;
96            in_x_prev = x_self;
97            in_y_prev = y_self;
98            in_b_prev = b_self;
99        }
100    }
101
102    Ok(())
103}