1 // Copyright 2016 Google Inc. All Rights Reserved.
2 //
3 // Use of this source code is governed by a BSD-style license
4 // that can be found in the COPYING file in the root of the source
5 // tree. An additional intellectual property rights grant can be found
6 // in the file PATENTS. All contributing project authors may
7 // be found in the AUTHORS file in the root of the source tree.
8 // -----------------------------------------------------------------------------
9 //
10 // MSA variant of alpha filters
11 //
12 // Author: Prashant Patil (prashant.patil@imgtec.com)
13
14 #include "src/dsp/dsp.h"
15
16 #if defined(WEBP_USE_MSA)
17
18 #include "src/dsp/msa_macro.h"
19
20 #include <assert.h>
21
PredictLineInverse0(const uint8_t * src,const uint8_t * pred,uint8_t * dst,int length)22 static WEBP_INLINE void PredictLineInverse0(const uint8_t* src,
23 const uint8_t* pred,
24 uint8_t* dst, int length) {
25 v16u8 src0, pred0, dst0;
26 assert(length >= 0);
27 while (length >= 32) {
28 v16u8 src1, pred1, dst1;
29 LD_UB2(src, 16, src0, src1);
30 LD_UB2(pred, 16, pred0, pred1);
31 SUB2(src0, pred0, src1, pred1, dst0, dst1);
32 ST_UB2(dst0, dst1, dst, 16);
33 src += 32;
34 pred += 32;
35 dst += 32;
36 length -= 32;
37 }
38 if (length > 0) {
39 int i;
40 if (length >= 16) {
41 src0 = LD_UB(src);
42 pred0 = LD_UB(pred);
43 dst0 = src0 - pred0;
44 ST_UB(dst0, dst);
45 src += 16;
46 pred += 16;
47 dst += 16;
48 length -= 16;
49 }
50 for (i = 0; i < length; i++) {
51 dst[i] = src[i] - pred[i];
52 }
53 }
54 }
55
56 //------------------------------------------------------------------------------
57 // Helpful macro.
58
59 #define DCHECK(in, out) \
60 do { \
61 assert(in != NULL); \
62 assert(out != NULL); \
63 assert(width > 0); \
64 assert(height > 0); \
65 assert(stride >= width); \
66 } while (0)
67
68 //------------------------------------------------------------------------------
69 // Horrizontal filter
70
HorizontalFilter_MSA(const uint8_t * data,int width,int height,int stride,uint8_t * filtered_data)71 static void HorizontalFilter_MSA(const uint8_t* data, int width, int height,
72 int stride, uint8_t* filtered_data) {
73 const uint8_t* preds = data;
74 const uint8_t* in = data;
75 uint8_t* out = filtered_data;
76 int row = 1;
77 DCHECK(in, out);
78
79 // Leftmost pixel is the same as input for topmost scanline.
80 out[0] = in[0];
81 PredictLineInverse0(in + 1, preds, out + 1, width - 1);
82 preds += stride;
83 in += stride;
84 out += stride;
85 // Filter line-by-line.
86 while (row < height) {
87 // Leftmost pixel is predicted from above.
88 PredictLineInverse0(in, preds - stride, out, 1);
89 PredictLineInverse0(in + 1, preds, out + 1, width - 1);
90 ++row;
91 preds += stride;
92 in += stride;
93 out += stride;
94 }
95 }
96
97 //------------------------------------------------------------------------------
98 // Gradient filter
99
PredictLineGradient(const uint8_t * pinput,const uint8_t * ppred,uint8_t * poutput,int stride,int size)100 static WEBP_INLINE void PredictLineGradient(const uint8_t* pinput,
101 const uint8_t* ppred,
102 uint8_t* poutput, int stride,
103 int size) {
104 int w;
105 const v16i8 zero = { 0 };
106 while (size >= 16) {
107 v16u8 pred0, dst0;
108 v8i16 a0, a1, b0, b1, c0, c1;
109 const v16u8 tmp0 = LD_UB(ppred - 1);
110 const v16u8 tmp1 = LD_UB(ppred - stride);
111 const v16u8 tmp2 = LD_UB(ppred - stride - 1);
112 const v16u8 src0 = LD_UB(pinput);
113 ILVRL_B2_SH(zero, tmp0, a0, a1);
114 ILVRL_B2_SH(zero, tmp1, b0, b1);
115 ILVRL_B2_SH(zero, tmp2, c0, c1);
116 ADD2(a0, b0, a1, b1, a0, a1);
117 SUB2(a0, c0, a1, c1, a0, a1);
118 CLIP_SH2_0_255(a0, a1);
119 pred0 = (v16u8)__msa_pckev_b((v16i8)a1, (v16i8)a0);
120 dst0 = src0 - pred0;
121 ST_UB(dst0, poutput);
122 ppred += 16;
123 pinput += 16;
124 poutput += 16;
125 size -= 16;
126 }
127 for (w = 0; w < size; ++w) {
128 const int pred = ppred[w - 1] + ppred[w - stride] - ppred[w - stride - 1];
129 poutput[w] = pinput[w] - (pred < 0 ? 0 : pred > 255 ? 255 : pred);
130 }
131 }
132
133
GradientFilter_MSA(const uint8_t * data,int width,int height,int stride,uint8_t * filtered_data)134 static void GradientFilter_MSA(const uint8_t* data, int width, int height,
135 int stride, uint8_t* filtered_data) {
136 const uint8_t* in = data;
137 const uint8_t* preds = data;
138 uint8_t* out = filtered_data;
139 int row = 1;
140 DCHECK(in, out);
141
142 // left prediction for top scan-line
143 out[0] = in[0];
144 PredictLineInverse0(in + 1, preds, out + 1, width - 1);
145 preds += stride;
146 in += stride;
147 out += stride;
148 // Filter line-by-line.
149 while (row < height) {
150 out[0] = in[0] - preds[- stride];
151 PredictLineGradient(preds + 1, in + 1, out + 1, stride, width - 1);
152 ++row;
153 preds += stride;
154 in += stride;
155 out += stride;
156 }
157 }
158
159 //------------------------------------------------------------------------------
160 // Vertical filter
161
VerticalFilter_MSA(const uint8_t * data,int width,int height,int stride,uint8_t * filtered_data)162 static void VerticalFilter_MSA(const uint8_t* data, int width, int height,
163 int stride, uint8_t* filtered_data) {
164 const uint8_t* in = data;
165 const uint8_t* preds = data;
166 uint8_t* out = filtered_data;
167 int row = 1;
168 DCHECK(in, out);
169
170 // Very first top-left pixel is copied.
171 out[0] = in[0];
172 // Rest of top scan-line is left-predicted.
173 PredictLineInverse0(in + 1, preds, out + 1, width - 1);
174 in += stride;
175 out += stride;
176
177 // Filter line-by-line.
178 while (row < height) {
179 PredictLineInverse0(in, preds, out, width);
180 ++row;
181 preds += stride;
182 in += stride;
183 out += stride;
184 }
185 }
186
187 #undef DCHECK
188
189 //------------------------------------------------------------------------------
190 // Entry point
191
192 extern void VP8FiltersInitMSA(void);
193
VP8FiltersInitMSA(void)194 WEBP_TSAN_IGNORE_FUNCTION void VP8FiltersInitMSA(void) {
195 WebPFilters[WEBP_FILTER_HORIZONTAL] = HorizontalFilter_MSA;
196 WebPFilters[WEBP_FILTER_VERTICAL] = VerticalFilter_MSA;
197 WebPFilters[WEBP_FILTER_GRADIENT] = GradientFilter_MSA;
198 }
199
200 #else // !WEBP_USE_MSA
201
202 WEBP_DSP_INIT_STUB(VP8FiltersInitMSA)
203
204 #endif // WEBP_USE_MSA
205