mirror of
https://github.com/bend-n/fimg.git
synced 2024-12-22 10:28:21 -06:00
improve safety of blit()
This commit is contained in:
parent
8649f3c2a2
commit
4082ca3dda
|
@ -58,7 +58,6 @@
|
||||||
iter_array_chunks,
|
iter_array_chunks,
|
||||||
core_intrinsics,
|
core_intrinsics,
|
||||||
slice_as_chunks,
|
slice_as_chunks,
|
||||||
slice_flatten,
|
|
||||||
rustc_private,
|
rustc_private,
|
||||||
portable_simd,
|
portable_simd,
|
||||||
array_windows,
|
array_windows,
|
||||||
|
|
|
@ -70,45 +70,36 @@ pub trait ClonerOverlay<const W: usize, const C: usize>: Sealed {
|
||||||
/// # Safety
|
/// # Safety
|
||||||
/// - UB if rgb.len() % 3 != 0
|
/// - UB if rgb.len() % 3 != 0
|
||||||
/// - UB if rgba.len() % 4 != 0
|
/// - UB if rgba.len() % 4 != 0
|
||||||
unsafe fn blit(rgb: &mut [u8], rgba: &[u8]) {
|
unsafe fn blit(mut rgb: &mut [u8], mut rgba: &[u8]) {
|
||||||
let mut srci = 0;
|
while rgb.len() >= 16 {
|
||||||
let mut dsti = 0;
|
let dst = rgb.first_chunk_mut::<16>().unwrap();
|
||||||
while dsti + 16 <= rgb.len() {
|
let src = rgba.first_chunk::<16>().unwrap();
|
||||||
// SAFETY: i think it ok
|
let old = Simd::from_slice(dst);
|
||||||
let old: Simd<u8, 16> = Simd::from_slice(unsafe { rgb.get_unchecked(dsti..dsti + 16) });
|
let new: u8x16 = Simd::from_slice(src);
|
||||||
// SAFETY: definitly ok
|
|
||||||
let new: Simd<u8, 16> = Simd::from_slice(unsafe { rgba.get_unchecked(srci..srci + 16) });
|
|
||||||
|
|
||||||
let threshold = new.simd_ge(Simd::splat(128)).to_int().cast::<u8>();
|
let threshold = new.simd_ge(Simd::splat(128)).to_int().cast::<u8>();
|
||||||
let mut mask = simd_swizzle!(
|
let mut mask = simd_swizzle!(
|
||||||
threshold,
|
threshold,
|
||||||
|
// [r, g, b, a (3)] [r, g, b, a(7)]
|
||||||
[3, 3, 3, 7, 7, 7, 11, 11, 11, 15, 15, 15, 0, 0, 0, 0]
|
[3, 3, 3, 7, 7, 7, 11, 11, 11, 15, 15, 15, 0, 0, 0, 0]
|
||||||
);
|
);
|
||||||
mask &= Simd::from_array([
|
mask &= Simd::from_array([
|
||||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0,
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0,
|
||||||
]);
|
]);
|
||||||
|
// [r(0), g, b] <skip a> [r(4), g, b]
|
||||||
let new_rgb = simd_swizzle!(new, [0, 1, 2, 4, 5, 6, 8, 9, 10, 12, 13, 14, 0, 0, 0, 0]);
|
let new_rgb = simd_swizzle!(new, [0, 1, 2, 4, 5, 6, 8, 9, 10, 12, 13, 14, 0, 0, 0, 0]);
|
||||||
let blended = (new_rgb & mask) | (old & !mask);
|
let blended = (new_rgb & mask) | (old & !mask);
|
||||||
// SAFETY: 4 * 4 == 16, so in bounds
|
blended.copy_to_slice(dst);
|
||||||
blended.copy_to_slice(unsafe { rgb.get_unchecked_mut(dsti..dsti + 16) });
|
rgb = &mut rgb[12..];
|
||||||
|
rgba = &rgba[16..];
|
||||||
srci += 16;
|
|
||||||
dsti += 12;
|
|
||||||
}
|
}
|
||||||
|
while rgb.len() >= 3 {
|
||||||
while dsti + 3 <= rgb.len() {
|
// SAFETY: guaranteed
|
||||||
// SAFETY: caller guarantees slice is big enough
|
if unsafe { *rgba.get_unchecked(3) } >= 128 {
|
||||||
if unsafe { *rgba.get_unchecked(srci + 3) } >= 128 {
|
rgb[..3].copy_from_slice(&rgba[..3]);
|
||||||
// SAFETY: slice is big enough!
|
|
||||||
let src = unsafe { rgba.get_unchecked(srci..=srci + 2) };
|
|
||||||
// SAFETY: i hear it bound
|
|
||||||
let end = unsafe { rgb.get_unchecked_mut(dsti..=dsti + 2) };
|
|
||||||
end.copy_from_slice(src);
|
|
||||||
}
|
}
|
||||||
|
rgba = &rgba[4..];
|
||||||
srci += 4;
|
rgb = &mut rgb[3..];
|
||||||
dsti += 3;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue