#![forbid(unsafe_code)]
use crate::src::align::Align16;
use crate::src::align::Align32;
use crate::src::align::Align64;
use crate::src::align::aligned_inner;
use crate::src::const_fn::const_for;
use crate::src::const_fn::const_min;
use crate::src::levels::BlockSize;
use crate::src::levels::InterIntraPredMode;
use aligned::Aligned;
use paste::paste;
use std::cmp::Ordering;
use strum::EnumCount;
#[derive(Clone, Copy, EnumCount)]
enum WedgeDirectionType {
Horizontal,
Vertical,
Oblique27,
Oblique63,
Oblique117,
Oblique153,
}
struct WedgeCodeType {
pub direction: WedgeDirectionType,
pub x_offset: u8,
pub y_offset: u8,
}
impl WedgeCodeType {
const fn new(x_offset: u8, y_offset: u8, direction: WedgeDirectionType) -> Self {
Self {
direction,
x_offset,
y_offset,
}
}
}
struct WedgeCodeBook {
hgtw: [WedgeCodeType; 16],
hltw: [WedgeCodeType; 16],
heqw: [WedgeCodeType; 16],
}
impl WedgeCodeBook {
const fn build() -> Self {
use WedgeDirectionType::*;
Self {
hgtw: [
WedgeCodeType::new(4, 4, Oblique27),
WedgeCodeType::new(4, 4, Oblique63),
WedgeCodeType::new(4, 4, Oblique117),
WedgeCodeType::new(4, 4, Oblique153),
WedgeCodeType::new(4, 2, Horizontal),
WedgeCodeType::new(4, 4, Horizontal),
WedgeCodeType::new(4, 6, Horizontal),
WedgeCodeType::new(4, 4, Vertical),
WedgeCodeType::new(4, 2, Oblique27),
WedgeCodeType::new(4, 6, Oblique27),
WedgeCodeType::new(4, 2, Oblique153),
WedgeCodeType::new(4, 6, Oblique153),
WedgeCodeType::new(2, 4, Oblique63),
WedgeCodeType::new(6, 4, Oblique63),
WedgeCodeType::new(2, 4, Oblique117),
WedgeCodeType::new(6, 4, Oblique117),
],
hltw: [
WedgeCodeType::new(4, 4, Oblique27),
WedgeCodeType::new(4, 4, Oblique63),
WedgeCodeType::new(4, 4, Oblique117),
WedgeCodeType::new(4, 4, Oblique153),
WedgeCodeType::new(2, 4, Vertical),
WedgeCodeType::new(4, 4, Vertical),
WedgeCodeType::new(6, 4, Vertical),
WedgeCodeType::new(4, 4, Horizontal),
WedgeCodeType::new(4, 2, Oblique27),
WedgeCodeType::new(4, 6, Oblique27),
WedgeCodeType::new(4, 2, Oblique153),
WedgeCodeType::new(4, 6, Oblique153),
WedgeCodeType::new(2, 4, Oblique63),
WedgeCodeType::new(6, 4, Oblique63),
WedgeCodeType::new(2, 4, Oblique117),
WedgeCodeType::new(6, 4, Oblique117),
],
heqw: [
WedgeCodeType::new(4, 4, Oblique27),
WedgeCodeType::new(4, 4, Oblique63),
WedgeCodeType::new(4, 4, Oblique117),
WedgeCodeType::new(4, 4, Oblique153),
WedgeCodeType::new(4, 2, Horizontal),
WedgeCodeType::new(4, 6, Horizontal),
WedgeCodeType::new(2, 4, Vertical),
WedgeCodeType::new(6, 4, Vertical),
WedgeCodeType::new(4, 2, Oblique27),
WedgeCodeType::new(4, 6, Oblique27),
WedgeCodeType::new(4, 2, Oblique153),
WedgeCodeType::new(4, 6, Oblique153),
WedgeCodeType::new(2, 4, Oblique63),
WedgeCodeType::new(6, 4, Oblique63),
WedgeCodeType::new(2, 4, Oblique117),
WedgeCodeType::new(6, 4, Oblique117),
],
}
}
const fn get(&self, w: usize, h: usize) -> &[WedgeCodeType; 16] {
let Self { hgtw, hltw, heqw } = self;
use Ordering::*;
let order = if h < w {
Less
} else if h > w {
Greater
} else {
Equal
};
match order {
Less => hltw,
Equal => heqw,
Greater => hgtw,
}
}
}
const fn insert_border(
mut dst: [[u8; 64]; 64],
y: usize,
src: &[u8; 8],
ctr: usize,
) -> [[u8; 64]; 64] {
{
if ctr > 4 {
const_for!(i in 0..ctr - 4 => {
dst[y][i] = 0;
});
}
}
{
let dst_off = ctr.saturating_sub(4);
let src_off = 4usize.saturating_sub(ctr);
let len = const_min!(64 - ctr, 8);
const_for!(i in 0..len => {
dst[y][dst_off + i] = src[src_off + i];
});
}
{
let ctr = ctr + 4;
if ctr < 64 {
const_for!(i in 0..64 - ctr => {
dst[y][ctr + i] = 64;
});
}
}
dst
}
const fn transposed<const N: usize, const M: usize>(src: &[[u8; N]; M]) -> [[u8; M]; N] {
let mut dst = [[0; M]; N];
const_for!(y in 0..M => {
const_for!(x in 0..N => {
dst[x][y] = src[y][x];
});
});
dst
}
const fn hflip(src: &[[u8; 64]; 64]) -> [[u8; 64]; 64] {
let mut dst = [[0; 64]; 64];
const_for!(y in 0..dst.len() => {
const_for!(x in 0..dst[y].len() => {
dst[y][dst[y].len() - 1 - x] = src[y][x];
});
});
dst
}
const fn invert<const N: usize>(src: &[u8; N], w: usize, h: usize) -> [u8; N] {
assert!(w * h == N);
let mut dst = [0; N];
const_for!(y in 0..h => {
let y_off = y * w;
const_for!(x in 0..w => {
dst[y_off + x] = 64 - src[y_off + x];
});
});
dst
}
const fn copy2d<const N: usize>(
src: &[[u8; 64]; 64],
w: usize,
h: usize,
x_off: usize,
y_off: usize,
) -> [u8; N] {
let mut dst = [0; N];
const_for!(y in 0..h => {
const_for!(x in 0..w => {
dst[y * w + x] = src[y_off + y][x_off + x];
});
});
dst
}
const fn init_chroma<const LEN_LUMA: usize, const LEN_CHROMA: usize>(
luma: &[u8; LEN_LUMA],
sign: bool,
w: usize,
h: usize,
ss_ver: bool,
) -> [u8; LEN_CHROMA] {
let sign = sign as u16;
let ss_ver = ss_ver as usize;
let mut chroma = [0; LEN_CHROMA];
let mut luma_off = 0;
let mut chroma_off = 0;
const_for!(_y in 0..h, step_by 1 + ss_ver => {
const_for!(x in 0..w, step_by 2 => {
let mut sum = luma[luma_off + x] as u16 + luma[luma_off + x + 1] as u16 + 1;
if ss_ver != 0 {
sum += luma[luma_off + w + x] as u16 + luma[luma_off + w + x + 1] as u16 + 1;
}
chroma[chroma_off + (x >> 1)] = (sum - sign >> 1 + ss_ver) as u8;
});
luma_off += w << ss_ver;
chroma_off += w >> 1;
});
chroma
}
struct WedgeMasks<const LEN_444: usize, const LEN_422: usize, const LEN_420: usize> {
masks_444: Align64<[[[u8; LEN_444]; 16]; 2]>,
masks_422: Align64<[[[u8; LEN_422]; 16]; 2]>,
masks_420: Align64<[[[u8; LEN_420]; 16]; 2]>,
signs: u16,
}
impl<const LEN_444: usize, const LEN_422: usize, const LEN_420: usize>
WedgeMasks<LEN_444, LEN_422, LEN_420>
{
const fn fill2d_16x2(
w: usize,
h: usize,
master: &[[[u8; 64]; 64]; WedgeDirectionType::COUNT],
cb: &[WedgeCodeType; 16],
signs: u16,
) -> Self {
assert!(LEN_444 == (w * h) >> 0);
assert!(LEN_422 == (w * h) >> 1);
assert!(LEN_420 == (w * h) >> 2);
let mut masks_444 = [[[0; LEN_444]; 16]; 2];
let mut masks_422 = [[[0; LEN_422]; 16]; 2];
let mut masks_420 = [[[0; LEN_420]; 16]; 2];
const_for!(n in 0..16 => {
masks_444[0][n] = copy2d(
&master[cb[n].direction as usize],
w,
h,
32 - (w * cb[n].x_offset as usize >> 3),
32 - (h * cb[n].y_offset as usize >> 3),
);
});
const_for!(n in 0..16 => {
masks_444[1][n] = invert(&masks_444[0][n], w, h);
});
const_for!(n in 0..16 => {
let sign = (signs >> n & 1) != 0;
let luma = &masks_444[sign as usize][n];
masks_422[sign as usize][n] = init_chroma(luma, false, w, h, false);
masks_422[!sign as usize][n] = init_chroma(luma, true, w, h, false);
masks_420[sign as usize][n] = init_chroma(luma, false, w, h, true);
masks_420[!sign as usize][n] = init_chroma(luma, true, w, h, true);
});
Self {
masks_444: Aligned(masks_444),
masks_422: Aligned(masks_422),
masks_420: Aligned(masks_420),
signs,
}
}
const fn slice(&self) -> [[[&[u8]; 16]; 2]; 3] {
let Self {
masks_444,
masks_422,
masks_420,
signs,
} = self;
let masks_444 = aligned_inner(masks_444);
let masks_422 = aligned_inner(masks_422);
let masks_420 = aligned_inner(masks_420);
let mut masks = [[[&[] as &'static [u8]; 16]; 2]; 3];
const_for!(n in 0..16 => {
let sign = (*signs >> n & 1) != 0;
masks[0][0][n] = &masks_444[sign as usize][n];
masks[0][1][n] = &masks_444[sign as usize][n];
masks[1][0][n] = &masks_422[sign as usize][n];
masks[1][1][n] = &masks_422[!sign as usize][n];
masks[2][0][n] = &masks_420[sign as usize][n];
masks[2][1][n] = &masks_420[!sign as usize][n];
});
masks
}
}
const fn build_master() -> [[[u8; 64]; 64]; WedgeDirectionType::COUNT] {
#[derive(EnumCount)]
enum WedgeMasterLineType {
Odd,
Even,
Vert,
}
const wedge_master_border: [[u8; 8]; WedgeMasterLineType::COUNT] = [
[1, 2, 6, 18, 37, 53, 60, 63],
[1, 4, 11, 27, 46, 58, 62, 63],
[0, 2, 7, 21, 43, 57, 62, 64],
];
let mut master = [[[0; 64]; 64]; WedgeDirectionType::COUNT];
const_for!(y in 0..64 => {
master[WedgeDirectionType::Vertical as usize] = insert_border(
master[WedgeDirectionType::Vertical as usize],
y,
&wedge_master_border[WedgeMasterLineType::Vert as usize],
32,
);
});
const_for!(y in 0..64, step_by 2 => {
let ctr = 48 - (y / 2);
master[WedgeDirectionType::Oblique63 as usize] = insert_border(
master[WedgeDirectionType::Oblique63 as usize],
y,
&wedge_master_border[WedgeMasterLineType::Even as usize],
ctr,
);
master[WedgeDirectionType::Oblique63 as usize] = insert_border(
master[WedgeDirectionType::Oblique63 as usize],
y + 1,
&wedge_master_border[WedgeMasterLineType::Odd as usize],
ctr - 1,
);
});
master[WedgeDirectionType::Oblique27 as usize] =
transposed(&master[WedgeDirectionType::Oblique63 as usize]);
master[WedgeDirectionType::Horizontal as usize] =
transposed(&master[WedgeDirectionType::Vertical as usize]);
master[WedgeDirectionType::Oblique117 as usize] =
hflip(&master[WedgeDirectionType::Oblique63 as usize]);
master[WedgeDirectionType::Oblique153 as usize] =
hflip(&master[WedgeDirectionType::Oblique27 as usize]);
master
}
pub static dav1d_wedge_masks: [[[[&'static [u8]; 16]; 2]; 3]; BlockSize::COUNT] = {
use BlockSize::*;
const master: [[[u8; 64]; 64]; WedgeDirectionType::COUNT] = build_master();
const wedge_codebook_16: WedgeCodeBook = WedgeCodeBook::build();
let mut masks = [[[[&[] as &'static [u8]; 16]; 2]; 3]; BlockSize::COUNT];
macro_rules! fill {
($w:literal x $h:literal, $signs:expr) => {{
static wedge_masks: WedgeMasks<
{ $w * $h },
{ ($w / 2) * $h },
{ ($w / 2) * ($h / 2) },
> = WedgeMasks::fill2d_16x2($w, $h, &master, wedge_codebook_16.get($w, $h), $signs);
paste! {
masks[[<Bs $w x $h>] as usize] = wedge_masks.slice();
}
}};
}
fill!(32 x 32, 0x7bfb);
fill!(32 x 16, 0x7beb);
fill!(32 x 8, 0x6beb);
fill!(16 x 32, 0x7beb);
fill!(16 x 16, 0x7bfb);
fill!(16 x 8, 0x7beb);
fill!( 8 x 32, 0x7aeb);
fill!( 8 x 16, 0x7beb);
fill!( 8 x 8, 0x7bfb);
masks
};
static ii_dc_mask: Align64<[u8; 32 * 32]> = Aligned([32; 32 * 32]);
const N_II_PRED_MODES: usize = InterIntraPredMode::COUNT - 1;
const fn build_nondc_ii_masks<const N: usize>(
w: usize,
h: usize,
step: usize,
) -> [[u8; N]; N_II_PRED_MODES] {
use InterIntraPredMode::*;
const ii_weights_1d: [u8; 32] = [
60, 52, 45, 39, 34, 30, 26, 22, 19, 17, 15, 13, 11, 10, 8, 7, 6, 6, 5, 4, 4, 3, 3, 2, 2, 2,
2, 1, 1, 1, 1, 1,
];
let mut masks = [[0; N]; N_II_PRED_MODES];
const_for!(y in 0..h => {
let off = y * w;
const_for!(i in 0..w => {
masks[Vert as usize - 1][off + i] = ii_weights_1d[y * step];
});
const_for!(x in 0..w => {
masks[Smooth as usize - 1][off + x] = ii_weights_1d[const_min!(x, y) * step];
masks[Hor as usize - 1][off + x] = ii_weights_1d[x * step];
});
});
masks
}
static ii_nondc_mask_32x32: Align64<[[u8; 32 * 32]; N_II_PRED_MODES]> =
Aligned(build_nondc_ii_masks(32, 32, 1));
static ii_nondc_mask_16x32: Align64<[[u8; 16 * 32]; N_II_PRED_MODES]> =
Aligned(build_nondc_ii_masks(16, 32, 1));
static ii_nondc_mask_16x16: Align64<[[u8; 16 * 16]; N_II_PRED_MODES]> =
Aligned(build_nondc_ii_masks(16, 16, 2));
static ii_nondc_mask_8x32: Align64<[[u8; 8 * 32]; N_II_PRED_MODES]> =
Aligned(build_nondc_ii_masks(8, 32, 1));
static ii_nondc_mask_8x16: Align64<[[u8; 8 * 16]; N_II_PRED_MODES]> =
Aligned(build_nondc_ii_masks(8, 16, 2));
static ii_nondc_mask_8x8: Align64<[[u8; 8 * 8]; N_II_PRED_MODES]> =
Aligned(build_nondc_ii_masks(8, 8, 4));
static ii_nondc_mask_4x16: Align64<[[u8; 4 * 16]; N_II_PRED_MODES]> =
Aligned(build_nondc_ii_masks(4, 16, 2));
static ii_nondc_mask_4x8: Align32<[[u8; 4 * 8]; N_II_PRED_MODES]> =
Aligned(build_nondc_ii_masks(4, 8, 4));
static ii_nondc_mask_4x4: Align16<[[u8; 4 * 4]; N_II_PRED_MODES]> =
Aligned(build_nondc_ii_masks(4, 4, 8));
pub static dav1d_ii_masks: [[[&'static [u8]; InterIntraPredMode::COUNT]; 3]; BlockSize::COUNT] = {
use BlockSize::*;
use InterIntraPredMode::*;
let mut masks = [[[&[] as &'static [u8]; InterIntraPredMode::COUNT]; 3]; BlockSize::COUNT];
macro_rules! set {
($h:literal x $w:literal) => {{
let mut a = [&[] as &'static [u8]; InterIntraPredMode::COUNT];
paste! {
a[Dc as usize] = aligned_inner(&ii_dc_mask);
a[Vert as usize] = &aligned_inner(&[<ii_nondc_mask _ $h x $w>])[Vert as usize - 1];
a[Hor as usize] = &aligned_inner(&[<ii_nondc_mask _ $h x $w>])[Hor as usize - 1];
a[Smooth as usize] = &aligned_inner(&[<ii_nondc_mask _ $h x $w>])[Smooth as usize - 1];
}
a
}};
([$($h:literal x $w:literal),*]) => {
[$(set!($h x $w),)*]
}
}
masks[Bs8x8 as usize] = set!([8 x 8, 4 x 8, 4 x 4]);
masks[Bs8x16 as usize] = set!([8 x 16, 4 x 16, 4 x 8]);
masks[Bs16x8 as usize] = set!([16 x 16, 8 x 8, 8 x 8]);
masks[Bs16x16 as usize] = set!([16 x 16, 8 x 16, 8 x 8]);
masks[Bs16x32 as usize] = set!([16 x 32, 8 x 32, 8 x 16]);
masks[Bs32x16 as usize] = set!([32 x 32, 16 x 16, 16 x 16]);
masks[Bs32x32 as usize] = set!([32 x 32, 16 x 32, 16 x 16]);
masks
};