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::tile::Tile;
9use vello_common::util::Div255Ext;
10
11pub(crate) mod scalar {
12 #[inline(always)]
33 pub(crate) const fn div_255(val: u16) -> u16 {
34 debug_assert!(
35 val < 65280,
36 "the properties of `div_255` do not hold for values of `65280` or greater"
37 );
38 (val + 255) >> 8
39 }
40
41 #[cfg(test)]
42 mod tests {
43 use crate::util::scalar::div_255;
44
45 #[test]
46 fn div_255_properties() {
47 for i in 0_u16..256 * 255 {
48 let expected = i / 255;
49 let actual = div_255(i);
50
51 assert!(
52 expected <= actual,
53 "In case of a discrepancy, the division should yield a value higher than the original."
54 );
55
56 let diff = expected.abs_diff(actual);
57 assert!(diff <= 1, "Rounding error shouldn't be higher than 1.");
58
59 if i % 255 == 0 {
60 assert_eq!(diff, 0, "Division should be accurate for multiples of 255.");
61 }
62 }
63 }
64 }
65}
66
67pub(crate) trait NormalizedMulExt {
68 fn normalized_mul(self, other: Self) -> Self;
69}
70
71impl<S: Simd> NormalizedMulExt for u8x32<S> {
72 #[inline(always)]
73 fn normalized_mul(self, other: Self) -> Self {
74 let divided = (self.simd.widen_u8x32(self) * other.simd.widen_u8x32(other)).div_255();
75 self.simd.narrow_u16x32(divided)
76 }
77}
78
79pub(crate) trait EncodedImageExt {
80 fn has_skew(&self) -> bool;
81 fn nearest_neighbor(&self) -> bool;
82}
83
84impl EncodedImageExt for EncodedImage {
85 fn has_skew(&self) -> bool {
86 !(self.x_advance.y as f32).is_nearly_zero() || !(self.y_advance.x as f32).is_nearly_zero()
87 }
88
89 fn nearest_neighbor(&self) -> bool {
90 self.sampler.quality == ImageQuality::Low
91 }
92}
93
94pub(crate) trait Premultiply {
95 fn premultiply(self, alphas: Self) -> Self;
96 fn unpremultiply(self, alphas: Self) -> Self;
97}
98
99impl<S: Simd> Premultiply for f32x4<S> {
100 #[inline(always)]
101 fn premultiply(self, alphas: Self) -> Self {
102 self * alphas
103 }
104
105 #[inline(always)]
106 fn unpremultiply(self, alphas: Self) -> Self {
107 let zero = Self::splat(alphas.simd, 0.0);
108 let divided = self / alphas;
109
110 self.simd
111 .select_f32x4(self.simd.simd_eq_f32x4(alphas, zero), zero, divided)
112 }
113}
114
115#[derive(Debug, Clone, Copy, PartialEq, Eq)]
117#[doc(hidden)]
118pub struct Span {
119 x: u16,
121 width: u16,
123}
124
125impl Span {
126 pub fn new(x: u16, width: u16) -> Self {
128 Self { x, width }
129 }
130
131 pub fn new_tile(tile_x: u16, tile_width: u16) -> Self {
133 Self {
134 x: tile_x * Tile::WIDTH,
135 width: tile_width * Tile::WIDTH,
136 }
137 }
138
139 pub fn tile_x(self) -> u16 {
141 self.x / Tile::WIDTH
142 }
143
144 pub fn tile_end(self) -> u16 {
146 self.pixel_end().div_ceil(Tile::WIDTH)
147 }
148
149 pub fn extend(&mut self, other: Self) {
151 let x = self.x.min(other.x);
152 let end = self.pixel_end().max(other.pixel_end());
153 *self = Self::new(x, end.saturating_sub(x));
154 }
155
156 pub fn intersect(self, other: Self) -> Option<Self> {
158 let x = self.x.max(other.x);
159 let end = self.pixel_end().min(other.pixel_end());
160 (x < end).then(|| Self::new(x, end - x))
161 }
162
163 pub fn pixel_x(self) -> u16 {
165 self.x
166 }
167
168 pub fn pixel_width(self) -> u16 {
170 self.width
171 }
172
173 pub fn pixel_end(self) -> u16 {
175 self.pixel_x().saturating_add(self.pixel_width())
176 }
177}