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