blob: 9c0f807356313ed57605d9ece9a546e6e11a49d6 [file] [log] [blame]
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use std::simd::prelude::*;
use std::simd::Simd;
use crate::Reg;
const fn create_bayer_matrix(num: i32, denom: i32) -> [[i16; 4]; 4] {
#[rustfmt::skip]
let base_pattern: [[i32; 4]; 4] = [
[ 0, 8, 2, 10],
[12, 4, 14, 6],
[ 3, 11, 1, 9],
[15, 7, 13, 5],
];
let mut matrix = [[0i16; 4]; 4];
// Only while loops are possible, not for, in const fns
let mut y = 0;
let mut x = 0;
while y < 4 {
while x < 4 {
let value = (base_pattern[y][x] - 8) * num / denom / 16;
matrix[y][x] = value as i16;
x += 1;
}
y += 1;
}
matrix
}
// RGB565 dither table, strengthened by 1.33x (for better masking of banding).
const BAYER_31: [[i16; 4]; 4] = create_bayer_matrix(255 * 4, 31 * 3);
const BAYER_63: [[i16; 4]; 4] = create_bayer_matrix(255 * 4, 63 * 3);
/// Bayer dithering. The purpose of the dithering is mostly to mask artifacts;
/// the strength of dithering is not really related to the quantization scheme
/// (444 or 555) nor the selector table values.
#[inline]
pub fn dither(data: &[[[Reg; 3]; 4]; 4]) -> [[[Reg; 3]; 4]; 4] {
let mut out = [[[Reg::default(); 3]; 4]; 4];
for y in 0..4 {
for x in 0..4 {
for (ch, matrix) in [(0, &BAYER_31), (1, &BAYER_63), (2, &BAYER_31)] {
out[y][x][ch] = (data[y][x][ch] + Simd::splat(matrix[y][x]))
.simd_clamp(Simd::splat(0), Simd::splat(255));
}
}
}
out
}