use crate::convolution::ColumnFilter;
use crate::filter_weights::{FilterBounds, FilterWeights};
use crate::{ImageSize, ImageStore, ImageStoreMut, ThreadingPolicy};
use novtb::{ParallelZonedIterator, TbSliceMut};
pub(crate) struct VerticalFiltering<T, F, const N: usize> {
pub(crate) filter_row: fn(usize, &FilterBounds, &[T], &mut [T], usize, &[F], u32),
pub(crate) filter_weights: FilterWeights<F>,
pub(crate) threading_policy: ThreadingPolicy,
}
impl<T: Send + Sync, F: Send + Sync, const N: usize> ColumnFilter<T, N>
for VerticalFiltering<T, F, N>
where
[T]: ToOwned<Owned = Vec<T>>,
{
fn filter(&self, source: &ImageStore<'_, T, N>, destination: &mut ImageStoreMut<T, N>) {
let pool = self
.threading_policy
.get_nova_pool(ImageSize::new(destination.width, destination.height));
let src_stride = source.stride();
let dst_stride = destination.stride();
let dst_width = destination.width;
let row_filter = self.filter_row;
let dst_bit_depth = destination.bit_depth as u32;
let dst_buffer = destination.projected();
let source_buffer = source.projected();
dst_buffer
.tb_par_chunks_mut(dst_stride)
.for_each_enumerated(&pool, |y, row| {
if row.is_empty() {
return;
}
let bounds = self.filter_weights.bounds[y];
let filter_offset = y * self.filter_weights.aligned_size;
let weights = &self.filter_weights.weights[filter_offset..];
row_filter(
dst_width,
&bounds,
source_buffer,
&mut row[..dst_width * N],
src_stride,
weights,
dst_bit_depth,
);
});
}
fn run_on_row(
&self,
src: &[T],
dst: &mut [T],
dst_width: usize,
src_stride: usize,
y: usize,
bit_depth: u32,
) {
let bounds = self.filter_weights.bounds[y];
let filter_offset = y * self.filter_weights.aligned_size;
let weights = &self.filter_weights.weights[filter_offset..];
let row_filter = self.filter_row;
row_filter(
dst_width,
&bounds,
src,
&mut dst[..dst_width * N],
src_stride,
weights,
bit_depth,
);
}
}