@@ -10,8 +10,7 @@ use crate::common::BytesPerPixel;
10
10
#[ cfg( feature = "unstable" ) ]
11
11
mod simd {
12
12
use std:: simd:: {
13
- i16x4, i16x8, u8x4, u8x8, LaneCount , Simd , SimdInt , SimdOrd , SimdPartialEq , SimdUint ,
14
- SupportedLaneCount ,
13
+ u8x4, u8x8, LaneCount , Simd , SimdInt , SimdOrd , SimdPartialEq , SimdUint , SupportedLaneCount ,
15
14
} ;
16
15
17
16
/// This is an equivalent of the `PaethPredictor` function from
@@ -54,6 +53,40 @@ mod simd {
54
53
. select ( a, smallest. simd_eq ( pb) . select ( b, c) )
55
54
}
56
55
56
+ /// Memory of previous pixels (as needed to unfilter `FilterType::Paeth`).
57
+ /// See also https://www.w3.org/TR/png/#filter-byte-positions
58
+ #[ derive( Default ) ]
59
+ struct PaethState < const N : usize >
60
+ where
61
+ LaneCount < N > : SupportedLaneCount ,
62
+ {
63
+ /// Previous pixel in the previous row.
64
+ c : Simd < i16 , N > ,
65
+
66
+ /// Previous pixel in the current row.
67
+ a : Simd < i16 , N > ,
68
+ }
69
+
70
+ /// Mutates `x` as needed to unfilter `FilterType::Paeth`.
71
+ ///
72
+ /// `b` is the current pixel in the previous row. `x` is the current pixel in the current row.
73
+ /// See also https://www.w3.org/TR/png/#filter-byte-positions
74
+ fn paeth_step < const N : usize > ( state : & mut PaethState < N > , b : Simd < u8 , N > , x : & mut Simd < u8 , N > )
75
+ where
76
+ LaneCount < N > : SupportedLaneCount ,
77
+ {
78
+ // Storing the inputs.
79
+ let b = b. cast :: < i16 > ( ) ;
80
+
81
+ // Calculating the new value of the current pixel.
82
+ let predictor = paeth_predictor ( state. a , b, state. c ) ;
83
+ * x += predictor. cast :: < u8 > ( ) ;
84
+
85
+ // Preparing for the next step.
86
+ state. c = b;
87
+ state. a = x. cast :: < i16 > ( ) ;
88
+ }
89
+
57
90
fn load3 ( src : & [ u8 ] ) -> u8x4 {
58
91
u8x4:: from_array ( [ src[ 0 ] , src[ 1 ] , src[ 2 ] , 0 ] )
59
92
}
@@ -67,28 +100,12 @@ mod simd {
67
100
debug_assert_eq ! ( prev_row. len( ) , curr_row. len( ) ) ;
68
101
debug_assert_eq ! ( prev_row. len( ) % 3 , 0 ) ;
69
102
70
- // Paeth tries to predict pixel x using the pixel to the left of it, a,
71
- // and two pixels from the previous row, b and c:
72
- //
73
- // prev_row: c b
74
- // curr_row: a x
75
- //
76
- // The first pixel has no left context, and so uses an Up filter, p = b.
77
- // This works naturally with our main loop's p = a+b-c if we force a and c
78
- // to zero.
79
- let mut a = i16x4:: default ( ) ;
80
- let mut c = i16x4:: default ( ) ;
81
-
103
+ let mut state = PaethState :: < 4 > :: default ( ) ;
82
104
for ( prev, curr) in prev_row. chunks_exact ( 3 ) . zip ( curr_row. chunks_exact_mut ( 3 ) ) {
83
- let b = load3 ( prev) . cast :: < i16 > ( ) ;
105
+ let b = load3 ( prev) ;
84
106
let mut x = load3 ( curr) ;
85
-
86
- let predictor = paeth_predictor ( a, b, c) ;
87
- x += predictor. cast :: < u8 > ( ) ;
107
+ paeth_step ( & mut state, b, & mut x) ;
88
108
store3 ( x, curr) ;
89
-
90
- c = b;
91
- a = x. cast :: < i16 > ( ) ;
92
109
}
93
110
}
94
111
@@ -105,28 +122,12 @@ mod simd {
105
122
debug_assert_eq ! ( prev_row. len( ) , curr_row. len( ) ) ;
106
123
debug_assert_eq ! ( prev_row. len( ) % 6 , 0 ) ;
107
124
108
- // Paeth tries to predict pixel x using the pixel to the left of it, a,
109
- // and two pixels from the previous row, b and c:
110
- //
111
- // prev_row: c b
112
- // curr_row: a x
113
- //
114
- // The first pixel has no left context, and so uses an Up filter, p = b.
115
- // This works naturally with our main loop's p = a+b-c if we force a and c
116
- // to zero.
117
- let mut a = i16x8:: default ( ) ;
118
- let mut c = i16x8:: default ( ) ;
119
-
125
+ let mut state = PaethState :: < 8 > :: default ( ) ;
120
126
for ( prev, curr) in prev_row. chunks_exact ( 6 ) . zip ( curr_row. chunks_exact_mut ( 6 ) ) {
121
- let b = load6 ( prev) . cast :: < i16 > ( ) ;
127
+ let b = load6 ( prev) ;
122
128
let mut x = load6 ( curr) ;
123
-
124
- let predictor = paeth_predictor ( a, b, c) ;
125
- x += predictor. cast :: < u8 > ( ) ;
129
+ paeth_step ( & mut state, b, & mut x) ;
126
130
store6 ( x, curr) ;
127
-
128
- c = b;
129
- a = x. cast :: < i16 > ( ) ;
130
131
}
131
132
}
132
133
}
0 commit comments