zoomvtools 2.0.0

Video motion vector analysis utilities in pure Rust
Documentation
#[cfg(all(target_arch = "x86_64", feature = "simd"))]
mod avx2;
mod rust;

#[cfg(test)]
mod tests;

use std::num::NonZeroUsize;

use crate::util::Pixel;

#[cfg(all(target_arch = "x86_64", feature = "simd"))]
pub const MAX_REFS_SIZE: usize = 12;

pub type DegrainFn = unsafe fn(
    dest: *mut u8,
    dest_stride_bytes: NonZeroUsize,
    src: *const u8,
    src_stride_bytes: NonZeroUsize,
    refs: &[*const u8],
    refs_strides_bytes: &[NonZeroUsize],
    w_src: i32,
    w_refs: &[i32],
);

#[must_use]
#[inline]
pub fn select_degrain<T: Pixel, const RADIUS: usize>(
    width: NonZeroUsize,
    height: NonZeroUsize,
) -> DegrainFn {
    #[cfg(all(target_arch = "x86_64", feature = "simd"))]
    if cpudetect::x86_64::is_x86_64_v3_compatible() {
        // PERF: 75-90% faster than scalar on test machine
        // depending on block size
        return select_degrain_avx2::<T, RADIUS>(width, height);
    }

    select_degrain_rust::<T, RADIUS>(width, height)
}

#[must_use]
fn select_degrain_rust<T: Pixel, const RADIUS: usize>(
    width: NonZeroUsize,
    height: NonZeroUsize,
) -> DegrainFn {
    match (width.get(), height.get()) {
        (2, 2) => rust::degrain::<T, RADIUS, 2, 2>,
        (2, 4) => rust::degrain::<T, RADIUS, 2, 4>,
        (4, 2) => rust::degrain::<T, RADIUS, 4, 2>,
        (4, 4) => rust::degrain::<T, RADIUS, 4, 4>,
        (4, 8) => rust::degrain::<T, RADIUS, 4, 8>,
        (8, 1) => rust::degrain::<T, RADIUS, 8, 1>,
        (8, 2) => rust::degrain::<T, RADIUS, 8, 2>,
        (8, 4) => rust::degrain::<T, RADIUS, 8, 4>,
        (8, 8) => rust::degrain::<T, RADIUS, 8, 8>,
        (8, 16) => rust::degrain::<T, RADIUS, 8, 16>,
        (16, 1) => rust::degrain::<T, RADIUS, 16, 1>,
        (16, 2) => rust::degrain::<T, RADIUS, 16, 2>,
        (16, 4) => rust::degrain::<T, RADIUS, 16, 4>,
        (16, 8) => rust::degrain::<T, RADIUS, 16, 8>,
        (16, 16) => rust::degrain::<T, RADIUS, 16, 16>,
        (16, 32) => rust::degrain::<T, RADIUS, 16, 32>,
        (32, 8) => rust::degrain::<T, RADIUS, 32, 8>,
        (32, 16) => rust::degrain::<T, RADIUS, 32, 16>,
        (32, 32) => rust::degrain::<T, RADIUS, 32, 32>,
        (32, 64) => rust::degrain::<T, RADIUS, 32, 64>,
        (64, 16) => rust::degrain::<T, RADIUS, 64, 16>,
        (64, 32) => rust::degrain::<T, RADIUS, 64, 32>,
        (64, 64) => rust::degrain::<T, RADIUS, 64, 64>,
        (64, 128) => rust::degrain::<T, RADIUS, 64, 128>,
        (128, 32) => rust::degrain::<T, RADIUS, 128, 32>,
        (128, 64) => rust::degrain::<T, RADIUS, 128, 64>,
        (128, 128) => rust::degrain::<T, RADIUS, 128, 128>,
        _ => unreachable!(),
    }
}

#[cfg(all(target_arch = "x86_64", feature = "simd"))]
#[must_use]
pub(super) fn select_degrain_avx2<T: Pixel, const RADIUS: usize>(
    width: NonZeroUsize,
    height: NonZeroUsize,
) -> DegrainFn {
    match std::mem::size_of::<T>() {
        1 => select_degrain_avx2_u8::<RADIUS>(width, height),
        2 => select_degrain_avx2_u16::<RADIUS>(width, height),
        _ => unreachable!(),
    }
}

#[cfg(all(target_arch = "x86_64", feature = "simd"))]
#[must_use]
fn select_degrain_avx2_u8<const RADIUS: usize>(
    width: NonZeroUsize,
    height: NonZeroUsize,
) -> DegrainFn {
    match (width.get(), height.get()) {
        (2, 2) => avx2::degrain_u8::<RADIUS, 2, 2>,
        (2, 4) => avx2::degrain_u8::<RADIUS, 2, 4>,
        (4, 2) => avx2::degrain_u8::<RADIUS, 4, 2>,
        (4, 4) => avx2::degrain_u8::<RADIUS, 4, 4>,
        (4, 8) => avx2::degrain_u8::<RADIUS, 4, 8>,
        (8, 1) => avx2::degrain_u8::<RADIUS, 8, 1>,
        (8, 2) => avx2::degrain_u8::<RADIUS, 8, 2>,
        (8, 4) => avx2::degrain_u8::<RADIUS, 8, 4>,
        (8, 8) => avx2::degrain_u8::<RADIUS, 8, 8>,
        (8, 16) => avx2::degrain_u8::<RADIUS, 8, 16>,
        (16, 1) => avx2::degrain_u8::<RADIUS, 16, 1>,
        (16, 2) => avx2::degrain_u8::<RADIUS, 16, 2>,
        (16, 4) => avx2::degrain_u8::<RADIUS, 16, 4>,
        (16, 8) => avx2::degrain_u8::<RADIUS, 16, 8>,
        (16, 16) => avx2::degrain_u8::<RADIUS, 16, 16>,
        (16, 32) => avx2::degrain_u8::<RADIUS, 16, 32>,
        (32, 8) => avx2::degrain_u8::<RADIUS, 32, 8>,
        (32, 16) => avx2::degrain_u8::<RADIUS, 32, 16>,
        (32, 32) => avx2::degrain_u8::<RADIUS, 32, 32>,
        (32, 64) => avx2::degrain_u8::<RADIUS, 32, 64>,
        (64, 16) => avx2::degrain_u8::<RADIUS, 64, 16>,
        (64, 32) => avx2::degrain_u8::<RADIUS, 64, 32>,
        (64, 64) => avx2::degrain_u8::<RADIUS, 64, 64>,
        (64, 128) => avx2::degrain_u8::<RADIUS, 64, 128>,
        (128, 32) => avx2::degrain_u8::<RADIUS, 128, 32>,
        (128, 64) => avx2::degrain_u8::<RADIUS, 128, 64>,
        (128, 128) => avx2::degrain_u8::<RADIUS, 128, 128>,
        _ => unreachable!(),
    }
}

#[cfg(all(target_arch = "x86_64", feature = "simd"))]
#[must_use]
fn select_degrain_avx2_u16<const RADIUS: usize>(
    width: NonZeroUsize,
    height: NonZeroUsize,
) -> DegrainFn {
    match (width.get(), height.get()) {
        (2, 2) => avx2::degrain_u16::<RADIUS, 2, 2>,
        (2, 4) => avx2::degrain_u16::<RADIUS, 2, 4>,
        (4, 2) => avx2::degrain_u16::<RADIUS, 4, 2>,
        (4, 4) => avx2::degrain_u16::<RADIUS, 4, 4>,
        (4, 8) => avx2::degrain_u16::<RADIUS, 4, 8>,
        (8, 1) => avx2::degrain_u16::<RADIUS, 8, 1>,
        (8, 2) => avx2::degrain_u16::<RADIUS, 8, 2>,
        (8, 4) => avx2::degrain_u16::<RADIUS, 8, 4>,
        (8, 8) => avx2::degrain_u16::<RADIUS, 8, 8>,
        (8, 16) => avx2::degrain_u16::<RADIUS, 8, 16>,
        (16, 1) => avx2::degrain_u16::<RADIUS, 16, 1>,
        (16, 2) => avx2::degrain_u16::<RADIUS, 16, 2>,
        (16, 4) => avx2::degrain_u16::<RADIUS, 16, 4>,
        (16, 8) => avx2::degrain_u16::<RADIUS, 16, 8>,
        (16, 16) => avx2::degrain_u16::<RADIUS, 16, 16>,
        (16, 32) => avx2::degrain_u16::<RADIUS, 16, 32>,
        (32, 8) => avx2::degrain_u16::<RADIUS, 32, 8>,
        (32, 16) => avx2::degrain_u16::<RADIUS, 32, 16>,
        (32, 32) => avx2::degrain_u16::<RADIUS, 32, 32>,
        (32, 64) => avx2::degrain_u16::<RADIUS, 32, 64>,
        (64, 16) => avx2::degrain_u16::<RADIUS, 64, 16>,
        (64, 32) => avx2::degrain_u16::<RADIUS, 64, 32>,
        (64, 64) => avx2::degrain_u16::<RADIUS, 64, 64>,
        (64, 128) => avx2::degrain_u16::<RADIUS, 64, 128>,
        (128, 32) => avx2::degrain_u16::<RADIUS, 128, 32>,
        (128, 64) => avx2::degrain_u16::<RADIUS, 128, 64>,
        (128, 128) => avx2::degrain_u16::<RADIUS, 128, 128>,
        _ => unreachable!(),
    }
}