]> granicus.if.org Git - libvpx/blob - vp8/common/arm/neon/loopfilterhorizontaledge_uv_neon.asm
safety check to avoid divide by 0s
[libvpx] / vp8 / common / arm / neon / loopfilterhorizontaledge_uv_neon.asm
1 ;
2 ;  Copyright (c) 2010 The WebM 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     EXPORT  |vp8_loop_filter_horizontal_edge_uv_neon|
13     ARM
14     REQUIRE8
15     PRESERVE8
16
17     AREA ||.text||, CODE, READONLY, ALIGN=2
18 ;Note: flimit, limit, and thresh shpuld be positive numbers. All 16 elements in flimit
19 ;are equal. So, in the code, only one load is needed
20 ;for flimit. Same way applies to limit and thresh.
21 ; r0    unsigned char *u,
22 ; r1    int p, //pitch
23 ; r2    const signed char *flimit,
24 ; r3    const signed char *limit,
25 ; stack(r4) const signed char *thresh,
26 ; stack(r5) unsigned char *v
27
28 |vp8_loop_filter_horizontal_edge_uv_neon| PROC
29     sub         r0, r0, r1, lsl #2          ; move u pointer down by 4 lines
30     vld1.s8     {d0[], d1[]}, [r2]          ; flimit
31
32     ldr         r2, [sp, #4]                ; load v ptr
33     ldr         r12, [sp, #0]               ; load thresh pointer
34
35     sub         r2, r2, r1, lsl #2          ; move v pointer down by 4 lines
36
37     vld1.u8     {d6}, [r0], r1              ; p3
38     vld1.u8     {d7}, [r2], r1              ; p3
39     vld1.u8     {d8}, [r0], r1              ; p2
40     vld1.u8     {d9}, [r2], r1              ; p2
41     vld1.u8     {d10}, [r0], r1             ; p1
42     vld1.u8     {d11}, [r2], r1             ; p1
43     vld1.u8     {d12}, [r0], r1             ; p0
44     vld1.u8     {d13}, [r2], r1             ; p0
45     vld1.u8     {d14}, [r0], r1             ; q0
46     vld1.u8     {d15}, [r2], r1             ; q0
47     vld1.u8     {d16}, [r0], r1             ; q1
48     vld1.u8     {d17}, [r2], r1             ; q1
49     vld1.u8     {d18}, [r0], r1             ; q2
50     vld1.u8     {d19}, [r2], r1             ; q2
51     vld1.u8     {d20}, [r0], r1             ; q3
52     vld1.u8     {d21}, [r2], r1             ; q3
53
54     vld1.s8     {d2[], d3[]}, [r3]          ; limit
55     vld1.s8     {d4[], d5[]}, [r12]         ; thresh
56
57     ldr         r12, _lfhuv_coeff_
58     ; vp8_filter_mask
59     vabd.u8     q11, q3, q4                 ; abs(p3 - p2)
60     vabd.u8     q12, q4, q5                 ; abs(p2 - p1)
61     vabd.u8     q13, q5, q6                 ; abs(p1 - p0)
62     vabd.u8     q14, q8, q7                 ; abs(q1 - q0)
63     vabd.u8     q3, q9, q8                  ; abs(q2 - q1)
64     vabd.u8     q4, q10, q9                 ; abs(q3 - q2)
65     vabd.u8     q9, q6, q7                  ; abs(p0 - q0)
66
67     vmax.u8     q11, q11, q12
68     vmax.u8     q12, q13, q14
69     vmax.u8     q3, q3, q4
70     vmax.u8     q15, q11, q12
71
72     ; vp8_hevmask
73     vcgt.u8     q13, q13, q2                ; (abs(p1 - p0) > thresh)*-1
74     vcgt.u8     q14, q14, q2                ; (abs(q1 - q0) > thresh)*-1
75     vmax.u8     q15, q15, q3
76
77     vadd.u8     q0, q0, q0                  ; flimit * 2
78     vadd.u8     q0, q0, q1                  ; flimit * 2 + limit
79     vcge.u8     q15, q1, q15                ; (max  > limit) * -1
80
81     vabd.u8     q2, q5, q8                  ; abs(p1 - q1)
82     vqadd.u8    q9, q9, q9                  ; abs(p0 - q0) * 2
83     vshr.u8     q2, q2, #1                  ; abs(p1 - q1) / 2
84     vqadd.u8    q9, q9, q2                  ; abs(p0 - q0) * 2 + abs(p1 - q1) / 2
85     vcge.u8     q9, q0, q9                  ; (abs(p0 - q0)*2 + abs(p1-q1)/2 > flimit*2 + limit)*-1
86
87     vld1.u8     {q0}, [r12]!
88
89     ;vp8_filter() function
90     veor        q7, q7, q0                  ; qs0: q0 offset to convert to a signed value
91     veor        q6, q6, q0                  ; ps0: p0 offset to convert to a signed value
92     veor        q5, q5, q0                  ; ps1: p1 offset to convert to a signed value
93     veor        q8, q8, q0                  ; qs1: q1 offset to convert to a signed value
94 ;;;;;;;;;;;;;;
95     vld1.u8     {q10}, [r12]!
96
97     vsubl.s8    q2, d14, d12                ; ( qs0 - ps0)
98     vsubl.s8    q11, d15, d13
99
100     vmovl.u8    q4, d20
101
102     vqsub.s8    q1, q5, q8                  ; vp8_filter = vp8_signed_char_clamp(ps1-qs1)
103     vorr        q14, q13, q14               ; q14: vp8_hevmask
104
105     vmul.i16    q2, q2, q4                  ; 3 * ( qs0 - ps0)
106     vmul.i16    q11, q11, q4
107
108     vand        q1, q1, q14                 ; vp8_filter &= hev
109     vand        q15, q15, q9                ; vp8_filter_mask
110
111     vaddw.s8    q2, q2, d2
112     vaddw.s8    q11, q11, d3
113
114     vld1.u8     {q9}, [r12]!
115     ;
116     vqmovn.s16  d2, q2                      ; vp8_filter = vp8_signed_char_clamp(vp8_filter + 3 * ( qs0 - ps0))
117     vqmovn.s16  d3, q11
118     ;;
119
120     vand        q1, q1, q15                 ; vp8_filter &= mask
121     vqadd.s8    q2, q1, q10                 ; Filter2 = vp8_signed_char_clamp(vp8_filter+3)
122     vqadd.s8    q1, q1, q9                  ; Filter1 = vp8_signed_char_clamp(vp8_filter+4)
123     vshr.s8     q2, q2, #3                  ; Filter2 >>= 3
124     vshr.s8     q1, q1, #3                  ; Filter1 >>= 3
125
126     ;calculate output
127     vqadd.s8    q11, q6, q2             ; u = vp8_signed_char_clamp(ps0 + Filter2)
128     vqsub.s8    q10, q7, q1                 ; u = vp8_signed_char_clamp(qs0 - Filter1)
129 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
130
131     vrshr.s8    q1, q1, #1                  ;round/shift:  vp8_filter += 1; vp8_filter >>= 1
132
133     sub         r0, r0, r1, lsl #2
134     sub         r0, r0, r1, lsl #1
135     ;
136
137     vbic        q1, q1, q14                 ; vp8_filter &= ~hev
138
139     sub         r2, r2, r1, lsl #2
140     sub         r2, r2, r1, lsl #1
141     ;;
142
143     vqadd.s8    q13, q5, q1                 ; u = vp8_signed_char_clamp(ps1 + vp8_filter)
144     vqsub.s8    q12, q8, q1                 ; u = vp8_signed_char_clamp(qs1 - vp8_filter)
145     ;
146
147     veor        q5, q13, q0                 ; *op1 = u^0x80
148     veor        q6, q11, q0                 ; *op0 = u^0x80
149     veor        q7, q10, q0                 ; *oq0 = u^0x80
150     veor        q8, q12, q0                 ; *oq1 = u^0x80
151     ;
152
153     vst1.u8     {d10}, [r0], r1             ; store u op1
154     vst1.u8     {d11}, [r2], r1             ; store v op1
155     vst1.u8     {d12}, [r0], r1             ; store u op0
156     vst1.u8     {d13}, [r2], r1             ; store v op0
157     vst1.u8     {d14}, [r0], r1             ; store u oq0
158     vst1.u8     {d15}, [r2], r1             ; store v oq0
159     vst1.u8     {d16}, [r0], r1             ; store u oq1
160     vst1.u8     {d17}, [r2], r1             ; store v oq1
161
162     bx          lr
163     ENDP        ; |vp8_loop_filter_horizontal_edge_uv_neon|
164
165 ;-----------------
166     AREA    hloopfilteruv_dat, DATA, READWRITE          ;read/write by default
167 ;Data section with name data_area is specified. DCD reserves space in memory for 16 data.
168 ;One word each is reserved. Label filter_coeff can be used to access the data.
169 ;Data address: filter_coeff, filter_coeff+4, filter_coeff+8 ...
170 _lfhuv_coeff_
171     DCD     lfhuv_coeff
172 lfhuv_coeff
173     DCD     0x80808080, 0x80808080, 0x80808080, 0x80808080
174     DCD     0x03030303, 0x03030303, 0x03030303, 0x03030303
175     DCD     0x04040404, 0x04040404, 0x04040404, 0x04040404
176     DCD     0x01010101, 0x01010101, 0x01010101, 0x01010101
177
178     END