loopfilter_16_neon.asm revision 7ce0a1d1337c01056ba24006efab21f00e179e04
1;
2;  Copyright (c) 2013 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    EXPORT  |vpx_lpf_horizontal_4_dual_neon|
12    ARM
13
14    AREA ||.text||, CODE, READONLY, ALIGN=2
15
16;void vpx_lpf_horizontal_4_dual_neon(uint8_t *s, int p,
17;                                    const uint8_t *blimit0,
18;                                    const uint8_t *limit0,
19;                                    const uint8_t *thresh0,
20;                                    const uint8_t *blimit1,
21;                                    const uint8_t *limit1,
22;                                    const uint8_t *thresh1)
23; r0    uint8_t *s,
24; r1    int p,
25; r2    const uint8_t *blimit0,
26; r3    const uint8_t *limit0,
27; sp    const uint8_t *thresh0,
28; sp+4  const uint8_t *blimit1,
29; sp+8  const uint8_t *limit1,
30; sp+12 const uint8_t *thresh1,
31
32|vpx_lpf_horizontal_4_dual_neon| PROC
33    push        {lr}
34
35    ldr         r12, [sp, #4]              ; load thresh0
36    vld1.8      {d0}, [r2]                 ; load blimit0 to first half q
37    vld1.8      {d2}, [r3]                 ; load limit0 to first half q
38
39    add         r1, r1, r1                 ; double pitch
40    ldr         r2, [sp, #8]               ; load blimit1
41
42    vld1.8      {d4}, [r12]                ; load thresh0 to first half q
43
44    ldr         r3, [sp, #12]              ; load limit1
45    ldr         r12, [sp, #16]             ; load thresh1
46    vld1.8      {d1}, [r2]                 ; load blimit1 to 2nd half q
47
48    sub         r2, r0, r1, lsl #1         ; s[-4 * p]
49
50    vld1.8      {d3}, [r3]                 ; load limit1 to 2nd half q
51    vld1.8      {d5}, [r12]                ; load thresh1 to 2nd half q
52
53    vpush       {d8-d15}                   ; save neon registers
54
55    add         r3, r2, r1, lsr #1         ; s[-3 * p]
56
57    vld1.u8     {q3}, [r2@64], r1          ; p3
58    vld1.u8     {q4}, [r3@64], r1          ; p2
59    vld1.u8     {q5}, [r2@64], r1          ; p1
60    vld1.u8     {q6}, [r3@64], r1          ; p0
61    vld1.u8     {q7}, [r2@64], r1          ; q0
62    vld1.u8     {q8}, [r3@64], r1          ; q1
63    vld1.u8     {q9}, [r2@64]              ; q2
64    vld1.u8     {q10}, [r3@64]             ; q3
65
66    sub         r2, r2, r1, lsl #1
67    sub         r3, r3, r1, lsl #1
68
69    bl          vpx_loop_filter_neon_16
70
71    vst1.u8     {q5}, [r2@64], r1          ; store op1
72    vst1.u8     {q6}, [r3@64], r1          ; store op0
73    vst1.u8     {q7}, [r2@64], r1          ; store oq0
74    vst1.u8     {q8}, [r3@64], r1          ; store oq1
75
76    vpop        {d8-d15}                   ; restore neon registers
77
78    pop         {pc}
79    ENDP        ; |vpx_lpf_horizontal_4_dual_neon|
80
81; void vpx_loop_filter_neon_16();
82; This is a helper function for the loopfilters. The invidual functions do the
83; necessary load, transpose (if necessary) and store. This function uses
84; registers d8-d15, so the calling function must save those registers.
85;
86; r0-r3, r12 PRESERVE
87; q0    blimit
88; q1    limit
89; q2    thresh
90; q3    p3
91; q4    p2
92; q5    p1
93; q6    p0
94; q7    q0
95; q8    q1
96; q9    q2
97; q10   q3
98;
99; Outputs:
100; q5    op1
101; q6    op0
102; q7    oq0
103; q8    oq1
104|vpx_loop_filter_neon_16| PROC
105
106    ; filter_mask
107    vabd.u8     q11, q3, q4                 ; m1 = abs(p3 - p2)
108    vabd.u8     q12, q4, q5                 ; m2 = abs(p2 - p1)
109    vabd.u8     q13, q5, q6                 ; m3 = abs(p1 - p0)
110    vabd.u8     q14, q8, q7                 ; m4 = abs(q1 - q0)
111    vabd.u8     q3, q9, q8                  ; m5 = abs(q2 - q1)
112    vabd.u8     q4, q10, q9                 ; m6 = abs(q3 - q2)
113
114    ; only compare the largest value to limit
115    vmax.u8     q11, q11, q12               ; m7 = max(m1, m2)
116    vmax.u8     q12, q13, q14               ; m8 = max(m3, m4)
117
118    vabd.u8     q9, q6, q7                  ; abs(p0 - q0)
119
120    vmax.u8     q3, q3, q4                  ; m9 = max(m5, m6)
121
122    vmov.u8     q10, #0x80
123
124    vmax.u8     q15, q11, q12               ; m10 = max(m7, m8)
125
126    vcgt.u8     q13, q13, q2                ; (abs(p1 - p0) > thresh)*-1
127    vcgt.u8     q14, q14, q2                ; (abs(q1 - q0) > thresh)*-1
128    vmax.u8     q15, q15, q3                ; m11 = max(m10, m9)
129
130    vabd.u8     q2, q5, q8                  ; a = abs(p1 - q1)
131    vqadd.u8    q9, q9, q9                  ; b = abs(p0 - q0) * 2
132
133    veor        q7, q7, q10                 ; qs0
134
135    vcge.u8     q15, q1, q15                ; abs(m11) > limit
136
137    vshr.u8     q2, q2, #1                  ; a = a / 2
138    veor        q6, q6, q10                 ; ps0
139
140    veor        q5, q5, q10                 ; ps1
141    vqadd.u8    q9, q9, q2                  ; a = b + a
142
143    veor        q8, q8, q10                 ; qs1
144
145    vmov.u16    q4, #3
146
147    vsubl.s8    q2, d14, d12                ; ( qs0 - ps0)
148    vsubl.s8    q11, d15, d13
149
150    vcge.u8     q9, q0, q9                  ; a > blimit
151
152    vqsub.s8    q1, q5, q8                  ; filter = clamp(ps1-qs1)
153    vorr        q14, q13, q14               ; hev
154
155    vmul.i16    q2, q2, q4                  ; 3 * ( qs0 - ps0)
156    vmul.i16    q11, q11, q4
157
158    vand        q1, q1, q14                 ; filter &= hev
159    vand        q15, q15, q9                ; mask
160
161    vmov.u8     q4, #3
162
163    vaddw.s8    q2, q2, d2                  ; filter + 3 * (qs0 - ps0)
164    vaddw.s8    q11, q11, d3
165
166    vmov.u8     q9, #4
167
168    ; filter = clamp(filter + 3 * ( qs0 - ps0))
169    vqmovn.s16  d2, q2
170    vqmovn.s16  d3, q11
171    vand        q1, q1, q15                 ; filter &= mask
172
173    vqadd.s8    q2, q1, q4                  ; filter2 = clamp(filter+3)
174    vqadd.s8    q1, q1, q9                  ; filter1 = clamp(filter+4)
175    vshr.s8     q2, q2, #3                  ; filter2 >>= 3
176    vshr.s8     q1, q1, #3                  ; filter1 >>= 3
177
178
179    vqadd.s8    q11, q6, q2                 ; u = clamp(ps0 + filter2)
180    vqsub.s8    q0, q7, q1                  ; u = clamp(qs0 - filter1)
181
182    ; outer tap adjustments
183    vrshr.s8    q1, q1, #1                  ; filter = ++filter1 >> 1
184
185    veor        q7, q0,  q10                ; *oq0 = u^0x80
186
187    vbic        q1, q1, q14                 ; filter &= ~hev
188
189    vqadd.s8    q13, q5, q1                 ; u = clamp(ps1 + filter)
190    vqsub.s8    q12, q8, q1                 ; u = clamp(qs1 - filter)
191
192    veor        q6, q11, q10                ; *op0 = u^0x80
193    veor        q5, q13, q10                ; *op1 = u^0x80
194    veor        q8, q12, q10                ; *oq1 = u^0x80
195
196    bx          lr
197    ENDP        ; |vpx_loop_filter_neon_16|
198
199    END
200