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 SANITY_CHECK(in, out)  \
60   assert(in != NULL);          \
61   assert(out != NULL);         \
62   assert(width > 0);           \
63   assert(height > 0);          \
64   assert(stride >= width);
65 
66 //------------------------------------------------------------------------------
67 // Horrizontal filter
68 
HorizontalFilter_MSA(const uint8_t * data,int width,int height,int stride,uint8_t * filtered_data)69 static void HorizontalFilter_MSA(const uint8_t* data, int width, int height,
70                                  int stride, uint8_t* filtered_data) {
71   const uint8_t* preds = data;
72   const uint8_t* in = data;
73   uint8_t* out = filtered_data;
74   int row = 1;
75   SANITY_CHECK(in, out);
76 
77   // Leftmost pixel is the same as input for topmost scanline.
78   out[0] = in[0];
79   PredictLineInverse0(in + 1, preds, out + 1, width - 1);
80   preds += stride;
81   in += stride;
82   out += stride;
83   // Filter line-by-line.
84   while (row < height) {
85     // Leftmost pixel is predicted from above.
86     PredictLineInverse0(in, preds - stride, out, 1);
87     PredictLineInverse0(in + 1, preds, out + 1, width - 1);
88     ++row;
89     preds += stride;
90     in += stride;
91     out += stride;
92   }
93 }
94 
95 //------------------------------------------------------------------------------
96 // Gradient filter
97 
PredictLineGradient(const uint8_t * pinput,const uint8_t * ppred,uint8_t * poutput,int stride,int size)98 static WEBP_INLINE void PredictLineGradient(const uint8_t* pinput,
99                                             const uint8_t* ppred,
100                                             uint8_t* poutput, int stride,
101                                             int size) {
102   int w;
103   const v16i8 zero = { 0 };
104   while (size >= 16) {
105     v16u8 pred0, dst0;
106     v8i16 a0, a1, b0, b1, c0, c1;
107     const v16u8 tmp0 = LD_UB(ppred - 1);
108     const v16u8 tmp1 = LD_UB(ppred - stride);
109     const v16u8 tmp2 = LD_UB(ppred - stride - 1);
110     const v16u8 src0 = LD_UB(pinput);
111     ILVRL_B2_SH(zero, tmp0, a0, a1);
112     ILVRL_B2_SH(zero, tmp1, b0, b1);
113     ILVRL_B2_SH(zero, tmp2, c0, c1);
114     ADD2(a0, b0, a1, b1, a0, a1);
115     SUB2(a0, c0, a1, c1, a0, a1);
116     CLIP_SH2_0_255(a0, a1);
117     pred0 = (v16u8)__msa_pckev_b((v16i8)a1, (v16i8)a0);
118     dst0 = src0 - pred0;
119     ST_UB(dst0, poutput);
120     ppred += 16;
121     pinput += 16;
122     poutput += 16;
123     size -= 16;
124   }
125   for (w = 0; w < size; ++w) {
126     const int pred = ppred[w - 1] + ppred[w - stride] - ppred[w - stride - 1];
127     poutput[w] = pinput[w] - (pred < 0 ? 0 : pred > 255 ? 255 : pred);
128   }
129 }
130 
131 
GradientFilter_MSA(const uint8_t * data,int width,int height,int stride,uint8_t * filtered_data)132 static void GradientFilter_MSA(const uint8_t* data, int width, int height,
133                                int stride, uint8_t* filtered_data) {
134   const uint8_t* in = data;
135   const uint8_t* preds = data;
136   uint8_t* out = filtered_data;
137   int row = 1;
138   SANITY_CHECK(in, out);
139 
140   // left prediction for top scan-line
141   out[0] = in[0];
142   PredictLineInverse0(in + 1, preds, out + 1, width - 1);
143   preds += stride;
144   in += stride;
145   out += stride;
146   // Filter line-by-line.
147   while (row < height) {
148     out[0] = in[0] - preds[- stride];
149     PredictLineGradient(preds + 1, in + 1, out + 1, stride, width - 1);
150     ++row;
151     preds += stride;
152     in += stride;
153     out += stride;
154   }
155 }
156 
157 //------------------------------------------------------------------------------
158 // Vertical filter
159 
VerticalFilter_MSA(const uint8_t * data,int width,int height,int stride,uint8_t * filtered_data)160 static void VerticalFilter_MSA(const uint8_t* data, int width, int height,
161                                int stride, uint8_t* filtered_data) {
162   const uint8_t* in = data;
163   const uint8_t* preds = data;
164   uint8_t* out = filtered_data;
165   int row = 1;
166   SANITY_CHECK(in, out);
167 
168   // Very first top-left pixel is copied.
169   out[0] = in[0];
170   // Rest of top scan-line is left-predicted.
171   PredictLineInverse0(in + 1, preds, out + 1, width - 1);
172   in += stride;
173   out += stride;
174 
175   // Filter line-by-line.
176   while (row < height) {
177     PredictLineInverse0(in, preds, out, width);
178     ++row;
179     preds += stride;
180     in += stride;
181     out += stride;
182   }
183 }
184 
185 #undef SANITY_CHECK
186 
187 //------------------------------------------------------------------------------
188 // Entry point
189 
190 extern void VP8FiltersInitMSA(void);
191 
VP8FiltersInitMSA(void)192 WEBP_TSAN_IGNORE_FUNCTION void VP8FiltersInitMSA(void) {
193   WebPFilters[WEBP_FILTER_HORIZONTAL] = HorizontalFilter_MSA;
194   WebPFilters[WEBP_FILTER_VERTICAL] = VerticalFilter_MSA;
195   WebPFilters[WEBP_FILTER_GRADIENT] = GradientFilter_MSA;
196 }
197 
198 #else  // !WEBP_USE_MSA
199 
200 WEBP_DSP_INIT_STUB(VP8FiltersInitMSA)
201 
202 #endif  // WEBP_USE_MSA
203