use crate::{
colour::BlendMode,
formats::Rgba32,
math::*,
op::{avx::*, binary_map_pixel_data_with, common_x86_64::*},
prelude::*,
};
pub fn avx_rgba32_rgba32(
write_data: &mut dyn BitmapRawDataMut,
read_data: &dyn BitmapRawData,
params: &(PixelBox, PixelPoint, BlendMode),
) {
match params.2 {
BlendMode::SourceCopy => binary_map_pixel_data_with::<0, Rgba32, Rgba32>(
write_data,
read_data,
params.0.size(),
params.1,
params.0.min,
<[u8]>::copy_from_slice,
),
BlendMode::Simple => binary_map_pixel_data_with::<2, Rgba32, Rgba32>(
write_data,
read_data,
params.0.size(),
params.1,
params.0.min,
|w, r| unsafe {
(rgba32_rgba32_simple)(
&mut *(w.as_mut_ptr() as *mut [u8; 8]),
&*(r.as_ptr() as *const [u8; 8]),
)
},
),
BlendMode::SourceAlpha => binary_map_pixel_data_with::<4, Rgba32, Rgba32>(
write_data,
read_data,
params.0.size(),
params.1,
params.0.min,
|w, r| unsafe {
(rgba32_rgba32_source)(
&mut *(w.as_mut_ptr() as *mut [u8; 16]),
&*(r.as_ptr() as *const [u8; 16]),
)
},
),
BlendMode::BackdropAlpha => binary_map_pixel_data_with::<4, Rgba32, Rgba32>(
write_data,
read_data,
params.0.size(),
params.1,
params.0.min,
|w, r| unsafe {
(rgba32_rgba32_backdrop)(
&mut *(w.as_mut_ptr() as *mut [u8; 16]),
&*(r.as_ptr() as *const [u8; 16]),
)
},
),
BlendMode::Multiply => binary_map_pixel_data_with::<4, Rgba32, Rgba32>(
write_data,
read_data,
params.0.size(),
params.1,
params.0.min,
|w, r| unsafe {
(rgba32_rgba32_multiply)(
&mut *(w.as_mut_ptr() as *mut [u8; 16]),
&*(r.as_ptr() as *const [u8; 16]),
)
},
),
}
}
#[inline]
#[target_feature(enable = "fma")]
#[target_feature(enable = "avx2")]
fn rgba32_rgba32_simple(e: &mut [u8; 8], s: &[u8; 8]) {
let bvec = Rf32x8::load8_and_expand(e);
let svec = Rf32x8::load8_and_expand(s);
rgba_simple_blend!(bvec, svec).shrink_and_store8(e)
}
#[inline]
#[target_feature(enable = "avx2")]
fn rgba32_rgba32_source(e: &mut [u8; 16], s: &[u8; 16]) {
let bvec = Ri16x16::load8_and_expand(e);
let svec = Ri16x16::load8_and_expand(s);
rgba_source_blend!(bvec, svec).shrink_and_store8(e);
}
#[inline]
#[target_feature(enable = "avx2")]
fn rgba32_rgba32_backdrop(e: &mut [u8; 16], s: &[u8; 16]) {
let bvec = Ri16x16::load8_and_expand(e);
let svec = Ri16x16::load8_and_expand(s);
rgba_backdrop_blend!(bvec, svec).shrink_and_store8(e);
}
#[inline]
#[target_feature(enable = "avx2")]
fn rgba32_rgba32_multiply(e: &mut [u8; 16], s: &[u8; 16]) {
let bvec = Ri16x16::load8_and_expand(e);
let svec = Ri16x16::load8_and_expand(s);
rgba_multiply_blend!(bvec, svec).shrink_and_store8(e);
}
#[cfg(test)]
mod test {
use super::{
rgba32_rgba32_backdrop, rgba32_rgba32_multiply, rgba32_rgba32_simple, rgba32_rgba32_source,
};
use crate::colour::{test::*, Colour};
use crate::palette::css;
use rstest::rstest;
use rstest_reuse::apply;
fn col_to_arr_int(col: Colour) -> [u8; 16] {
unsafe { std::mem::transmute([[col.r, col.g, col.b, col.a]; 4]) }
}
fn col_to_arr_fp(col: Colour) -> [u8; 8] {
unsafe { std::mem::transmute([[col.r, col.g, col.b, col.a]; 2]) }
}
fn arr_to_col(data: &[u8]) -> Colour {
Colour::new(data[0], data[1], data[2], data[3])
}
#[apply(blend_template)]
fn simple_blend_mode_fp(tc: BlendTestCase) {
if !std::arch::is_x86_feature_detected!("avx2") {
println!("no avx2 detected, skipping test");
return;
}
println!("blending case: {}", tc.desc);
let r = tc
.simple_result
.expect("there is no expected simple result for this case");
println!("blending {:?} and {:?}", tc.source, tc.backdrop);
println!("expecting {r:?}");
let mut backdrop = col_to_arr_fp(tc.backdrop);
let source = col_to_arr_fp(tc.source);
unsafe { rgba32_rgba32_simple(&mut backdrop, &source) }
assert_eq!(r, arr_to_col(&backdrop))
}
#[apply(blend_template)]
fn source_alpha_blend_mode_int(tc: BlendTestCase) {
if !std::arch::is_x86_feature_detected!("avx2") {
println!("no avx2 detected, skipping test");
return;
}
println!("blending case: {}", tc.desc);
let r = tc
.source_result
.expect("there is no expected source result for this case");
println!("blending {:?} and {:?}", tc.source, tc.backdrop);
println!("expecting {r:?}");
let mut backdrop = col_to_arr_int(tc.backdrop);
let source = col_to_arr_int(tc.source);
unsafe { rgba32_rgba32_source(&mut backdrop, &source) }
assert_eq!(r, arr_to_col(&backdrop))
}
#[apply(blend_template)]
fn backdrop_alpha_blend_mode_int(tc: BlendTestCase) {
if !std::arch::is_x86_feature_detected!("avx2") {
println!("no avx2 detected, skipping test");
return;
}
println!("blending case: {}", tc.desc);
let r = tc
.backdrop_result
.expect("there is no expected backdrop result for this case");
println!("blending {:?} and {:?}", tc.source, tc.backdrop);
println!("expecting {r:?}");
let mut backdrop = col_to_arr_int(tc.backdrop);
let source = col_to_arr_int(tc.source);
unsafe { rgba32_rgba32_backdrop(&mut backdrop, &source) }
assert_eq!(r, arr_to_col(&backdrop))
}
#[apply(blend_template)]
fn multiply_blend_mode_int(tc: BlendTestCase) {
if !std::arch::is_x86_feature_detected!("avx2") {
println!("no avx2 detected, skipping test");
return;
}
println!("blending case: {}", tc.desc);
let r = tc
.multiply_result
.expect("there is no expected multiply result for this case");
println!("blending {:?} and {:?}", tc.source, tc.backdrop);
println!("expecting {r:?}");
let mut backdrop = col_to_arr_int(tc.backdrop);
let source = col_to_arr_int(tc.source);
unsafe { rgba32_rgba32_multiply(&mut backdrop, &source) }
assert_eq!(r, arr_to_col(&backdrop))
}
}