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_sixtap_predict16x16_neon|
13    ARM
14    REQUIRE8
15    PRESERVE8
16
17    AREA ||.text||, CODE, READONLY, ALIGN=2
18
19filter16_coeff
20    DCD     0,  0,  128,    0,   0,  0,   0,  0
21    DCD     0, -6,  123,   12,  -1,  0,   0,  0
22    DCD     2, -11, 108,   36,  -8,  1,   0,  0
23    DCD     0, -9,   93,   50,  -6,  0,   0,  0
24    DCD     3, -16,  77,   77, -16,  3,   0,  0
25    DCD     0, -6,   50,   93,  -9,  0,   0,  0
26    DCD     1, -8,   36,  108, -11,  2,   0,  0
27    DCD     0, -1,   12,  123,  -6,   0,  0,  0
28
29; r0    unsigned char  *src_ptr,
30; r1    int  src_pixels_per_line,
31; r2    int  xoffset,
32; r3    int  yoffset,
33; r4    unsigned char *dst_ptr,
34; stack(r5) int  dst_pitch
35
36;Note: To take advantage of 8-bit mulplication instruction in NEON. First apply abs() to
37; filter coeffs to make them u8. Then, use vmlsl for negtive coeffs. After multiplication,
38; the result can be negtive. So, I treat the result as s16. But, since it is also possible
39; that the result can be a large positive number (> 2^15-1), which could be confused as a
40; negtive number. To avoid that error, apply filter coeffs in the order of 0, 1, 4 ,5 ,2,
41; which ensures that the result stays in s16 range. Finally, saturated add the result by
42; applying 3rd filter coeff. Same applys to other filter functions.
43
44|vp8_sixtap_predict16x16_neon| PROC
45    push            {r4-r5, lr}
46
47    adr             r12, filter16_coeff
48    ldr             r4, [sp, #12]           ;load parameters from stack
49    ldr             r5, [sp, #16]           ;load parameters from stack
50
51    cmp             r2, #0                  ;skip first_pass filter if xoffset=0
52    beq             secondpass_filter16x16_only
53
54    add             r2, r12, r2, lsl #5     ;calculate filter location
55
56    cmp             r3, #0                  ;skip second_pass filter if yoffset=0
57
58    vld1.s32        {q14, q15}, [r2]        ;load first_pass filter
59
60    beq             firstpass_filter16x16_only
61
62    sub             sp, sp, #336            ;reserve space on stack for temporary storage
63    mov             lr, sp
64
65    vabs.s32        q12, q14
66    vabs.s32        q13, q15
67
68    mov             r2, #7                  ;loop counter
69    sub             r0, r0, #2              ;move srcptr back to (line-2) and (column-2)
70    sub             r0, r0, r1, lsl #1
71
72    vdup.8          d0, d24[0]              ;first_pass filter (d0-d5)
73    vdup.8          d1, d24[4]
74    vdup.8          d2, d25[0]
75    vdup.8          d3, d25[4]
76    vdup.8          d4, d26[0]
77    vdup.8          d5, d26[4]
78
79;First Pass: output_height lines x output_width columns (21x16)
80filt_blk2d_fp16x16_loop_neon
81    vld1.u8         {d6, d7, d8}, [r0], r1      ;load src data
82    vld1.u8         {d9, d10, d11}, [r0], r1
83    vld1.u8         {d12, d13, d14}, [r0], r1
84
85    pld             [r0]
86    pld             [r0, r1]
87    pld             [r0, r1, lsl #1]
88
89    vmull.u8        q8, d6, d0              ;(src_ptr[-2] * vp8_filter[0])
90    vmull.u8        q9, d7, d0
91    vmull.u8        q10, d9, d0
92    vmull.u8        q11, d10, d0
93    vmull.u8        q12, d12, d0
94    vmull.u8        q13, d13, d0
95
96    vext.8          d28, d6, d7, #1         ;construct src_ptr[-1]
97    vext.8          d29, d9, d10, #1
98    vext.8          d30, d12, d13, #1
99
100    vmlsl.u8        q8, d28, d1             ;-(src_ptr[-1] * vp8_filter[1])
101    vmlsl.u8        q10, d29, d1
102    vmlsl.u8        q12, d30, d1
103
104    vext.8          d28, d7, d8, #1
105    vext.8          d29, d10, d11, #1
106    vext.8          d30, d13, d14, #1
107
108    vmlsl.u8        q9, d28, d1             ;-(src_ptr[-1] * vp8_filter[1])
109    vmlsl.u8        q11, d29, d1
110    vmlsl.u8        q13, d30, d1
111
112    vext.8          d28, d6, d7, #4         ;construct src_ptr[2]
113    vext.8          d29, d9, d10, #4
114    vext.8          d30, d12, d13, #4
115
116    vmlsl.u8        q8, d28, d4             ;-(src_ptr[2] * vp8_filter[4])
117    vmlsl.u8        q10, d29, d4
118    vmlsl.u8        q12, d30, d4
119
120    vext.8          d28, d7, d8, #4
121    vext.8          d29, d10, d11, #4
122    vext.8          d30, d13, d14, #4
123
124    vmlsl.u8        q9, d28, d4             ;-(src_ptr[2] * vp8_filter[4])
125    vmlsl.u8        q11, d29, d4
126    vmlsl.u8        q13, d30, d4
127
128    vext.8          d28, d6, d7, #5         ;construct src_ptr[3]
129    vext.8          d29, d9, d10, #5
130    vext.8          d30, d12, d13, #5
131
132    vmlal.u8        q8, d28, d5             ;(src_ptr[3] * vp8_filter[5])
133    vmlal.u8        q10, d29, d5
134    vmlal.u8        q12, d30, d5
135
136    vext.8          d28, d7, d8, #5
137    vext.8          d29, d10, d11, #5
138    vext.8          d30, d13, d14, #5
139
140    vmlal.u8        q9, d28, d5             ;(src_ptr[3] * vp8_filter[5])
141    vmlal.u8        q11, d29, d5
142    vmlal.u8        q13, d30, d5
143
144    vext.8          d28, d6, d7, #2         ;construct src_ptr[0]
145    vext.8          d29, d9, d10, #2
146    vext.8          d30, d12, d13, #2
147
148    vmlal.u8        q8, d28, d2             ;(src_ptr[0] * vp8_filter[2])
149    vmlal.u8        q10, d29, d2
150    vmlal.u8        q12, d30, d2
151
152    vext.8          d28, d7, d8, #2
153    vext.8          d29, d10, d11, #2
154    vext.8          d30, d13, d14, #2
155
156    vmlal.u8        q9, d28, d2             ;(src_ptr[0] * vp8_filter[2])
157    vmlal.u8        q11, d29, d2
158    vmlal.u8        q13, d30, d2
159
160    vext.8          d28, d6, d7, #3         ;construct src_ptr[1]
161    vext.8          d29, d9, d10, #3
162    vext.8          d30, d12, d13, #3
163
164    vext.8          d15, d7, d8, #3
165    vext.8          d31, d10, d11, #3
166    vext.8          d6, d13, d14, #3
167
168    vmull.u8        q4, d28, d3             ;(src_ptr[1] * vp8_filter[3])
169    vmull.u8        q5, d29, d3
170    vmull.u8        q6, d30, d3
171
172    vqadd.s16       q8, q4                  ;sum of all (src_data*filter_parameters)
173    vqadd.s16       q10, q5
174    vqadd.s16       q12, q6
175
176    vmull.u8        q6, d15, d3             ;(src_ptr[1] * vp8_filter[3])
177    vmull.u8        q7, d31, d3
178    vmull.u8        q3, d6, d3
179
180    subs            r2, r2, #1
181
182    vqadd.s16       q9, q6
183    vqadd.s16       q11, q7
184    vqadd.s16       q13, q3
185
186    vqrshrun.s16    d6, q8, #7              ;shift/round/saturate to u8
187    vqrshrun.s16    d7, q9, #7
188    vqrshrun.s16    d8, q10, #7
189    vqrshrun.s16    d9, q11, #7
190    vqrshrun.s16    d10, q12, #7
191    vqrshrun.s16    d11, q13, #7
192
193    vst1.u8         {d6, d7, d8}, [lr]!     ;store result
194    vst1.u8         {d9, d10, d11}, [lr]!
195
196    bne             filt_blk2d_fp16x16_loop_neon
197
198;Second pass: 16x16
199;secondpass_filter - do first 8-columns and then second 8-columns
200    add             r3, r12, r3, lsl #5
201    sub             lr, lr, #336
202
203    vld1.s32        {q5, q6}, [r3]          ;load second_pass filter
204    mov             r3, #2                  ;loop counter
205
206    vabs.s32        q7, q5
207    vabs.s32        q8, q6
208
209    mov             r2, #16
210
211    vdup.8          d0, d14[0]              ;second_pass filter parameters (d0-d5)
212    vdup.8          d1, d14[4]
213    vdup.8          d2, d15[0]
214    vdup.8          d3, d15[4]
215    vdup.8          d4, d16[0]
216    vdup.8          d5, d16[4]
217
218filt_blk2d_sp16x16_outloop_neon
219    vld1.u8         {d18}, [lr], r2         ;load src data
220    vld1.u8         {d19}, [lr], r2
221    vld1.u8         {d20}, [lr], r2
222    vld1.u8         {d21}, [lr], r2
223    mov             r12, #4                 ;loop counter
224    vld1.u8         {d22}, [lr], r2
225
226secondpass_inner_loop_neon
227    vld1.u8         {d23}, [lr], r2         ;load src data
228    vld1.u8         {d24}, [lr], r2
229    vld1.u8         {d25}, [lr], r2
230    vld1.u8         {d26}, [lr], r2
231
232    vmull.u8        q3, d18, d0             ;(src_ptr[-2] * vp8_filter[0])
233    vmull.u8        q4, d19, d0
234    vmull.u8        q5, d20, d0
235    vmull.u8        q6, d21, d0
236
237    vmlsl.u8        q3, d19, d1             ;-(src_ptr[-1] * vp8_filter[1])
238    vmlsl.u8        q4, d20, d1
239    vmlsl.u8        q5, d21, d1
240    vmlsl.u8        q6, d22, d1
241
242    vmlsl.u8        q3, d22, d4             ;-(src_ptr[2] * vp8_filter[4])
243    vmlsl.u8        q4, d23, d4
244    vmlsl.u8        q5, d24, d4
245    vmlsl.u8        q6, d25, d4
246
247    vmlal.u8        q3, d20, d2             ;(src_ptr[0] * vp8_filter[2])
248    vmlal.u8        q4, d21, d2
249    vmlal.u8        q5, d22, d2
250    vmlal.u8        q6, d23, d2
251
252    vmlal.u8        q3, d23, d5             ;(src_ptr[3] * vp8_filter[5])
253    vmlal.u8        q4, d24, d5
254    vmlal.u8        q5, d25, d5
255    vmlal.u8        q6, d26, d5
256
257    vmull.u8        q7, d21, d3             ;(src_ptr[1] * vp8_filter[3])
258    vmull.u8        q8, d22, d3
259    vmull.u8        q9, d23, d3
260    vmull.u8        q10, d24, d3
261
262    subs            r12, r12, #1
263
264    vqadd.s16       q7, q3                  ;sum of all (src_data*filter_parameters)
265    vqadd.s16       q8, q4
266    vqadd.s16       q9, q5
267    vqadd.s16       q10, q6
268
269    vqrshrun.s16    d6, q7, #7              ;shift/round/saturate to u8
270    vqrshrun.s16    d7, q8, #7
271    vqrshrun.s16    d8, q9, #7
272    vqrshrun.s16    d9, q10, #7
273
274    vst1.u8         {d6}, [r4], r5          ;store result
275    vmov            q9, q11
276    vst1.u8         {d7}, [r4], r5
277    vmov            q10, q12
278    vst1.u8         {d8}, [r4], r5
279    vmov            d22, d26
280    vst1.u8         {d9}, [r4], r5
281
282    bne             secondpass_inner_loop_neon
283
284    subs            r3, r3, #1
285    sub             lr, lr, #336
286    add             lr, lr, #8
287
288    sub             r4, r4, r5, lsl #4
289    add             r4, r4, #8
290
291    bne filt_blk2d_sp16x16_outloop_neon
292
293    add             sp, sp, #336
294    pop             {r4-r5,pc}
295
296;--------------------
297firstpass_filter16x16_only
298    vabs.s32        q12, q14
299    vabs.s32        q13, q15
300
301    mov             r2, #8                  ;loop counter
302    sub             r0, r0, #2              ;move srcptr back to (column-2)
303
304    vdup.8          d0, d24[0]              ;first_pass filter (d0-d5)
305    vdup.8          d1, d24[4]
306    vdup.8          d2, d25[0]
307    vdup.8          d3, d25[4]
308    vdup.8          d4, d26[0]
309    vdup.8          d5, d26[4]
310
311;First Pass: output_height lines x output_width columns (16x16)
312filt_blk2d_fpo16x16_loop_neon
313    vld1.u8         {d6, d7, d8}, [r0], r1      ;load src data
314    vld1.u8         {d9, d10, d11}, [r0], r1
315
316    pld             [r0]
317    pld             [r0, r1]
318
319    vmull.u8        q6, d6, d0              ;(src_ptr[-2] * vp8_filter[0])
320    vmull.u8        q7, d7, d0
321    vmull.u8        q8, d9, d0
322    vmull.u8        q9, d10, d0
323
324    vext.8          d20, d6, d7, #1         ;construct src_ptr[-1]
325    vext.8          d21, d9, d10, #1
326    vext.8          d22, d7, d8, #1
327    vext.8          d23, d10, d11, #1
328    vext.8          d24, d6, d7, #4         ;construct src_ptr[2]
329    vext.8          d25, d9, d10, #4
330    vext.8          d26, d7, d8, #4
331    vext.8          d27, d10, d11, #4
332    vext.8          d28, d6, d7, #5         ;construct src_ptr[3]
333    vext.8          d29, d9, d10, #5
334
335    vmlsl.u8        q6, d20, d1             ;-(src_ptr[-1] * vp8_filter[1])
336    vmlsl.u8        q8, d21, d1
337    vmlsl.u8        q7, d22, d1             ;-(src_ptr[-1] * vp8_filter[1])
338    vmlsl.u8        q9, d23, d1
339    vmlsl.u8        q6, d24, d4             ;-(src_ptr[2] * vp8_filter[4])
340    vmlsl.u8        q8, d25, d4
341    vmlsl.u8        q7, d26, d4             ;-(src_ptr[2] * vp8_filter[4])
342    vmlsl.u8        q9, d27, d4
343    vmlal.u8        q6, d28, d5             ;(src_ptr[3] * vp8_filter[5])
344    vmlal.u8        q8, d29, d5
345
346    vext.8          d20, d7, d8, #5
347    vext.8          d21, d10, d11, #5
348    vext.8          d22, d6, d7, #2         ;construct src_ptr[0]
349    vext.8          d23, d9, d10, #2
350    vext.8          d24, d7, d8, #2
351    vext.8          d25, d10, d11, #2
352
353    vext.8          d26, d6, d7, #3         ;construct src_ptr[1]
354    vext.8          d27, d9, d10, #3
355    vext.8          d28, d7, d8, #3
356    vext.8          d29, d10, d11, #3
357
358    vmlal.u8        q7, d20, d5             ;(src_ptr[3] * vp8_filter[5])
359    vmlal.u8        q9, d21, d5
360    vmlal.u8        q6, d22, d2             ;(src_ptr[0] * vp8_filter[2])
361    vmlal.u8        q8, d23, d2
362    vmlal.u8        q7, d24, d2             ;(src_ptr[0] * vp8_filter[2])
363    vmlal.u8        q9, d25, d2
364
365    vmull.u8        q10, d26, d3            ;(src_ptr[1] * vp8_filter[3])
366    vmull.u8        q11, d27, d3
367    vmull.u8        q12, d28, d3            ;(src_ptr[1] * vp8_filter[3])
368    vmull.u8        q15, d29, d3
369
370    vqadd.s16       q6, q10                 ;sum of all (src_data*filter_parameters)
371    vqadd.s16       q8, q11
372    vqadd.s16       q7, q12
373    vqadd.s16       q9, q15
374
375    subs            r2, r2, #1
376
377    vqrshrun.s16    d6, q6, #7              ;shift/round/saturate to u8
378    vqrshrun.s16    d7, q7, #7
379    vqrshrun.s16    d8, q8, #7
380    vqrshrun.s16    d9, q9, #7
381
382    vst1.u8         {q3}, [r4], r5              ;store result
383    vst1.u8         {q4}, [r4], r5
384
385    bne             filt_blk2d_fpo16x16_loop_neon
386
387    pop             {r4-r5,pc}
388
389;--------------------
390secondpass_filter16x16_only
391;Second pass: 16x16
392    add             r3, r12, r3, lsl #5
393    sub             r0, r0, r1, lsl #1
394
395    vld1.s32        {q5, q6}, [r3]          ;load second_pass filter
396    mov             r3, #2                  ;loop counter
397
398    vabs.s32        q7, q5
399    vabs.s32        q8, q6
400
401    vdup.8          d0, d14[0]              ;second_pass filter parameters (d0-d5)
402    vdup.8          d1, d14[4]
403    vdup.8          d2, d15[0]
404    vdup.8          d3, d15[4]
405    vdup.8          d4, d16[0]
406    vdup.8          d5, d16[4]
407
408filt_blk2d_spo16x16_outloop_neon
409    vld1.u8         {d18}, [r0], r1         ;load src data
410    vld1.u8         {d19}, [r0], r1
411    vld1.u8         {d20}, [r0], r1
412    vld1.u8         {d21}, [r0], r1
413    mov             r12, #4                 ;loop counter
414    vld1.u8         {d22}, [r0], r1
415
416secondpass_only_inner_loop_neon
417    vld1.u8         {d23}, [r0], r1         ;load src data
418    vld1.u8         {d24}, [r0], r1
419    vld1.u8         {d25}, [r0], r1
420    vld1.u8         {d26}, [r0], r1
421
422    vmull.u8        q3, d18, d0             ;(src_ptr[-2] * vp8_filter[0])
423    vmull.u8        q4, d19, d0
424    vmull.u8        q5, d20, d0
425    vmull.u8        q6, d21, d0
426
427    vmlsl.u8        q3, d19, d1             ;-(src_ptr[-1] * vp8_filter[1])
428    vmlsl.u8        q4, d20, d1
429    vmlsl.u8        q5, d21, d1
430    vmlsl.u8        q6, d22, d1
431
432    vmlsl.u8        q3, d22, d4             ;-(src_ptr[2] * vp8_filter[4])
433    vmlsl.u8        q4, d23, d4
434    vmlsl.u8        q5, d24, d4
435    vmlsl.u8        q6, d25, d4
436
437    vmlal.u8        q3, d20, d2             ;(src_ptr[0] * vp8_filter[2])
438    vmlal.u8        q4, d21, d2
439    vmlal.u8        q5, d22, d2
440    vmlal.u8        q6, d23, d2
441
442    vmlal.u8        q3, d23, d5             ;(src_ptr[3] * vp8_filter[5])
443    vmlal.u8        q4, d24, d5
444    vmlal.u8        q5, d25, d5
445    vmlal.u8        q6, d26, d5
446
447    vmull.u8        q7, d21, d3             ;(src_ptr[1] * vp8_filter[3])
448    vmull.u8        q8, d22, d3
449    vmull.u8        q9, d23, d3
450    vmull.u8        q10, d24, d3
451
452    subs            r12, r12, #1
453
454    vqadd.s16       q7, q3                  ;sum of all (src_data*filter_parameters)
455    vqadd.s16       q8, q4
456    vqadd.s16       q9, q5
457    vqadd.s16       q10, q6
458
459    vqrshrun.s16    d6, q7, #7              ;shift/round/saturate to u8
460    vqrshrun.s16    d7, q8, #7
461    vqrshrun.s16    d8, q9, #7
462    vqrshrun.s16    d9, q10, #7
463
464    vst1.u8         {d6}, [r4], r5          ;store result
465    vmov            q9, q11
466    vst1.u8         {d7}, [r4], r5
467    vmov            q10, q12
468    vst1.u8         {d8}, [r4], r5
469    vmov            d22, d26
470    vst1.u8         {d9}, [r4], r5
471
472    bne             secondpass_only_inner_loop_neon
473
474    subs            r3, r3, #1
475    sub             r0, r0, r1, lsl #4
476    sub             r0, r0, r1, lsl #2
477    sub             r0, r0, r1
478    add             r0, r0, #8
479
480    sub             r4, r4, r5, lsl #4
481    add             r4, r4, #8
482
483    bne filt_blk2d_spo16x16_outloop_neon
484
485    pop             {r4-r5,pc}
486
487    ENDP
488
489;-----------------
490    END
491