Merge "Detect toolchain based on gcc -dumpmachine"
[profile/ivi/libvpx.git] / vp8 / common / loopfilter_filters.c
1 /*
2  *  Copyright (c) 2010 The VP8 project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license 
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may 
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10
11
12 #include <stdlib.h>
13 #include "loopfilter.h"
14 #include "onyxc_int.h"
15
16
17 #define NEW_LOOPFILTER_MASK
18
19 typedef unsigned char uc;
20
21 __inline signed char vp8_signed_char_clamp(int t)
22 {
23     t = (t < -128 ? -128 : t);
24     t = (t > 127 ? 127 : t);
25     return (signed char) t;
26 }
27
28
29 // should we apply any filter at all ( 11111111 yes, 00000000 no)
30 __inline signed char vp8_filter_mask(signed char limit, signed char flimit,
31                                      uc p3, uc p2, uc p1, uc p0, uc q0, uc q1, uc q2, uc q3)
32 {
33     signed char mask = 0;
34     mask |= (abs(p3 - p2) > limit) * -1;
35     mask |= (abs(p2 - p1) > limit) * -1;
36     mask |= (abs(p1 - p0) > limit) * -1;
37     mask |= (abs(q1 - q0) > limit) * -1;
38     mask |= (abs(q2 - q1) > limit) * -1;
39     mask |= (abs(q3 - q2) > limit) * -1;
40 #ifndef NEW_LOOPFILTER_MASK
41     mask |= (abs(p0 - q0) > flimit) * -1;
42 #else
43     mask |= (abs(p0 - q0) * 2 + abs(p1 - q1) / 2  > flimit * 2 + limit) * -1;
44 #endif
45     mask = ~mask;
46     return mask;
47 }
48
49 // is there high variance internal edge ( 11111111 yes, 00000000 no)
50 __inline signed char vp8_hevmask(signed char thresh, uc p1, uc p0, uc q0, uc q1)
51 {
52     signed char hev = 0;
53     hev  |= (abs(p1 - p0) > thresh) * -1;
54     hev  |= (abs(q1 - q0) > thresh) * -1;
55     return hev;
56 }
57
58 __inline void vp8_filter(signed char mask, signed char hev, uc *op1, uc *op0, uc *oq0, uc *oq1)
59
60 {
61     signed char ps0, qs0;
62     signed char ps1, qs1;
63     signed char vp8_filter, Filter1, Filter2;
64     signed char u;
65
66     ps1 = (signed char) * op1 ^ 0x80;
67     ps0 = (signed char) * op0 ^ 0x80;
68     qs0 = (signed char) * oq0 ^ 0x80;
69     qs1 = (signed char) * oq1 ^ 0x80;
70
71     // add outer taps if we have high edge variance
72     vp8_filter = vp8_signed_char_clamp(ps1 - qs1);
73     vp8_filter &= hev;
74
75     // inner taps
76     vp8_filter = vp8_signed_char_clamp(vp8_filter + 3 * (qs0 - ps0));
77     vp8_filter &= mask;
78
79     // save bottom 3 bits so that we round one side +4 and the other +3
80     // if it equals 4 we'll set to adjust by -1 to account for the fact
81     // we'd round 3 the other way
82     Filter1 = vp8_signed_char_clamp(vp8_filter + 4);
83     Filter2 = vp8_signed_char_clamp(vp8_filter + 3);
84     Filter1 >>= 3;
85     Filter2 >>= 3;
86     u = vp8_signed_char_clamp(qs0 - Filter1);
87     *oq0 = u ^ 0x80;
88     u = vp8_signed_char_clamp(ps0 + Filter2);
89     *op0 = u ^ 0x80;
90     vp8_filter = Filter1;
91
92     // outer tap adjustments
93     vp8_filter += 1;
94     vp8_filter >>= 1;
95     vp8_filter &= ~hev;
96
97     u = vp8_signed_char_clamp(qs1 - vp8_filter);
98     *oq1 = u ^ 0x80;
99     u = vp8_signed_char_clamp(ps1 + vp8_filter);
100     *op1 = u ^ 0x80;
101
102 }
103 void vp8_loop_filter_horizontal_edge_c
104 (
105     unsigned char *s,
106     int p, //pitch
107     const signed char *flimit,
108     const signed char *limit,
109     const signed char *thresh,
110     int count
111 )
112 {
113     int  hev = 0; // high edge variance
114     signed char mask = 0;
115     int i = 0;
116
117     // loop filter designed to work using chars so that we can make maximum use
118     // of 8 bit simd instructions.
119     do
120     {
121         mask = vp8_filter_mask(limit[i], flimit[i],
122                                s[-4*p], s[-3*p], s[-2*p], s[-1*p],
123                                s[0*p], s[1*p], s[2*p], s[3*p]);
124
125         hev = vp8_hevmask(thresh[i], s[-2*p], s[-1*p], s[0*p], s[1*p]);
126
127         vp8_filter(mask, hev, s - 2 * p, s - 1 * p, s, s + 1 * p);
128
129         ++s;
130     }
131     while (++i < count * 8);
132 }
133
134 void vp8_loop_filter_vertical_edge_c
135 (
136     unsigned char *s,
137     int p,
138     const signed char *flimit,
139     const signed char *limit,
140     const signed char *thresh,
141     int count
142 )
143 {
144     int  hev = 0; // high edge variance
145     signed char mask = 0;
146     int i = 0;
147
148     // loop filter designed to work using chars so that we can make maximum use
149     // of 8 bit simd instructions.
150     do
151     {
152         mask = vp8_filter_mask(limit[i], flimit[i],
153                                s[-4], s[-3], s[-2], s[-1], s[0], s[1], s[2], s[3]);
154
155         hev = vp8_hevmask(thresh[i], s[-2], s[-1], s[0], s[1]);
156
157         vp8_filter(mask, hev, s - 2, s - 1, s, s + 1);
158
159         s += p;
160     }
161     while (++i < count * 8);
162 }
163
164 __inline void vp8_mbfilter(signed char mask, signed char hev,
165                            uc *op2, uc *op1, uc *op0, uc *oq0, uc *oq1, uc *oq2)
166 {
167     signed char s, u;
168     signed char vp8_filter, Filter1, Filter2;
169     signed char ps2 = (signed char) * op2 ^ 0x80;
170     signed char ps1 = (signed char) * op1 ^ 0x80;
171     signed char ps0 = (signed char) * op0 ^ 0x80;
172     signed char qs0 = (signed char) * oq0 ^ 0x80;
173     signed char qs1 = (signed char) * oq1 ^ 0x80;
174     signed char qs2 = (signed char) * oq2 ^ 0x80;
175
176     // add outer taps if we have high edge variance
177     vp8_filter = vp8_signed_char_clamp(ps1 - qs1);
178     vp8_filter = vp8_signed_char_clamp(vp8_filter + 3 * (qs0 - ps0));
179     vp8_filter &= mask;
180
181     Filter2 = vp8_filter;
182     Filter2 &= hev;
183
184     // save bottom 3 bits so that we round one side +4 and the other +3
185     Filter1 = vp8_signed_char_clamp(Filter2 + 4);
186     Filter2 = vp8_signed_char_clamp(Filter2 + 3);
187     Filter1 >>= 3;
188     Filter2 >>= 3;
189     qs0 = vp8_signed_char_clamp(qs0 - Filter1);
190     ps0 = vp8_signed_char_clamp(ps0 + Filter2);
191
192
193     // only apply wider filter if not high edge variance
194     vp8_filter &= ~hev;
195     Filter2 = vp8_filter;
196
197     // roughly 3/7th difference across boundary
198     u = vp8_signed_char_clamp((63 + Filter2 * 27) >> 7);
199     s = vp8_signed_char_clamp(qs0 - u);
200     *oq0 = s ^ 0x80;
201     s = vp8_signed_char_clamp(ps0 + u);
202     *op0 = s ^ 0x80;
203
204     // roughly 2/7th difference across boundary
205     u = vp8_signed_char_clamp((63 + Filter2 * 18) >> 7);
206     s = vp8_signed_char_clamp(qs1 - u);
207     *oq1 = s ^ 0x80;
208     s = vp8_signed_char_clamp(ps1 + u);
209     *op1 = s ^ 0x80;
210
211     // roughly 1/7th difference across boundary
212     u = vp8_signed_char_clamp((63 + Filter2 * 9) >> 7);
213     s = vp8_signed_char_clamp(qs2 - u);
214     *oq2 = s ^ 0x80;
215     s = vp8_signed_char_clamp(ps2 + u);
216     *op2 = s ^ 0x80;
217 }
218
219 void vp8_mbloop_filter_horizontal_edge_c
220 (
221     unsigned char *s,
222     int p,
223     const signed char *flimit,
224     const signed char *limit,
225     const signed char *thresh,
226     int count
227 )
228 {
229     signed char hev = 0; // high edge variance
230     signed char mask = 0;
231     int i = 0;
232
233     // loop filter designed to work using chars so that we can make maximum use
234     // of 8 bit simd instructions.
235     do
236     {
237
238         mask = vp8_filter_mask(limit[i], flimit[i],
239                                s[-4*p], s[-3*p], s[-2*p], s[-1*p],
240                                s[0*p], s[1*p], s[2*p], s[3*p]);
241
242         hev = vp8_hevmask(thresh[i], s[-2*p], s[-1*p], s[0*p], s[1*p]);
243
244         vp8_mbfilter(mask, hev, s - 3 * p, s - 2 * p, s - 1 * p, s, s + 1 * p, s + 2 * p);
245
246         ++s;
247     }
248     while (++i < count * 8);
249
250 }
251
252
253 void vp8_mbloop_filter_vertical_edge_c
254 (
255     unsigned char *s,
256     int p,
257     const signed char *flimit,
258     const signed char *limit,
259     const signed char *thresh,
260     int count
261 )
262 {
263     signed char hev = 0; // high edge variance
264     signed char mask = 0;
265     int i = 0;
266
267     do
268     {
269
270         mask = vp8_filter_mask(limit[i], flimit[i],
271                                s[-4], s[-3], s[-2], s[-1], s[0], s[1], s[2], s[3]);
272
273         hev = vp8_hevmask(thresh[i], s[-2], s[-1], s[0], s[1]);
274
275         vp8_mbfilter(mask, hev, s - 3, s - 2, s - 1, s, s + 1, s + 2);
276
277         s += p;
278     }
279     while (++i < count * 8);
280
281 }
282
283 // should we apply any filter at all ( 11111111 yes, 00000000 no)
284 __inline signed char vp8_simple_filter_mask(signed char limit, signed char flimit, uc p1, uc p0, uc q0, uc q1)
285 {
286 // Why does this cause problems for win32?
287 // error C2143: syntax error : missing ';' before 'type'
288 //  (void) limit;
289 #ifndef NEW_LOOPFILTER_MASK
290     signed char mask = (abs(p0 - q0) <= flimit) * -1;
291 #else
292     signed char mask = (abs(p0 - q0) * 2 + abs(p1 - q1) / 2  <= flimit * 2 + limit) * -1;
293 #endif
294     return mask;
295 }
296
297 __inline void vp8_simple_filter(signed char mask, uc *op1, uc *op0, uc *oq0, uc *oq1)
298 {
299     signed char vp8_filter, Filter1, Filter2;
300     signed char p1 = (signed char) * op1 ^ 0x80;
301     signed char p0 = (signed char) * op0 ^ 0x80;
302     signed char q0 = (signed char) * oq0 ^ 0x80;
303     signed char q1 = (signed char) * oq1 ^ 0x80;
304     signed char u;
305
306     vp8_filter = vp8_signed_char_clamp(p1 - q1);
307     vp8_filter = vp8_signed_char_clamp(vp8_filter + 3 * (q0 - p0));
308     vp8_filter &= mask;
309
310     // save bottom 3 bits so that we round one side +4 and the other +3
311     Filter1 = vp8_signed_char_clamp(vp8_filter + 4);
312     Filter1 >>= 3;
313     u = vp8_signed_char_clamp(q0 - Filter1);
314     *oq0  = u ^ 0x80;
315
316     Filter2 = vp8_signed_char_clamp(vp8_filter + 3);
317     Filter2 >>= 3;
318     u = vp8_signed_char_clamp(p0 + Filter2);
319     *op0 = u ^ 0x80;
320 }
321
322 void vp8_loop_filter_simple_horizontal_edge_c
323 (
324     unsigned char *s,
325     int p,
326     const signed char *flimit,
327     const signed char *limit,
328     const signed char *thresh,
329     int count
330 )
331 {
332     signed char mask = 0;
333     int i = 0;
334     (void) thresh;
335
336     do
337     {
338         //mask = vp8_simple_filter_mask( limit[i], flimit[i],s[-1*p],s[0*p]);
339         mask = vp8_simple_filter_mask(limit[i], flimit[i], s[-2*p], s[-1*p], s[0*p], s[1*p]);
340         vp8_simple_filter(mask, s - 2 * p, s - 1 * p, s, s + 1 * p);
341         ++s;
342     }
343     while (++i < count * 8);
344 }
345
346 void vp8_loop_filter_simple_vertical_edge_c
347 (
348     unsigned char *s,
349     int p,
350     const signed char *flimit,
351     const signed char *limit,
352     const signed char *thresh,
353     int count
354 )
355 {
356     signed char mask = 0;
357     int i = 0;
358     (void) thresh;
359
360     do
361     {
362         //mask = vp8_simple_filter_mask( limit[i], flimit[i],s[-1],s[0]);
363         mask = vp8_simple_filter_mask(limit[i], flimit[i], s[-2], s[-1], s[0], s[1]);
364         vp8_simple_filter(mask, s - 2, s - 1, s, s + 1);
365         s += p;
366     }
367     while (++i < count * 8);
368
369 }