pub(crate) const CDEF_VERY_LARGE: i32 = 0x4000;
static CDEF_DIRECTIONS: [[(i32, i32); 2]; 8] = [
[(-1, 1), (-2, 2)],
[(0, 1), (-1, 2)],
[(0, 1), (0, 2)],
[(0, 1), (1, 2)],
[(1, 1), (2, 2)],
[(1, 0), (2, 1)],
[(1, 0), (2, 0)],
[(1, 0), (2, -1)],
];
static CDEF_PRI_TAPS: [[i32; 2]; 2] = [[4, 2], [3, 3]];
static CDEF_SEC_TAPS: [i32; 2] = [2, 1];
#[inline]
#[allow(dead_code)]
fn constrain(diff: i32, strength: i32, damping: i32) -> i32 {
constrain_spec(diff, strength, damping)
}
#[inline]
fn log2_floor(v: i32) -> i32 {
if v <= 0 {
0
} else {
31 - (v as u32).leading_zeros() as i32
}
}
#[inline]
fn constrain_spec(diff: i32, strength: i32, damping: i32) -> i32 {
if strength == 0 {
return 0;
}
let shift = (damping - log2_floor(strength)).max(0);
let reduced = strength - (diff.abs() >> shift);
let clamped = reduced.clamp(0, diff.abs());
if diff < 0 { -clamped } else { clamped }
}
pub(crate) fn cdef_direction(
plane: &[i32],
stride: usize,
x: usize,
y: usize,
bd: u8,
) -> (usize, i32) {
let coeff_shift = (bd - 8) as i32;
let mut cost = [0i64; 8];
let mut partial = [[0i32; 15]; 8];
let rows = plane.len() / stride;
for i in 0..8 {
for j in 0..8 {
let yy = (y + i).min(rows - 1);
let xx = (x + j).min(stride - 1);
let p = (plane[yy * stride + xx] >> coeff_shift) - 128;
partial[0][i + j] += p;
partial[1][i + j / 2] += p;
partial[2][i] += p;
partial[3][3 + i - j / 2] += p;
partial[4][7 + i - j] += p;
partial[5][3 - i / 2 + j] += p;
partial[6][j] += p;
partial[7][i / 2 + j] += p;
}
}
#[allow(clippy::needless_range_loop)]
for i in 0..8 {
cost[2] += (partial[2][i] as i64) * (partial[2][i] as i64);
cost[6] += (partial[6][i] as i64) * (partial[6][i] as i64);
}
cost[2] *= 105;
cost[6] *= 105;
const DIV: [i64; 8] = [0, 840, 420, 280, 210, 168, 140, 120];
for i in 0..7 {
let i2 = 2 * i + 1;
cost[0] +=
((partial[0][i] as i64).pow(2) + (partial[0][14 - i] as i64).pow(2)) * DIV[i + 1];
cost[4] +=
((partial[4][i] as i64).pow(2) + (partial[4][14 - i] as i64).pow(2)) * DIV[i + 1];
let _ = i2;
}
cost[0] += (partial[0][7] as i64).pow(2) * 105;
cost[4] += (partial[4][7] as i64).pow(2) * 105;
for s in [1usize, 3, 5, 7] {
for i in 0..5 {
cost[s] += (partial[s][3 + i] as i64).pow(2) * 105;
}
for i in 0..3 {
cost[s] += ((partial[s][i] as i64).pow(2) + (partial[s][10 - i] as i64).pow(2))
* DIV[2 * i + 2];
}
}
let mut best_dir = 0usize;
let mut best = cost[0];
for (d, &c) in cost.iter().enumerate() {
if c > best {
best = c;
best_dir = d;
}
}
let var = ((best - cost[(best_dir + 4) & 7]) >> 10) as i32;
(best_dir, var)
}
pub(crate) fn adjust_pri(pri: i32, var: i32) -> i32 {
if var == 0 {
return 0;
}
let vs = var >> 6;
let l = if vs != 0 { log2_floor(vs).min(12) } else { 0 };
(pri * (4 + l) + 8) >> 4
}
#[allow(clippy::too_many_arguments)]
pub(crate) fn cdef_filter_8x8(
dst: &mut [i32],
src: &[i32],
stride: usize,
x: usize,
y: usize,
pri: i32,
sec: i32,
dir: usize,
damping: i32,
bd: u8,
) {
cdef_filter_block(dst, 0, src, stride, x, y, 8, 8, pri, sec, dir, damping, bd);
}
#[allow(clippy::too_many_arguments)]
pub(crate) fn cdef_filter_block(
dst: &mut [i32],
dst_y0: usize,
src: &[i32],
stride: usize,
x: usize,
y: usize,
bw: usize,
bh: usize,
pri: i32,
sec: i32,
dir: usize,
damping: i32,
bd: u8,
) {
let coeff_shift = (bd - 8) as i32;
let pri_damping = damping.max(1);
let sec_damping = damping.max(1);
let pri_taps = CDEF_PRI_TAPS[((pri >> coeff_shift) & 1) as usize];
let enable_pri = pri != 0;
let enable_sec = sec != 0;
let clipping = enable_pri && enable_sec;
let maxv = (1i32 << bd) - 1;
let rows = src.len() / stride;
for i in 0..bh {
for j in 0..bw {
let cx = x + j;
let cy = y + i;
if cx >= stride || cy >= rows {
continue; }
let centre = src[cy * stride + cx];
if centre == CDEF_VERY_LARGE {
continue;
}
let mut sum = 0i32;
let mut min = centre;
let mut max = centre;
for k in 0..2usize {
if enable_pri {
let (pdr, pdc) = CDEF_DIRECTIONS[dir][k];
for &sgn in &[1i32, -1] {
let p = sample(src, stride, cx as i32 + sgn * pdc, cy as i32 + sgn * pdr);
if p != CDEF_VERY_LARGE {
sum += pri_taps[k] * constrain_spec(p - centre, pri, pri_damping);
if clipping {
if p > max {
max = p;
}
if p < min {
min = p;
}
}
}
}
}
if enable_sec {
for &doff in &[2usize, 6] {
let sd = (dir + doff) & 7;
let (sdr, sdc) = CDEF_DIRECTIONS[sd][k];
for &sgn in &[1i32, -1] {
let p =
sample(src, stride, cx as i32 + sgn * sdc, cy as i32 + sgn * sdr);
if p != CDEF_VERY_LARGE {
sum +=
CDEF_SEC_TAPS[k] * constrain_spec(p - centre, sec, sec_damping);
if clipping {
if p > max {
max = p;
}
if p < min {
min = p;
}
}
}
}
}
}
}
let mut out = centre + ((8 + sum - (sum < 0) as i32) >> 4);
if clipping {
out = out.clamp(min, max);
}
dst[(cy - dst_y0) * stride + cx] = out.clamp(0, maxv);
}
}
}
#[inline]
fn sample(plane: &[i32], stride: usize, x: i32, y: i32) -> i32 {
if x < 0 || y < 0 {
return CDEF_VERY_LARGE;
}
let (x, y) = (x as usize, y as usize);
let rows = plane.len() / stride;
if x >= stride || y >= rows {
return CDEF_VERY_LARGE;
}
plane[y * stride + x]
}
pub(crate) static PRI_CANDIDATES: [i32; 4] = [0, 1, 2, 4];
pub(crate) static SEC_CANDIDATES: [i32; 3] = [0, 1, 2];
pub(crate) fn block_sse_8x8(a: &[i32], b: &[i32], w: usize, h: usize, x: usize, y: usize) -> i64 {
let mut s = 0i64;
let yh = (y + 8).min(h);
let xw = (x + 8).min(w);
for yy in y..yh {
for xx in x..xw {
let d = (a[yy * w + xx] - b[yy * w + xx]) as i64;
s += d * d;
}
}
s
}
pub(crate) fn cdef_dist_8x8(
src: &[i32],
dst: &[i32],
w: usize,
h: usize,
x: usize,
y: usize,
coeff_shift: u32,
) -> i64 {
if x + 8 > w || y + 8 > h {
return block_sse_8x8(dst, src, w, h, x, y);
}
let (mut ss, mut sd, mut ss2, mut sd2, mut ssd) = (0i64, 0i64, 0i64, 0i64, 0i64);
for yy in y..y + 8 {
for xx in x..x + 8 {
let s = src[yy * w + xx] as i64;
let d = dst[yy * w + xx] as i64;
ss += s;
sd += d;
ss2 += s * s;
sd2 += d * d;
ssd += s * d;
}
}
let svar = ss2 - ((ss * ss + 32) >> 6);
let dvar = sd2 - ((sd * sd + 32) >> 6);
let sse = (sd2 + ss2 - 2 * ssd) as f64;
let c1 = (400i64 << (2 * coeff_shift)) as f64;
let c2 = (20000i64 << (4 * coeff_shift)) as f64;
let w = 0.5 * (svar as f64 + dvar as f64 + c1) / (c2 + svar as f64 * dvar as f64).sqrt();
(0.5 + sse * w) as i64
}