1use crate::peniko::ImageQuality;
5use vello_common::encode::EncodedImage;
6use vello_common::fearless_simd::{Simd, SimdBase, f32x4, u8x32};
7use vello_common::math::FloatExt;
8use vello_common::util::Div255Ext;
9
10pub(crate) mod scalar {
11 #[inline(always)]
32 pub(crate) const fn div_255(val: u16) -> u16 {
33 debug_assert!(
34 val < 65280,
35 "the properties of `div_255` do not hold for values of `65280` or greater"
36 );
37 (val + 255) >> 8
38 }
39
40 #[cfg(test)]
41 mod tests {
42 use crate::util::scalar::div_255;
43
44 #[test]
45 fn div_255_properties() {
46 for i in 0_u16..256 * 255 {
47 let expected = i / 255;
48 let actual = div_255(i);
49
50 assert!(
51 expected <= actual,
52 "In case of a discrepancy, the division should yield a value higher than the original."
53 );
54
55 let diff = expected.abs_diff(actual);
56 assert!(diff <= 1, "Rounding error shouldn't be higher than 1.");
57
58 if i % 255 == 0 {
59 assert_eq!(diff, 0, "Division should be accurate for multiples of 255.");
60 }
61 }
62 }
63 }
64}
65
66pub(crate) trait NormalizedMulExt {
67 fn normalized_mul(self, other: Self) -> Self;
68}
69
70impl<S: Simd> NormalizedMulExt for u8x32<S> {
71 #[inline(always)]
72 fn normalized_mul(self, other: Self) -> Self {
73 let divided = (self.simd.widen_u8x32(self) * other.simd.widen_u8x32(other)).div_255();
74 self.simd.narrow_u16x32(divided)
75 }
76}
77
78pub(crate) trait EncodedImageExt {
79 fn has_skew(&self) -> bool;
80 fn nearest_neighbor(&self) -> bool;
81}
82
83impl EncodedImageExt for EncodedImage {
84 fn has_skew(&self) -> bool {
85 !(self.x_advance.y as f32).is_nearly_zero() || !(self.y_advance.x as f32).is_nearly_zero()
86 }
87
88 fn nearest_neighbor(&self) -> bool {
89 self.sampler.quality == ImageQuality::Low
90 }
91}
92
93pub(crate) trait Premultiply {
94 fn premultiply(self, alphas: Self) -> Self;
95 fn unpremultiply(self, alphas: Self) -> Self;
96}
97
98impl<S: Simd> Premultiply for f32x4<S> {
99 #[inline(always)]
100 fn premultiply(self, alphas: Self) -> Self {
101 self * alphas
102 }
103
104 #[inline(always)]
105 fn unpremultiply(self, alphas: Self) -> Self {
106 let zero = Self::splat(alphas.simd, 0.0);
107 let divided = self / alphas;
108
109 self.simd
110 .select_f32x4(self.simd.simd_eq_f32x4(alphas, zero), zero, divided)
111 }
112}