1 // Copyright 2011 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 // Spatial prediction using various filters
11 //
12 // Author: Urvang (urvang@google.com)
13 
14 #include "src/dsp/dsp.h"
15 #include <assert.h>
16 #include <stdlib.h>
17 #include <string.h>
18 
19 //------------------------------------------------------------------------------
20 // Helpful macro.
21 
22 # define SANITY_CHECK(in, out)                                                 \
23   assert((in) != NULL);                                                        \
24   assert((out) != NULL);                                                       \
25   assert(width > 0);                                                           \
26   assert(height > 0);                                                          \
27   assert(stride >= width);                                                     \
28   assert(row >= 0 && num_rows > 0 && row + num_rows <= height);                \
29   (void)height;  // Silence unused warning.
30 
31 #if !WEBP_NEON_OMIT_C_CODE
PredictLine_C(const uint8_t * src,const uint8_t * pred,uint8_t * dst,int length,int inverse)32 static WEBP_INLINE void PredictLine_C(const uint8_t* src, const uint8_t* pred,
33                                       uint8_t* dst, int length, int inverse) {
34   int i;
35   if (inverse) {
36     for (i = 0; i < length; ++i) dst[i] = (uint8_t)(src[i] + pred[i]);
37   } else {
38     for (i = 0; i < length; ++i) dst[i] = (uint8_t)(src[i] - pred[i]);
39   }
40 }
41 
42 //------------------------------------------------------------------------------
43 // Horizontal filter.
44 
DoHorizontalFilter_C(const uint8_t * in,int width,int height,int stride,int row,int num_rows,int inverse,uint8_t * out)45 static WEBP_INLINE void DoHorizontalFilter_C(const uint8_t* in,
46                                              int width, int height, int stride,
47                                              int row, int num_rows,
48                                              int inverse, uint8_t* out) {
49   const uint8_t* preds;
50   const size_t start_offset = row * stride;
51   const int last_row = row + num_rows;
52   SANITY_CHECK(in, out);
53   in += start_offset;
54   out += start_offset;
55   preds = inverse ? out : in;
56 
57   if (row == 0) {
58     // Leftmost pixel is the same as input for topmost scanline.
59     out[0] = in[0];
60     PredictLine_C(in + 1, preds, out + 1, width - 1, inverse);
61     row = 1;
62     preds += stride;
63     in += stride;
64     out += stride;
65   }
66 
67   // Filter line-by-line.
68   while (row < last_row) {
69     // Leftmost pixel is predicted from above.
70     PredictLine_C(in, preds - stride, out, 1, inverse);
71     PredictLine_C(in + 1, preds, out + 1, width - 1, inverse);
72     ++row;
73     preds += stride;
74     in += stride;
75     out += stride;
76   }
77 }
78 
79 //------------------------------------------------------------------------------
80 // Vertical filter.
81 
DoVerticalFilter_C(const uint8_t * in,int width,int height,int stride,int row,int num_rows,int inverse,uint8_t * out)82 static WEBP_INLINE void DoVerticalFilter_C(const uint8_t* in,
83                                            int width, int height, int stride,
84                                            int row, int num_rows,
85                                            int inverse, uint8_t* out) {
86   const uint8_t* preds;
87   const size_t start_offset = row * stride;
88   const int last_row = row + num_rows;
89   SANITY_CHECK(in, out);
90   in += start_offset;
91   out += start_offset;
92   preds = inverse ? out : in;
93 
94   if (row == 0) {
95     // Very first top-left pixel is copied.
96     out[0] = in[0];
97     // Rest of top scan-line is left-predicted.
98     PredictLine_C(in + 1, preds, out + 1, width - 1, inverse);
99     row = 1;
100     in += stride;
101     out += stride;
102   } else {
103     // We are starting from in-between. Make sure 'preds' points to prev row.
104     preds -= stride;
105   }
106 
107   // Filter line-by-line.
108   while (row < last_row) {
109     PredictLine_C(in, preds, out, width, inverse);
110     ++row;
111     preds += stride;
112     in += stride;
113     out += stride;
114   }
115 }
116 #endif  // !WEBP_NEON_OMIT_C_CODE
117 
118 //------------------------------------------------------------------------------
119 // Gradient filter.
120 
GradientPredictor_C(uint8_t a,uint8_t b,uint8_t c)121 static WEBP_INLINE int GradientPredictor_C(uint8_t a, uint8_t b, uint8_t c) {
122   const int g = a + b - c;
123   return ((g & ~0xff) == 0) ? g : (g < 0) ? 0 : 255;  // clip to 8bit
124 }
125 
126 #if !WEBP_NEON_OMIT_C_CODE
DoGradientFilter_C(const uint8_t * in,int width,int height,int stride,int row,int num_rows,int inverse,uint8_t * out)127 static WEBP_INLINE void DoGradientFilter_C(const uint8_t* in,
128                                            int width, int height, int stride,
129                                            int row, int num_rows,
130                                            int inverse, uint8_t* out) {
131   const uint8_t* preds;
132   const size_t start_offset = row * stride;
133   const int last_row = row + num_rows;
134   SANITY_CHECK(in, out);
135   in += start_offset;
136   out += start_offset;
137   preds = inverse ? out : in;
138 
139   // left prediction for top scan-line
140   if (row == 0) {
141     out[0] = in[0];
142     PredictLine_C(in + 1, preds, out + 1, width - 1, inverse);
143     row = 1;
144     preds += stride;
145     in += stride;
146     out += stride;
147   }
148 
149   // Filter line-by-line.
150   while (row < last_row) {
151     int w;
152     // leftmost pixel: predict from above.
153     PredictLine_C(in, preds - stride, out, 1, inverse);
154     for (w = 1; w < width; ++w) {
155       const int pred = GradientPredictor_C(preds[w - 1],
156                                            preds[w - stride],
157                                            preds[w - stride - 1]);
158       out[w] = (uint8_t)(in[w] + (inverse ? pred : -pred));
159     }
160     ++row;
161     preds += stride;
162     in += stride;
163     out += stride;
164   }
165 }
166 #endif  // !WEBP_NEON_OMIT_C_CODE
167 
168 #undef SANITY_CHECK
169 
170 //------------------------------------------------------------------------------
171 
172 #if !WEBP_NEON_OMIT_C_CODE
HorizontalFilter_C(const uint8_t * data,int width,int height,int stride,uint8_t * filtered_data)173 static void HorizontalFilter_C(const uint8_t* data, int width, int height,
174                                int stride, uint8_t* filtered_data) {
175   DoHorizontalFilter_C(data, width, height, stride, 0, height, 0,
176                        filtered_data);
177 }
178 
VerticalFilter_C(const uint8_t * data,int width,int height,int stride,uint8_t * filtered_data)179 static void VerticalFilter_C(const uint8_t* data, int width, int height,
180                              int stride, uint8_t* filtered_data) {
181   DoVerticalFilter_C(data, width, height, stride, 0, height, 0, filtered_data);
182 }
183 
GradientFilter_C(const uint8_t * data,int width,int height,int stride,uint8_t * filtered_data)184 static void GradientFilter_C(const uint8_t* data, int width, int height,
185                              int stride, uint8_t* filtered_data) {
186   DoGradientFilter_C(data, width, height, stride, 0, height, 0, filtered_data);
187 }
188 #endif  // !WEBP_NEON_OMIT_C_CODE
189 
190 //------------------------------------------------------------------------------
191 
HorizontalUnfilter_C(const uint8_t * prev,const uint8_t * in,uint8_t * out,int width)192 static void HorizontalUnfilter_C(const uint8_t* prev, const uint8_t* in,
193                                  uint8_t* out, int width) {
194   uint8_t pred = (prev == NULL) ? 0 : prev[0];
195   int i;
196   for (i = 0; i < width; ++i) {
197     out[i] = (uint8_t)(pred + in[i]);
198     pred = out[i];
199   }
200 }
201 
202 #if !WEBP_NEON_OMIT_C_CODE
VerticalUnfilter_C(const uint8_t * prev,const uint8_t * in,uint8_t * out,int width)203 static void VerticalUnfilter_C(const uint8_t* prev, const uint8_t* in,
204                                uint8_t* out, int width) {
205   if (prev == NULL) {
206     HorizontalUnfilter_C(NULL, in, out, width);
207   } else {
208     int i;
209     for (i = 0; i < width; ++i) out[i] = (uint8_t)(prev[i] + in[i]);
210   }
211 }
212 #endif  // !WEBP_NEON_OMIT_C_CODE
213 
GradientUnfilter_C(const uint8_t * prev,const uint8_t * in,uint8_t * out,int width)214 static void GradientUnfilter_C(const uint8_t* prev, const uint8_t* in,
215                                uint8_t* out, int width) {
216   if (prev == NULL) {
217     HorizontalUnfilter_C(NULL, in, out, width);
218   } else {
219     uint8_t top = prev[0], top_left = top, left = top;
220     int i;
221     for (i = 0; i < width; ++i) {
222       top = prev[i];  // need to read this first, in case prev==out
223       left = (uint8_t)(in[i] + GradientPredictor_C(left, top, top_left));
224       top_left = top;
225       out[i] = left;
226     }
227   }
228 }
229 
230 //------------------------------------------------------------------------------
231 // Init function
232 
233 WebPFilterFunc WebPFilters[WEBP_FILTER_LAST];
234 WebPUnfilterFunc WebPUnfilters[WEBP_FILTER_LAST];
235 
236 extern void VP8FiltersInitMIPSdspR2(void);
237 extern void VP8FiltersInitMSA(void);
238 extern void VP8FiltersInitNEON(void);
239 extern void VP8FiltersInitSSE2(void);
240 
WEBP_DSP_INIT_FUNC(VP8FiltersInit)241 WEBP_DSP_INIT_FUNC(VP8FiltersInit) {
242   WebPUnfilters[WEBP_FILTER_NONE] = NULL;
243 #if !WEBP_NEON_OMIT_C_CODE
244   WebPUnfilters[WEBP_FILTER_HORIZONTAL] = HorizontalUnfilter_C;
245   WebPUnfilters[WEBP_FILTER_VERTICAL] = VerticalUnfilter_C;
246 #endif
247   WebPUnfilters[WEBP_FILTER_GRADIENT] = GradientUnfilter_C;
248 
249   WebPFilters[WEBP_FILTER_NONE] = NULL;
250 #if !WEBP_NEON_OMIT_C_CODE
251   WebPFilters[WEBP_FILTER_HORIZONTAL] = HorizontalFilter_C;
252   WebPFilters[WEBP_FILTER_VERTICAL] = VerticalFilter_C;
253   WebPFilters[WEBP_FILTER_GRADIENT] = GradientFilter_C;
254 #endif
255 
256   if (VP8GetCPUInfo != NULL) {
257 #if defined(WEBP_USE_SSE2)
258     if (VP8GetCPUInfo(kSSE2)) {
259       VP8FiltersInitSSE2();
260     }
261 #endif
262 #if defined(WEBP_USE_MIPS_DSP_R2)
263     if (VP8GetCPUInfo(kMIPSdspR2)) {
264       VP8FiltersInitMIPSdspR2();
265     }
266 #endif
267 #if defined(WEBP_USE_MSA)
268     if (VP8GetCPUInfo(kMSA)) {
269       VP8FiltersInitMSA();
270     }
271 #endif
272   }
273 
274 #if defined(WEBP_USE_NEON)
275   if (WEBP_NEON_OMIT_C_CODE ||
276       (VP8GetCPUInfo != NULL && VP8GetCPUInfo(kNEON))) {
277     VP8FiltersInitNEON();
278   }
279 #endif
280 
281   assert(WebPUnfilters[WEBP_FILTER_HORIZONTAL] != NULL);
282   assert(WebPUnfilters[WEBP_FILTER_VERTICAL] != NULL);
283   assert(WebPUnfilters[WEBP_FILTER_GRADIENT] != NULL);
284   assert(WebPFilters[WEBP_FILTER_HORIZONTAL] != NULL);
285   assert(WebPFilters[WEBP_FILTER_VERTICAL] != NULL);
286   assert(WebPFilters[WEBP_FILTER_GRADIENT] != NULL);
287 }
288