use crate::{
bitmap::{BitmapRawData, BitmapRawDataMut},
colour::{read_from_bytes, write_as_bytes},
formats::{Abgr32, PixelFormatSpec, Rgba32, Rgba32P, A8},
math::{clip_to, PixelBox, PixelPoint},
};
use super::{dispatch::BinaryDispatch, BinaryOpSpec, GenericBinary};
#[cfg(target_arch = "x86_64")]
mod x86_64;
pub struct CopyFromOp;
#[cfg(test)]
const _: () = {
use super::generate;
impl generate::BinaryInputSpec for CopyFromOp {
fn gen<'l>() -> impl generate::ValueGeneratorList<'l, OutputTuple = Self::Params<'l>> {
(generate::src_area, generate::dst_point)
}
}
};
impl BinaryOpSpec for CopyFromOp {
type Params<'l> = (PixelBox, PixelPoint);
fn build<'l>() -> BinaryDispatch<Self::Params<'l>> {
BinaryDispatch::from_generic::<Self>()
.with::<A8, A8>(copy_same_fmt::<{ A8::PIXEL_STRIDE }>)
.with::<Abgr32, Abgr32>(copy_same_fmt::<{ Abgr32::PIXEL_STRIDE }>)
.with::<Rgba32, Rgba32>(copy_same_fmt::<{ Rgba32::PIXEL_STRIDE }>)
.with::<Rgba32P, Rgba32P>(copy_same_fmt::<{ Rgba32P::PIXEL_STRIDE }>)
.with_avx::<Rgba32, Abgr32>(x86_64::avx_rgba32_abgr32)
.with_avx::<Abgr32, Rgba32>(x86_64::avx_rgba32_abgr32)
}
}
fn copy_same_fmt<const WIDTH: usize>(
write_data: &mut dyn BitmapRawDataMut,
read_data: &dyn BitmapRawData,
params: &(PixelBox, PixelPoint),
) {
let read_box = params.0;
let write_box = PixelBox::from_origin_and_size(params.1, read_box.size());
let Some((read_box, write_box)) = clip_to(
PixelBox::from_size(read_data.size()),
PixelBox::from_size(write_data.size()),
read_box,
write_box,
) else {
return;
};
let write_stride = write_data.stride();
let write_data = write_data.data_mut();
let read_stride = read_data.stride();
let read_data = read_data.data();
let read_line_offset = read_box.min.x as usize * WIDTH;
let write_line_offset = write_box.min.x as usize * WIDTH;
let line_width = read_box.width() as usize * WIDTH;
for y in 0..read_box.height() {
let write_slice =
&mut write_data[(y + write_box.min.y) as usize * write_stride + write_line_offset..];
let read_slice =
&read_data[(y + read_box.min.y) as usize * read_stride + read_line_offset..];
(&mut write_slice[..line_width]).copy_from_slice(&read_slice[..line_width]);
}
}
impl GenericBinary<(PixelBox, PixelPoint)> for CopyFromOp {
fn perform<Format: PixelFormatSpec, ReadFormat: PixelFormatSpec>(
write_data: &mut dyn BitmapRawDataMut,
read_data: &dyn BitmapRawData,
params: &(PixelBox, PixelPoint),
) {
let read_box = params.0;
let write_box = PixelBox::from_origin_and_size(params.1, read_box.size());
let Some((read_box, write_box)) = clip_to(
PixelBox::from_size(read_data.size()),
PixelBox::from_size(write_data.size()),
read_box,
write_box,
) else {
return;
};
let write_stride = write_data.stride();
let write_data = write_data.data_mut();
let read_stride = read_data.stride();
let read_data = read_data.data();
for y in 0..read_box.height() {
let write_slice = &mut write_data[(y + write_box.min.y) as usize * write_stride..];
let read_slice = &read_data[(y + read_box.min.y) as usize * read_stride..];
for x in 0..read_box.width() {
let col = read_from_bytes::<ReadFormat>(
&read_slice[(x + read_box.min.x) as usize * ReadFormat::PIXEL_STRIDE..],
);
write_as_bytes::<Format>(
&col,
&mut write_slice[(x + write_box.min.x) as usize * Format::PIXEL_STRIDE..],
);
}
}
}
}