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