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_y_neon|
13    EXPORT  |vp8_loop_filter_horizontal_edge_uv_neon|
14    EXPORT  |vp8_loop_filter_vertical_edge_y_neon|
15    EXPORT  |vp8_loop_filter_vertical_edge_uv_neon|
16    ARM
17
18    AREA ||.text||, CODE, READONLY, ALIGN=2
19
20; r0    unsigned char *src
21; r1    int pitch
22; r2    unsigned char blimit
23; r3    unsigned char limit
24; sp    unsigned char thresh,
25|vp8_loop_filter_horizontal_edge_y_neon| PROC
26    push        {lr}
27    vdup.u8     q0, r2                     ; duplicate blimit
28    vdup.u8     q1, r3                     ; duplicate limit
29    sub         r2, r0, r1, lsl #2         ; move src pointer down by 4 lines
30    ldr         r3, [sp, #4]               ; load thresh
31    add         r12, r2, r1
32    add         r1, r1, r1
33
34    vdup.u8     q2, r3                     ; duplicate thresh
35
36    vld1.u8     {q3}, [r2@128], r1              ; p3
37    vld1.u8     {q4}, [r12@128], r1             ; p2
38    vld1.u8     {q5}, [r2@128], r1              ; p1
39    vld1.u8     {q6}, [r12@128], r1             ; p0
40    vld1.u8     {q7}, [r2@128], r1              ; q0
41    vld1.u8     {q8}, [r12@128], r1             ; q1
42    vld1.u8     {q9}, [r2@128]                  ; q2
43    vld1.u8     {q10}, [r12@128]                ; q3
44
45    sub         r2, r2, r1, lsl #1
46    sub         r12, r12, r1, lsl #1
47
48    bl          vp8_loop_filter_neon
49
50    vst1.u8     {q5}, [r2@128], r1              ; store op1
51    vst1.u8     {q6}, [r12@128], r1             ; store op0
52    vst1.u8     {q7}, [r2@128], r1              ; store oq0
53    vst1.u8     {q8}, [r12@128], r1             ; store oq1
54
55    pop         {pc}
56    ENDP        ; |vp8_loop_filter_horizontal_edge_y_neon|
57
58
59; r0    unsigned char *u,
60; r1    int pitch,
61; r2    unsigned char blimit
62; r3    unsigned char limit
63; sp    unsigned char thresh,
64; sp+4  unsigned char *v
65|vp8_loop_filter_horizontal_edge_uv_neon| PROC
66    push        {lr}
67    vdup.u8     q0, r2                      ; duplicate blimit
68    vdup.u8     q1, r3                      ; duplicate limit
69    ldr         r12, [sp, #4]               ; load thresh
70    ldr         r2, [sp, #8]                ; load v ptr
71    vdup.u8     q2, r12                     ; duplicate thresh
72
73    sub         r3, r0, r1, lsl #2          ; move u pointer down by 4 lines
74    sub         r12, r2, r1, lsl #2         ; move v pointer down by 4 lines
75
76    vld1.u8     {d6}, [r3@64], r1              ; p3
77    vld1.u8     {d7}, [r12@64], r1             ; p3
78    vld1.u8     {d8}, [r3@64], r1              ; p2
79    vld1.u8     {d9}, [r12@64], r1             ; p2
80    vld1.u8     {d10}, [r3@64], r1             ; p1
81    vld1.u8     {d11}, [r12@64], r1            ; p1
82    vld1.u8     {d12}, [r3@64], r1             ; p0
83    vld1.u8     {d13}, [r12@64], r1            ; p0
84    vld1.u8     {d14}, [r3@64], r1             ; q0
85    vld1.u8     {d15}, [r12@64], r1            ; q0
86    vld1.u8     {d16}, [r3@64], r1             ; q1
87    vld1.u8     {d17}, [r12@64], r1            ; q1
88    vld1.u8     {d18}, [r3@64], r1             ; q2
89    vld1.u8     {d19}, [r12@64], r1            ; q2
90    vld1.u8     {d20}, [r3@64]                 ; q3
91    vld1.u8     {d21}, [r12@64]                ; q3
92
93    bl          vp8_loop_filter_neon
94
95    sub         r0, r0, r1, lsl #1
96    sub         r2, r2, r1, lsl #1
97
98    vst1.u8     {d10}, [r0@64], r1             ; store u op1
99    vst1.u8     {d11}, [r2@64], r1             ; store v op1
100    vst1.u8     {d12}, [r0@64], r1             ; store u op0
101    vst1.u8     {d13}, [r2@64], r1             ; store v op0
102    vst1.u8     {d14}, [r0@64], r1             ; store u oq0
103    vst1.u8     {d15}, [r2@64], r1             ; store v oq0
104    vst1.u8     {d16}, [r0@64]                 ; store u oq1
105    vst1.u8     {d17}, [r2@64]                 ; store v oq1
106
107    pop         {pc}
108    ENDP        ; |vp8_loop_filter_horizontal_edge_uv_neon|
109
110; void vp8_loop_filter_vertical_edge_y_neon(unsigned char *src, int pitch,
111;                                           const signed char *flimit,
112;                                           const signed char *limit,
113;                                           const signed char *thresh,
114;                                           int count)
115; r0    unsigned char *src
116; r1    int pitch
117; r2    unsigned char blimit
118; r3    unsigned char limit
119; sp    unsigned char thresh,
120
121|vp8_loop_filter_vertical_edge_y_neon| PROC
122    push        {lr}
123    vdup.u8     q0, r2                     ; duplicate blimit
124    vdup.u8     q1, r3                     ; duplicate limit
125    sub         r2, r0, #4                 ; src ptr down by 4 columns
126    add         r1, r1, r1
127    ldr         r3, [sp, #4]               ; load thresh
128    add         r12, r2, r1, asr #1
129
130    vld1.u8     {d6}, [r2], r1
131    vld1.u8     {d8}, [r12], r1
132    vld1.u8     {d10}, [r2], r1
133    vld1.u8     {d12}, [r12], r1
134    vld1.u8     {d14}, [r2], r1
135    vld1.u8     {d16}, [r12], r1
136    vld1.u8     {d18}, [r2], r1
137    vld1.u8     {d20}, [r12], r1
138
139    vld1.u8     {d7}, [r2], r1              ; load second 8-line src data
140    vld1.u8     {d9}, [r12], r1
141    vld1.u8     {d11}, [r2], r1
142    vld1.u8     {d13}, [r12], r1
143    vld1.u8     {d15}, [r2], r1
144    vld1.u8     {d17}, [r12], r1
145    vld1.u8     {d19}, [r2]
146    vld1.u8     {d21}, [r12]
147
148    ;transpose to 8x16 matrix
149    vtrn.32     q3, q7
150    vtrn.32     q4, q8
151    vtrn.32     q5, q9
152    vtrn.32     q6, q10
153
154    vdup.u8     q2, r3                     ; duplicate thresh
155
156    vtrn.16     q3, q5
157    vtrn.16     q4, q6
158    vtrn.16     q7, q9
159    vtrn.16     q8, q10
160
161    vtrn.8      q3, q4
162    vtrn.8      q5, q6
163    vtrn.8      q7, q8
164    vtrn.8      q9, q10
165
166    bl          vp8_loop_filter_neon
167
168    vswp        d12, d11
169    vswp        d16, d13
170
171    sub         r0, r0, #2                 ; dst ptr
172
173    vswp        d14, d12
174    vswp        d16, d15
175
176    add         r12, r0, r1, asr #1
177
178    ;store op1, op0, oq0, oq1
179    vst4.8      {d10[0], d11[0], d12[0], d13[0]}, [r0], r1
180    vst4.8      {d10[1], d11[1], d12[1], d13[1]}, [r12], r1
181    vst4.8      {d10[2], d11[2], d12[2], d13[2]}, [r0], r1
182    vst4.8      {d10[3], d11[3], d12[3], d13[3]}, [r12], r1
183    vst4.8      {d10[4], d11[4], d12[4], d13[4]}, [r0], r1
184    vst4.8      {d10[5], d11[5], d12[5], d13[5]}, [r12], r1
185    vst4.8      {d10[6], d11[6], d12[6], d13[6]}, [r0], r1
186    vst4.8      {d10[7], d11[7], d12[7], d13[7]}, [r12], r1
187
188    vst4.8      {d14[0], d15[0], d16[0], d17[0]}, [r0], r1
189    vst4.8      {d14[1], d15[1], d16[1], d17[1]}, [r12], r1
190    vst4.8      {d14[2], d15[2], d16[2], d17[2]}, [r0], r1
191    vst4.8      {d14[3], d15[3], d16[3], d17[3]}, [r12], r1
192    vst4.8      {d14[4], d15[4], d16[4], d17[4]}, [r0], r1
193    vst4.8      {d14[5], d15[5], d16[5], d17[5]}, [r12], r1
194    vst4.8      {d14[6], d15[6], d16[6], d17[6]}, [r0]
195    vst4.8      {d14[7], d15[7], d16[7], d17[7]}, [r12]
196
197    pop         {pc}
198    ENDP        ; |vp8_loop_filter_vertical_edge_y_neon|
199
200; void vp8_loop_filter_vertical_edge_uv_neon(unsigned char *u, int pitch
201;                                            const signed char *flimit,
202;                                            const signed char *limit,
203;                                            const signed char *thresh,
204;                                            unsigned char *v)
205; r0    unsigned char *u,
206; r1    int pitch,
207; r2    unsigned char blimit
208; r3    unsigned char limit
209; sp    unsigned char thresh,
210; sp+4  unsigned char *v
211|vp8_loop_filter_vertical_edge_uv_neon| PROC
212    push        {lr}
213    vdup.u8     q0, r2                      ; duplicate blimit
214    sub         r12, r0, #4                 ; move u pointer down by 4 columns
215    ldr         r2, [sp, #8]                ; load v ptr
216    vdup.u8     q1, r3                      ; duplicate limit
217    sub         r3, r2, #4                  ; move v pointer down by 4 columns
218
219    vld1.u8     {d6}, [r12], r1             ;load u data
220    vld1.u8     {d7}, [r3], r1              ;load v data
221    vld1.u8     {d8}, [r12], r1
222    vld1.u8     {d9}, [r3], r1
223    vld1.u8     {d10}, [r12], r1
224    vld1.u8     {d11}, [r3], r1
225    vld1.u8     {d12}, [r12], r1
226    vld1.u8     {d13}, [r3], r1
227    vld1.u8     {d14}, [r12], r1
228    vld1.u8     {d15}, [r3], r1
229    vld1.u8     {d16}, [r12], r1
230    vld1.u8     {d17}, [r3], r1
231    vld1.u8     {d18}, [r12], r1
232    vld1.u8     {d19}, [r3], r1
233    vld1.u8     {d20}, [r12]
234    vld1.u8     {d21}, [r3]
235
236    ldr        r12, [sp, #4]               ; load thresh
237
238    ;transpose to 8x16 matrix
239    vtrn.32     q3, q7
240    vtrn.32     q4, q8
241    vtrn.32     q5, q9
242    vtrn.32     q6, q10
243
244    vdup.u8     q2, r12                     ; duplicate thresh
245
246    vtrn.16     q3, q5
247    vtrn.16     q4, q6
248    vtrn.16     q7, q9
249    vtrn.16     q8, q10
250
251    vtrn.8      q3, q4
252    vtrn.8      q5, q6
253    vtrn.8      q7, q8
254    vtrn.8      q9, q10
255
256    bl          vp8_loop_filter_neon
257
258    vswp        d12, d11
259    vswp        d16, d13
260    vswp        d14, d12
261    vswp        d16, d15
262
263    sub         r0, r0, #2
264    sub         r2, r2, #2
265
266    ;store op1, op0, oq0, oq1
267    vst4.8      {d10[0], d11[0], d12[0], d13[0]}, [r0], r1
268    vst4.8      {d14[0], d15[0], d16[0], d17[0]}, [r2], r1
269    vst4.8      {d10[1], d11[1], d12[1], d13[1]}, [r0], r1
270    vst4.8      {d14[1], d15[1], d16[1], d17[1]}, [r2], r1
271    vst4.8      {d10[2], d11[2], d12[2], d13[2]}, [r0], r1
272    vst4.8      {d14[2], d15[2], d16[2], d17[2]}, [r2], r1
273    vst4.8      {d10[3], d11[3], d12[3], d13[3]}, [r0], r1
274    vst4.8      {d14[3], d15[3], d16[3], d17[3]}, [r2], r1
275    vst4.8      {d10[4], d11[4], d12[4], d13[4]}, [r0], r1
276    vst4.8      {d14[4], d15[4], d16[4], d17[4]}, [r2], r1
277    vst4.8      {d10[5], d11[5], d12[5], d13[5]}, [r0], r1
278    vst4.8      {d14[5], d15[5], d16[5], d17[5]}, [r2], r1
279    vst4.8      {d10[6], d11[6], d12[6], d13[6]}, [r0], r1
280    vst4.8      {d14[6], d15[6], d16[6], d17[6]}, [r2], r1
281    vst4.8      {d10[7], d11[7], d12[7], d13[7]}, [r0]
282    vst4.8      {d14[7], d15[7], d16[7], d17[7]}, [r2]
283
284    pop         {pc}
285    ENDP        ; |vp8_loop_filter_vertical_edge_uv_neon|
286
287; void vp8_loop_filter_neon();
288; This is a helper function for the loopfilters. The invidual functions do the
289; necessary load, transpose (if necessary) and store.
290
291; r0-r3 PRESERVE
292; q0    flimit
293; q1    limit
294; q2    thresh
295; q3    p3
296; q4    p2
297; q5    p1
298; q6    p0
299; q7    q0
300; q8    q1
301; q9    q2
302; q10   q3
303|vp8_loop_filter_neon| PROC
304
305    ; vp8_filter_mask
306    vabd.u8     q11, q3, q4                 ; abs(p3 - p2)
307    vabd.u8     q12, q4, q5                 ; abs(p2 - p1)
308    vabd.u8     q13, q5, q6                 ; abs(p1 - p0)
309    vabd.u8     q14, q8, q7                 ; abs(q1 - q0)
310    vabd.u8     q3, q9, q8                  ; abs(q2 - q1)
311    vabd.u8     q4, q10, q9                 ; abs(q3 - q2)
312
313    vmax.u8     q11, q11, q12
314    vmax.u8     q12, q13, q14
315    vmax.u8     q3, q3, q4
316    vmax.u8     q15, q11, q12
317
318    vabd.u8     q9, q6, q7                  ; abs(p0 - q0)
319
320    ; vp8_hevmask
321    vcgt.u8     q13, q13, q2                ; (abs(p1 - p0) > thresh)*-1
322    vcgt.u8     q14, q14, q2                ; (abs(q1 - q0) > thresh)*-1
323    vmax.u8     q15, q15, q3
324
325    vmov.u8     q10, #0x80                   ; 0x80
326
327    vabd.u8     q2, q5, q8                  ; a = abs(p1 - q1)
328    vqadd.u8    q9, q9, q9                  ; b = abs(p0 - q0) * 2
329
330    vcge.u8     q15, q1, q15
331
332    ; vp8_filter() function
333    ; convert to signed
334    veor        q7, q7, q10                 ; qs0
335    vshr.u8     q2, q2, #1                  ; a = a / 2
336    veor        q6, q6, q10                 ; ps0
337
338    veor        q5, q5, q10                 ; ps1
339    vqadd.u8    q9, q9, q2                  ; a = b + a
340
341    veor        q8, q8, q10                 ; qs1
342
343    vmov.u8     q10, #3                     ; #3
344
345    vsubl.s8    q2, d14, d12                ; ( qs0 - ps0)
346    vsubl.s8    q11, d15, d13
347
348    vcge.u8     q9, q0, q9                  ; (a > flimit * 2 + limit) * -1
349
350    vmovl.u8    q4, d20
351
352    vqsub.s8    q1, q5, q8                  ; vp8_filter = clamp(ps1-qs1)
353    vorr        q14, q13, q14               ; vp8_hevmask
354
355    vmul.i16    q2, q2, q4                  ; 3 * ( qs0 - ps0)
356    vmul.i16    q11, q11, q4
357
358    vand        q1, q1, q14                 ; vp8_filter &= hev
359    vand        q15, q15, q9                ; vp8_filter_mask
360
361    vaddw.s8    q2, q2, d2
362    vaddw.s8    q11, q11, d3
363
364    vmov.u8     q9, #4                      ; #4
365
366    ; vp8_filter = clamp(vp8_filter + 3 * ( qs0 - ps0))
367    vqmovn.s16  d2, q2
368    vqmovn.s16  d3, q11
369    vand        q1, q1, q15                 ; vp8_filter &= mask
370
371    vqadd.s8    q2, q1, q10                 ; Filter2 = clamp(vp8_filter+3)
372    vqadd.s8    q1, q1, q9                  ; Filter1 = clamp(vp8_filter+4)
373    vshr.s8     q2, q2, #3                  ; Filter2 >>= 3
374    vshr.s8     q1, q1, #3                  ; Filter1 >>= 3
375
376
377    vqadd.s8    q11, q6, q2                 ; u = clamp(ps0 + Filter2)
378    vqsub.s8    q10, q7, q1                 ; u = clamp(qs0 - Filter1)
379
380    ; outer tap adjustments: ++vp8_filter >> 1
381    vrshr.s8    q1, q1, #1
382    vbic        q1, q1, q14                 ; vp8_filter &= ~hev
383    vmov.u8     q0, #0x80                   ; 0x80
384    vqadd.s8    q13, q5, q1                 ; u = clamp(ps1 + vp8_filter)
385    vqsub.s8    q12, q8, q1                 ; u = clamp(qs1 - vp8_filter)
386
387    veor        q6, q11, q0                 ; *op0 = u^0x80
388    veor        q7, q10, q0                 ; *oq0 = u^0x80
389    veor        q5, q13, q0                 ; *op1 = u^0x80
390    veor        q8, q12, q0                 ; *oq1 = u^0x80
391
392    bx          lr
393    ENDP        ; |vp8_loop_filter_horizontal_edge_y_neon|
394
395;-----------------
396
397    END
398