1 /*****************************************************************************
2 * mc.S: arm motion compensation
3 *****************************************************************************
4 * Copyright (C) 2009-2014 x264 project
6 * Authors: David Conrad <lessen42@gmail.com>
7 * Mans Rullgard <mans@mansr.com>
8 * Stefan Groenroos <stefan.gronroos@gmail.com>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
24 * This program is also available under a commercial proprietary license.
25 * For more information, contact us at licensing@x264.com.
26 *****************************************************************************/
33 // note: prefetch stuff assumes 64-byte cacheline, true for the Cortex-A8
34 // They also use nothing above armv5te, but we don't care about pre-armv6
36 // void prefetch_ref( uint8_t *pix, intptr_t stride, int parity )
37 function x264_prefetch_ref_arm
41 add r0, r0, r2, lsl #3
42 add r2, r1, r1, lsl #1
46 add r3, r0, r1, lsl #2
55 // void prefetch_fenc( uint8_t *pix_y, intptr_t stride_y,
56 // uint8_t *pix_uv, intptr_t stride_uv, int mb_x )
57 function x264_prefetch_fenc_arm
61 smulbb lr, lr, r1 // note: this assumes stride_y is <= 16 bits signed
66 add r0, r0, lr, lsl #2
68 add lr, r0, r1, lsl #1
71 add r2, r2, ip, lsl #2
74 add ip, r2, r3, lsl #1
82 // void *x264_memcpy_aligned( void *dst, const void *src, size_t n )
83 function x264_memcpy_aligned_neon
84 orr r3, r0, r1, lsr #1
85 movrel ip, memcpy_table
90 .macro MEMCPY_ALIGNED srcalign dstalign
91 function memcpy_aligned_\dstalign\()_\srcalign\()_neon, export=0
93 .if \srcalign == 8 && \dstalign == 8
95 vld1.64 {d0}, [r1,:64]!
96 vst1.64 {d0}, [r3,:64]!
100 .set r1align, \srcalign * 8
101 .set r3align, \dstalign * 8
106 vld1.64 {d0-d1}, [r1,:r1align]!
107 vst1.64 {d0-d1}, [r3,:r3align]!
108 32: // n is a multiple of 32
112 vld1.64 {d0-d3}, [r1,:r1align]!
113 vst1.64 {d0-d3}, [r3,:r3align]!
114 640: // n is a multiple of 64
119 vld1.64 {d0-d3}, [r1,:r1align]!
120 vld1.64 {d4-d7}, [r1,:r1align]!
121 vst1.64 {d0-d3}, [r3,:r3align]!
122 vst1.64 {d4-d7}, [r3,:r3align]!
125 .if \srcalign == 8 && \dstalign == 8
126 vld1.64 {d0}, [r1,:64]!
127 vst1.64 {d0}, [r3,:64]!
133 MEMCPY_ALIGNED 16, 16
140 .word memcpy_aligned_16_16_neon
141 .word memcpy_aligned_16_8_neon
142 .word memcpy_aligned_8_16_neon
143 .word memcpy_aligned_8_8_neon
148 // void x264_memzero_aligned( void *dst, size_t n )
149 function x264_memzero_aligned_neon
155 vst1.64 {d0-d3}, [r0,:128]!
162 // void pixel_avg( uint8_t *dst, intptr_t dst_stride,
163 // uint8_t *src1, intptr_t src1_stride,
164 // uint8_t *src2, intptr_t src2_stride, int weight );
166 function x264_pixel_avg_\w\()x\h\()_neon
170 ldrd r4, r5, [sp, #16]
172 beq x264_pixel_avg_w\w\()_neon
174 blt x264_pixel_avg_weight_w\w\()_add_sub_neon // weight > 64
176 bge x264_pixel_avg_weight_w\w\()_add_add_neon
177 b x264_pixel_avg_weight_w\w\()_sub_add_neon // weight < 0
192 .macro load_weights_add_add
197 .macro load_add_add d1 d2
198 vld1.32 {\d1}, [r2], r3
199 vld1.32 {\d2}, [r4], r5
202 .macro weight_add_add dst s1 s2
203 vmull.u8 \dst, \s1, d30
204 vmlal.u8 \dst, \s2, d31
208 .macro load_weights_add_sub
214 .macro load_add_sub d1 d2
215 vld1.32 {\d1}, [r2], r3
216 vld1.32 {\d2}, [r4], r5
219 .macro weight_add_sub dst s1 s2
220 vmull.u8 \dst, \s1, d30
221 vmlsl.u8 \dst, \s2, d31
225 .macro load_weights_sub_add
231 .macro load_sub_add d1 d2
232 vld1.32 {\d2}, [r4], r5
233 vld1.32 {\d1}, [r2], r3
236 .macro weight_sub_add dst s1 s2
237 vmull.u8 \dst, \s2, d31
238 vmlsl.u8 \dst, \s1, d30
241 .macro AVG_WEIGHT ext
242 function x264_pixel_avg_weight_w4_\ext\()_neon, export=0
247 weight_\ext q8, d0, d1
249 vqrshrun.s16 d0, q8, #6
250 weight_\ext q9, d2, d3
251 vst1.32 {d0[0]}, [r0,:32], r1
252 vqrshrun.s16 d1, q9, #6
253 vst1.32 {d1[0]}, [r0,:32], r1
258 function x264_pixel_avg_weight_w8_\ext\()_neon, export=0
263 weight_\ext q8, d0, d1
265 weight_\ext q9, d2, d3
267 weight_\ext q10, d4, d5
269 weight_\ext q11, d6, d7
270 vqrshrun.s16 d0, q8, #6
271 vqrshrun.s16 d1, q9, #6
272 vqrshrun.s16 d2, q10, #6
273 vqrshrun.s16 d3, q11, #6
274 vst1.64 {d0}, [r0,:64], r1
275 vst1.64 {d1}, [r0,:64], r1
276 vst1.64 {d2}, [r0,:64], r1
277 vst1.64 {d3}, [r0,:64], r1
282 function x264_pixel_avg_weight_w16_\ext\()_neon, export=0
286 load_\ext d0-d1, d2-d3
287 weight_\ext q8, d0, d2
288 weight_\ext q9, d1, d3
289 load_\ext d4-d5, d6-d7
290 weight_\ext q10, d4, d6
291 weight_\ext q11, d5, d7
292 vqrshrun.s16 d0, q8, #6
293 vqrshrun.s16 d1, q9, #6
294 vqrshrun.s16 d2, q10, #6
295 vqrshrun.s16 d3, q11, #6
296 vst1.64 {d0-d1}, [r0,:128], r1
297 vst1.64 {d2-d3}, [r0,:128], r1
307 function x264_pixel_avg_w4_neon, export=0
309 vld1.32 {d0[]}, [r2], r3
310 vld1.32 {d2[]}, [r4], r5
312 vld1.32 {d1[]}, [r2], r3
313 vld1.32 {d3[]}, [r4], r5
315 vst1.32 {d0[0]}, [r0,:32], r1
316 vst1.32 {d1[0]}, [r0,:32], r1
317 bgt x264_pixel_avg_w4_neon
321 function x264_pixel_avg_w8_neon, export=0
323 vld1.64 {d0}, [r2], r3
324 vld1.64 {d2}, [r4], r5
326 vld1.64 {d1}, [r2], r3
327 vld1.64 {d3}, [r4], r5
329 vst1.64 {d0}, [r0,:64], r1
330 vld1.64 {d2}, [r2], r3
331 vld1.64 {d4}, [r4], r5
333 vst1.64 {d1}, [r0,:64], r1
334 vld1.64 {d3}, [r2], r3
335 vld1.64 {d5}, [r4], r5
337 vst1.64 {d2}, [r0,:64], r1
338 vst1.64 {d3}, [r0,:64], r1
339 bgt x264_pixel_avg_w8_neon
343 function x264_pixel_avg_w16_neon, export=0
345 vld1.64 {d0-d1}, [r2], r3
346 vld1.64 {d2-d3}, [r4], r5
348 vld1.64 {d2-d3}, [r2], r3
349 vld1.64 {d4-d5}, [r4], r5
351 vst1.64 {d0-d1}, [r0,:128], r1
352 vld1.64 {d4-d5}, [r2], r3
353 vld1.64 {d6-d7}, [r4], r5
355 vst1.64 {d2-d3}, [r0,:128], r1
356 vld1.64 {d6-d7}, [r2], r3
357 vld1.64 {d0-d1}, [r4], r5
359 vst1.64 {d4-d5}, [r0,:128], r1
360 vst1.64 {d6-d7}, [r0,:128], r1
361 bgt x264_pixel_avg_w16_neon
366 function x264_pixel_avg2_w4_neon
372 vld1.32 {d0[]}, [r2], r3
373 vld1.32 {d2[]}, [lr], r3
375 vld1.32 {d1[]}, [r2], r3
376 vld1.32 {d3[]}, [lr], r3
378 vst1.32 {d0[0]}, [r0,:32], r1
379 vst1.32 {d1[0]}, [r0,:32], r1
384 function x264_pixel_avg2_w8_neon
390 vld1.64 {d0}, [r2], r3
391 vld1.64 {d2}, [lr], r3
393 vld1.64 {d1}, [r2], r3
394 vld1.64 {d3}, [lr], r3
396 vst1.64 {d0}, [r0,:64], r1
397 vst1.64 {d1}, [r0,:64], r1
402 function x264_pixel_avg2_w16_neon
408 vld1.64 {d0-d1}, [r2], r3
409 vld1.64 {d2-d3}, [lr], r3
411 vld1.64 {d4-d5}, [r2], r3
412 vld1.64 {d6-d7}, [lr], r3
414 vst1.64 {d0-d1}, [r0,:128], r1
415 vst1.64 {d4-d5}, [r0,:128], r1
420 function x264_pixel_avg2_w20_neon
427 vld1.64 {d0-d2}, [r2], r3
428 vld1.64 {d4-d6}, [lr], r3
431 vld1.64 {d4-d6}, [r2], r3
432 vld1.64 {d16-d18},[lr], r3
434 vst1.64 {d0-d1}, [r0,:128]!
435 vrhadd.u8 d6, d6, d18
436 vst1.32 {d2[0]}, [r0,:32], r1
437 vst1.64 {d4-d5}, [r0,:128]!
438 vst1.32 {d6[0]}, [r0,:32], r1
444 .macro weight_prologue type
446 ldr r4, [sp, #4*3] // weight_t
447 ldr ip, [sp, #4*3+4] // h
449 ldr lr, [r4, #32] // denom
451 ldrd r4, r5, [r4, #32+4] // scale, offset
460 // void mc_weight( uint8_t *src, intptr_t src_stride, uint8_t *dst, intptr_t dst_stride,
461 // const x264_weight_t *weight, int height )
462 function x264_mc_weight_w20_neon
467 vld1.8 {d17-d19}, [r2], r3
471 vld1.8 {d16-d18}, [r2], r3
475 vmul.s16 q10, q10, q0
476 vmul.s16 q11, q11, q0
477 vmul.s16 q12, q12, q0
478 vmul.s16 q13, q13, q0
479 vmul.s16 d28, d28, d0
480 vmul.s16 d29, d30, d0
481 vrshl.s16 q10, q10, q2
482 vrshl.s16 q11, q11, q2
483 vrshl.s16 q12, q12, q2
484 vrshl.s16 q13, q13, q2
485 vrshl.s16 q14, q14, q2
486 vadd.s16 q10, q10, q1
487 vadd.s16 q11, q11, q1
488 vadd.s16 q12, q12, q1
489 vadd.s16 q13, q13, q1
490 vadd.s16 q14, q14, q1
496 vst1.8 {d16-d17}, [r0,:128]!
497 vst1.32 {d20[0]}, [r0,:32], r1
498 vst1.8 {d18-d19}, [r0,:128]!
499 vst1.32 {d20[1]}, [r0,:32], r1
504 function x264_mc_weight_w16_neon
508 vld1.8 {d16-d17}, [r2], r3
509 vld1.8 {d18-d19}, [r2], r3
514 vmul.s16 q10, q10, q0
515 vmul.s16 q11, q11, q0
516 vmul.s16 q12, q12, q0
517 vmul.s16 q13, q13, q0
518 vrshl.s16 q10, q10, q2
519 vrshl.s16 q11, q11, q2
520 vrshl.s16 q12, q12, q2
521 vrshl.s16 q13, q13, q2
522 vadd.s16 q10, q10, q1
523 vadd.s16 q11, q11, q1
524 vadd.s16 q12, q12, q1
525 vadd.s16 q13, q13, q1
530 vst1.8 {d16-d17}, [r0,:128], r1
531 vst1.8 {d18-d19}, [r0,:128], r1
536 function x264_mc_weight_w8_neon
540 vld1.8 {d16}, [r2], r3
541 vld1.8 {d18}, [r2], r3
552 vst1.8 {d16}, [r0,:64], r1
553 vst1.8 {d18}, [r0,:64], r1
558 function x264_mc_weight_w4_neon
562 vld1.32 {d16[]}, [r2], r3
563 vld1.32 {d18[]}, [r2], r3
566 vmul.s16 d16, d16, d0
567 vmul.s16 d17, d18, d0
571 vst1.32 {d16[0]}, [r0,:32], r1
572 vst1.32 {d16[1]}, [r0,:32], r1
577 function x264_mc_weight_w20_nodenom_neon
578 weight_prologue nodenom
580 weight20_nodenom_loop:
582 vld1.8 {d17-d19}, [r2], r3
586 vld1.8 {d16-d18}, [r2], r3
596 vmla.s16 q10, q12, q0
597 vmla.s16 q11, q13, q0
599 vmla.s16 d24, d28, d0
600 vmla.s16 d25, d30, d0
606 vst1.8 {d16-d17}, [r0,:128]!
607 vst1.32 {d20[0]}, [r0,:32], r1
608 vst1.8 {d18-d19}, [r0,:128]!
609 vst1.32 {d20[1]}, [r0,:32], r1
610 bgt weight20_nodenom_loop
614 function x264_mc_weight_w16_nodenom_neon
615 weight_prologue nodenom
616 weight16_nodenom_loop:
618 vld1.8 {d16-d17}, [r2], r3
619 vld1.8 {d18-d19}, [r2], r3
630 vmla.s16 q10, q14, q0
631 vmla.s16 q11, q15, q0
636 vst1.8 {d16-d17}, [r0,:128], r1
637 vst1.8 {d18-d19}, [r0,:128], r1
638 bgt weight16_nodenom_loop
642 function x264_mc_weight_w8_nodenom_neon
643 weight_prologue nodenom
644 weight8_nodenom_loop:
646 vld1.8 {d16}, [r2], r3
647 vld1.8 {d18}, [r2], r3
656 vst1.8 {d16}, [r0,:64], r1
657 vst1.8 {d17}, [r0,:64], r1
658 bgt weight8_nodenom_loop
662 function x264_mc_weight_w4_nodenom_neon
663 weight_prologue nodenom
664 weight4_nodenom_loop:
666 vld1.32 {d16[]}, [r2], r3
667 vld1.32 {d18[]}, [r2], r3
671 vmla.s16 d20, d16, d0
672 vmla.s16 d21, d18, d0
674 vst1.32 {d16[0]}, [r0,:32], r1
675 vst1.32 {d16[1]}, [r0,:32], r1
676 bgt weight4_nodenom_loop
680 .macro weight_simple_prologue
682 ldr lr, [sp, #4] // weight_t
683 ldr ip, [sp, #8] // h
684 ldr lr, [lr] // offset
688 .macro weight_simple name op
689 function x264_mc_weight_w20_\name\()_neon
690 weight_simple_prologue
691 weight20_\name\()_loop:
693 vld1.8 {d16-d18}, [r2], r3
694 vld1.8 {d19-d21}, [r2], r3
698 vst1.8 {d16-d18}, [r0,:64], r1
699 vst1.8 {d19-d21}, [r0,:64], r1
700 bgt weight20_\name\()_loop
704 function x264_mc_weight_w16_\name\()_neon
705 weight_simple_prologue
706 weight16_\name\()_loop:
708 vld1.8 {d16-d17}, [r2], r3
709 vld1.8 {d18-d19}, [r2], r3
712 vst1.8 {d16-d17}, [r0,:128], r1
713 vst1.8 {d18-d19}, [r0,:128], r1
714 bgt weight16_\name\()_loop
718 function x264_mc_weight_w8_\name\()_neon
719 weight_simple_prologue
720 weight8_\name\()_loop:
722 vld1.8 {d16}, [r2], r3
723 vld1.8 {d17}, [r2], r3
725 vst1.8 {d16}, [r0,:64], r1
726 vst1.8 {d17}, [r0,:64], r1
727 bgt weight8_\name\()_loop
731 function x264_mc_weight_w4_\name\()_neon
732 weight_simple_prologue
733 weight4_\name\()_loop:
735 vld1.32 {d16[]}, [r2], r3
736 vld1.32 {d17[]}, [r2], r3
738 vst1.32 {d16[0]}, [r0,:32], r1
739 vst1.32 {d17[0]}, [r0,:32], r1
740 bgt weight4_\name\()_loop
745 weight_simple offsetadd, vqadd.u8
746 weight_simple offsetsub, vqsub.u8
749 // void mc_copy( uint8_t *dst, intptr_t dst_stride, uint8_t *src, intptr_t src_stride, int height )
750 function x264_mc_copy_w4_neon
754 vld1.32 {d0[]}, [r2], r3
755 vld1.32 {d1[]}, [r2], r3
756 vld1.32 {d2[]}, [r2], r3
757 vld1.32 {d3[]}, [r2], r3
758 vst1.32 {d0[0]}, [r0,:32], r1
759 vst1.32 {d1[0]}, [r0,:32], r1
760 vst1.32 {d2[0]}, [r0,:32], r1
761 vst1.32 {d3[0]}, [r0,:32], r1
766 function x264_mc_copy_w8_neon
770 vld1.32 {d0}, [r2], r3
771 vld1.32 {d1}, [r2], r3
772 vld1.32 {d2}, [r2], r3
773 vld1.32 {d3}, [r2], r3
774 vst1.32 {d0}, [r0,:64], r1
775 vst1.32 {d1}, [r0,:64], r1
776 vst1.32 {d2}, [r0,:64], r1
777 vst1.32 {d3}, [r0,:64], r1
782 function x264_mc_copy_w16_neon
786 vld1.32 {d0-d1}, [r2], r3
787 vld1.32 {d2-d3}, [r2], r3
788 vld1.32 {d4-d5}, [r2], r3
789 vld1.32 {d6-d7}, [r2], r3
790 vst1.32 {d0-d1}, [r0,:128], r1
791 vst1.32 {d2-d3}, [r0,:128], r1
792 vst1.32 {d4-d5}, [r0,:128], r1
793 vst1.32 {d6-d7}, [r0,:128], r1
798 function x264_mc_copy_w16_aligned_neon
800 copy_w16_aligned_loop:
802 vld1.32 {d0-d1}, [r2,:128], r3
803 vld1.32 {d2-d3}, [r2,:128], r3
804 vld1.32 {d4-d5}, [r2,:128], r3
805 vld1.32 {d6-d7}, [r2,:128], r3
806 vst1.32 {d0-d1}, [r0,:128], r1
807 vst1.32 {d2-d3}, [r0,:128], r1
808 vst1.32 {d4-d5}, [r0,:128], r1
809 vst1.32 {d6-d7}, [r0,:128], r1
810 bgt copy_w16_aligned_loop
815 // void x264_mc_chroma_neon( uint8_t *dst, intptr_t i_dst_stride,
816 // uint8_t *src, intptr_t i_src_stride,
817 // int dx, int dy, int i_width, int i_height );
819 function x264_mc_chroma_neon
822 ldrd r4, r5, [sp, #56]
823 ldrd r6, r7, [sp, #64]
827 add r3, r3, r5, asr #2
842 .macro CHROMA_MC_START r00, r01, r10, r11
844 rsb r7, lr, r6, lsl #3
845 rsb ip, lr, r5, lsl #3
846 sub r5, lr, r5, lsl #3
847 sub r5, r5, r6, lsl #3
851 vld2.8 {\r00-\r01}, [r3], r4
857 vld2.8 {\r10-\r11}, [r3], r4
862 .macro CHROMA_MC width, align
864 CHROMA_MC_START d4, d5, d8, d9
865 vext.8 d6, d4, d6, #1
866 vext.8 d7, d5, d7, #1
867 vext.8 d10, d8, d10, #1
868 vext.8 d11, d9, d11, #1
869 // since the element size varies, there's a different index for the 2nd store
884 1: // height loop, interpolate xy
891 vld2.8 {d4-d5}, [r3], r4
893 vext.8 d6, d4, d6, #1
894 vext.8 d7, d5, d7, #1
896 vadd.i16 d16, d16, d17
897 vadd.i16 d17, d18, d19
907 vld2.8 {d8-d9}, [r3], r4
909 vrshrn.u16 d16, q8, #6
911 vext.8 d10, d8, d10, #1
912 vext.8 d11, d9, d11, #1
914 vadd.i16 d18, d20, d21
915 vadd.i16 d19, d22, d23
920 vrshrn.u16 d18, q9, #6
927 vst1.\align {d16[0]}, [r0,:\align], r2
928 vst1.\align {d16[st2]}, [r1,:\align], r2
929 vst1.\align {d18[0]}, [r0,:\align], r2
930 vst1.\align {d18[st2]}, [r1,:\align], r2
945 vld1.64 {d4}, [r3], r4
946 vld1.64 {d6}, [r3], r4
948 3: // vertical interpolation loop
953 vld1.64 {d4}, [r3], r4
955 vld1.64 {d6}, [r3], r4
957 vrshrn.u16 d16, q8, #6 // uvuvuvuv
958 vrshrn.u16 d17, q9, #6 // uvuvuvuv
960 vuzp.8 d16, d17 // d16=uuuu|uuuu, d17=vvvv|vvvv
965 vst1.\align {d16[0]}, [r0,:\align], r2
966 vst1.\align {d16[st2]}, [r0,:\align], r2
967 vst1.\align {d17[0]}, [r1,:\align], r2
968 vst1.\align {d17[st2]}, [r1,:\align], r2
976 vld1.64 {d4-d5}, [r3], r4
977 vld1.64 {d6-d7}, [r3], r4
979 vext.8 d5, d4, d5, #2
980 vext.8 d7, d6, d7, #2
982 5: // horizontal interpolation loop
990 vld1.64 {d4-d5}, [r3], r4
991 vld1.64 {d6-d7}, [r3], r4
992 vext.8 d5, d4, d5, #2
993 vrshrn.u16 d16, q8, #6
994 vrshrn.u16 d17, q9, #6
995 vext.8 d7, d6, d7, #2
1001 vst1.\align {d16[0]}, [r0,:\align], r2
1002 vst1.\align {d16[st2]}, [r0,:\align], r2
1003 vst1.\align {d17[0]}, [r1,:\align], r2
1004 vst1.\align {d17[st2]}, [r1,:\align], r2
1015 CHROMA_MC_START d4, d7, d8, d11
1016 vext.8 d5, d4, d5, #1
1017 vext.8 d9, d8, d9, #1
1018 vext.8 d7, d6, d7, #1
1019 vext.8 d11, d10, d11, #1
1021 1: // height loop, interpolate xy
1029 vmlal.u8 q9, d10, d2
1030 vmlal.u8 q9, d11, d3
1032 vld2.8 {d4-d7}, [r3], r4
1034 vext.8 d5, d4, d5, #1
1035 vext.8 d7, d6, d7, #1
1037 vmull.u8 q10, d8, d0
1038 vmlal.u8 q10, d9, d1
1039 vmlal.u8 q10, d4, d2
1040 vmlal.u8 q10, d5, d3
1042 vmull.u8 q11, d10, d0
1043 vmlal.u8 q11, d11, d1
1044 vmlal.u8 q11, d6, d2
1045 vmlal.u8 q11, d7, d3
1048 vld2.8 {d8-d11}, [r3], r4
1050 vrshrn.u16 d16, q8, #6
1051 vrshrn.u16 d17, q9, #6
1052 vrshrn.u16 d18, q10, #6
1053 vext.8 d9, d8, d9, #1
1054 vrshrn.u16 d19, q11, #6
1055 vext.8 d11, d10, d11, #1
1060 vst1.64 {d16}, [r0,:64], r2
1061 vst1.64 {d17}, [r1,:64], r2
1062 vst1.64 {d18}, [r0,:64], r2
1063 vst1.64 {d19}, [r1,:64], r2
1070 2: // dx or dy are 0
1079 vld2.8 {d4-d5}, [r3], r4
1080 vld2.8 {d6-d7}, [r3], r4
1082 3: // vertical interpolation loop
1083 vmull.u8 q8, d4, d0 //U
1085 vmull.u8 q9, d5, d0 //V
1088 vld2.8 {d4-d5}, [r3], r4
1090 vmull.u8 q10, d6, d0
1091 vmlal.u8 q10, d4, d1
1092 vmull.u8 q11, d7, d0
1093 vmlal.u8 q11, d5, d1
1095 vld2.8 {d6-d7}, [r3], r4
1097 vrshrn.u16 d16, q8, #6
1098 vrshrn.u16 d17, q9, #6
1099 vrshrn.u16 d18, q10, #6
1100 vrshrn.u16 d19, q11, #6
1106 vst1.64 {d16}, [r0,:64], r2
1107 vst1.64 {d17}, [r1,:64], r2
1108 vst1.64 {d18}, [r0,:64], r2
1109 vst1.64 {d19}, [r1,:64], r2
1118 vld2.8 {d4-d7}, [r3], r4
1119 vld2.8 {d8-d11}, [r3], r4
1120 vext.8 d5, d4, d5, #1
1121 vext.8 d7, d6, d7, #1
1122 vext.8 d9, d8, d9, #1
1123 vext.8 d11, d10, d11, #1
1125 5: // horizontal interpolation loop
1127 vmull.u8 q8, d4, d0 //U
1129 vmull.u8 q9, d6, d0 //V
1132 vld2.8 {d4-d7}, [r3], r4
1134 vmull.u8 q10, d8, d0
1135 vmlal.u8 q10, d9, d1
1136 vmull.u8 q11, d10, d0
1137 vmlal.u8 q11, d11, d1
1139 vld2.8 {d8-d11}, [r3], r4
1141 vext.8 d5, d4, d5, #1
1142 vrshrn.u16 d16, q8, #6
1143 vext.8 d7, d6, d7, #1
1144 vrshrn.u16 d17, q9, #6
1145 vext.8 d9, d8, d9, #1
1146 vrshrn.u16 d18, q10, #6
1147 vext.8 d11, d10, d11, #1
1148 vrshrn.u16 d19, q11, #6
1153 vst1.64 {d16}, [r0,:64], r2
1154 vst1.64 {d17}, [r1,:64], r2
1155 vst1.64 {d18}, [r0,:64], r2
1156 vst1.64 {d19}, [r1,:64], r2
1165 // hpel_filter_v( uint8_t *dst, uint8_t *src, int16_t *buf, intptr_t stride, int width )
1166 function x264_hpel_filter_v_neon
1168 sub r1, r1, r3, lsl #1
1176 vld1.64 {d0-d1}, [r1,:128], r3
1177 vld1.64 {d2-d3}, [r1,:128], r3
1178 vld1.64 {d4-d5}, [r1,:128], r3
1179 vld1.64 {d6-d7}, [r1,:128], r3
1180 vld1.64 {d16-d17}, [r1,:128], r3
1181 vld1.64 {d18-d19}, [r1,:128], r3
1184 vaddl.u8 q10, d0, d18
1185 vmlsl.u8 q10, d2, d30
1186 vmlal.u8 q10, d4, d31
1187 vmlal.u8 q10, d6, d31
1188 vmlsl.u8 q10, d16, d30
1190 vaddl.u8 q11, d1, d19
1191 vmlsl.u8 q11, d3, d30
1192 vmlal.u8 q11, d5, d31
1193 vmlal.u8 q11, d7, d31
1194 vmlsl.u8 q11, d17, d30
1196 vqrshrun.s16 d0, q10, #5
1197 vst1.64 {d20-d21}, [r2,:128]!
1198 vqrshrun.s16 d1, q11, #5
1199 vst1.64 {d22-d23}, [r2,:128]!
1200 vst1.64 {d0-d1}, [r0,:128]!
1205 // hpel_filter_c( uint8_t *dst, int16_t *buf, int width );
1206 function x264_hpel_filter_c_neon
1208 vld1.64 {d0-d3}, [r1,:128]!
1210 // unrolled 2x: 4% faster
1213 vld1.64 {d4-d7}, [r1,:128]!
1214 vext.16 q8, q0, q1, #6
1215 vext.16 q12, q1, q2, #3
1216 vadd.s16 q8, q8, q12
1217 vext.16 q9, q0, q1, #7
1218 vext.16 q11, q1, q2, #2
1219 vadd.s16 q9, q9, q11
1220 vext.16 q10, q1, q2, #1
1221 vext.16 q11, q1, q2, #6
1222 vadd.s16 q10, q1, q10
1223 vsub.s16 q8, q8, q9 // a-b
1224 vext.16 q15, q2, q3, #3
1225 vsub.s16 q9, q9, q10 // b-c
1227 vext.16 q12, q1, q2, #7
1228 vshr.s16 q8, q8, #2 // (a-b)/4
1229 vadd.s16 q11, q11, q15
1230 vext.16 q14, q2, q3, #2
1231 vsub.s16 q8, q8, q9 // (a-b)/4-b+c
1232 vadd.s16 q12, q12, q14
1233 vext.16 q13, q2, q3, #1
1235 vshr.s16 q8, q8, #2 // ((a-b)/4-b+c)/4
1236 vadd.s16 q13, q2, q13
1237 vadd.s16 q8, q8, q10 // ((a-b)/4-b+c)/4+c = (a-5*b+20*c)/16
1238 vsub.s16 q11, q11, q12 // a-b
1239 vsub.s16 q12, q12, q13 // b-c
1240 vshr.s16 q11, q11, #2 // (a-b)/4
1241 vqrshrun.s16 d30, q8, #6
1242 vsub.s16 q11, q11, q12 // (a-b)/4-b+c
1243 vshr.s16 q11, q11, #2 // ((a-b)/4-b+c)/4
1244 vld1.64 {d0-d3}, [r1,:128]!
1245 vadd.s16 q11, q11, q13 // ((a-b)/4-b+c)/4+c = (a-5*b+20*c)/16
1247 vext.16 q8, q2, q3, #6
1248 vqrshrun.s16 d31, q11, #6
1249 vext.16 q12, q3, q0, #3
1250 vadd.s16 q8, q8, q12
1251 vext.16 q9, q2, q3, #7
1252 vst1.64 {d30-d31}, [r0,:128]!
1256 vext.16 q11, q3, q0, #2
1257 vadd.s16 q9, q9, q11
1258 vext.16 q10, q3, q0, #1
1259 vext.16 q11, q3, q0, #6
1260 vadd.s16 q10, q3, q10
1261 vsub.s16 q8, q8, q9 // a-b
1262 vext.16 q15, q0, q1, #3
1263 vsub.s16 q9, q9, q10 // b-c
1265 vext.16 q12, q3, q0, #7
1266 vshr.s16 q8, q8, #2 // (a-b)/4
1267 vadd.s16 q11, q11, q15
1268 vext.16 q14, q0, q1, #2
1269 vsub.s16 q8, q8, q9 // (a-b)/4-b+c
1270 vadd.s16 q12, q12, q14
1271 vext.16 q13, q0, q1, #1
1273 vshr.s16 q8, q8, #2 // ((a-b)/4-b+c)/4
1274 vadd.s16 q13, q0, q13
1275 vadd.s16 q8, q8, q10 // ((a-b)/4-b+c)/4+c = (a-5*b+20*c)/16
1276 vsub.s16 q11, q11, q12 // a-b
1277 vsub.s16 q12, q12, q13 // b-c
1278 vshr.s16 q11, q11, #2 // (a-b)/4
1279 vqrshrun.s16 d30, q8, #6
1280 vsub.s16 q11, q11, q12 // (a-b)/4-b+c
1281 vshr.s16 q11, q11, #2 // ((a-b)/4-b+c)/4
1282 vadd.s16 q11, q11, q13 // ((a-b)/4-b+c)/4+c = (a-5*b+20*c)/16
1284 vqrshrun.s16 d31, q11, #6
1285 vst1.64 {d30-d31}, [r0,:128]!
1290 // hpel_filter_h( uint8_t *dst, uint8_t *src, int width );
1291 function x264_hpel_filter_h_neon
1294 vld1.64 {d0-d3}, [r1,:128]!
1297 // unrolled 3x because it's 5% faster, due to mitigating
1298 // the high latency of multiplication and vqrshrun
1301 vld1.64 {d4-d5}, [r1,:128]!
1302 vext.8 q8, q0, q1, #14
1303 vext.8 q12, q1, q2, #3
1304 vaddl.u8 q13, d16, d24
1305 vext.8 q9, q0, q1, #15
1306 vaddl.u8 q14, d17, d25
1308 vext.8 q10, q1, q2, #1
1309 vmlal.u8 q13, d2, d31
1310 vmlsl.u8 q13, d18, d30
1311 vext.8 q11, q1, q2, #2
1312 vmlal.u8 q13, d20, d31
1313 vmlsl.u8 q13, d22, d30
1315 vmlsl.u8 q14, d19, d30
1316 vmlal.u8 q14, d3, d31
1317 vmlal.u8 q14, d21, d31
1318 vmlsl.u8 q14, d23, d30
1319 vqrshrun.s16 d6, q13, #5
1321 vld1.64 {d0-d1}, [r1,:128]!
1322 vext.8 q8, q1, q2, #14
1323 vext.8 q12, q2, q0, #3
1324 vaddl.u8 q13, d16, d24
1325 vqrshrun.s16 d7, q14, #5
1326 vext.8 q9, q1, q2, #15
1327 vaddl.u8 q14, d17, d25
1329 vst1.64 {d6-d7}, [r0,:128]!
1333 vext.8 q10, q2, q0, #1
1334 vmlal.u8 q13, d4, d31
1335 vmlsl.u8 q13, d18, d30
1336 vext.8 q11, q2, q0, #2
1337 vmlal.u8 q13, d20, d31
1338 vmlsl.u8 q13, d22, d30
1340 vmlsl.u8 q14, d19, d30
1341 vmlal.u8 q14, d5, d31
1342 vmlal.u8 q14, d21, d31
1343 vmlsl.u8 q14, d23, d30
1344 vqrshrun.s16 d6, q13, #5
1346 vld1.64 {d2-d3}, [r1,:128]!
1347 vext.8 q8, q2, q0, #14
1348 vext.8 q12, q0, q1, #3
1349 vaddl.u8 q13, d16, d24
1350 vqrshrun.s16 d7, q14, #5
1351 vext.8 q9, q2, q0, #15
1352 vaddl.u8 q14, d17, d25
1354 vst1.64 {d6-d7}, [r0,:128]!
1358 vext.8 q10, q0, q1, #1
1359 vmlal.u8 q13, d0, d31
1360 vmlsl.u8 q13, d18, d30
1361 vext.8 q11, q0, q1, #2
1362 vmlal.u8 q13, d20, d31
1363 vmlsl.u8 q13, d22, d30
1365 vmlsl.u8 q14, d19, d30
1366 vmlal.u8 q14, d1, d31
1367 vmlal.u8 q14, d21, d31
1368 vmlsl.u8 q14, d23, d30
1370 vqrshrun.s16 d6, q13, #5
1371 vqrshrun.s16 d7, q14, #5
1372 vst1.64 {d6-d7}, [r0,:128]!
1378 // frame_init_lowres_core( uint8_t *src0, uint8_t *dst0, uint8_t *dsth, uint8_t *dstv,
1379 // uint8_t *dstc, intptr_t src_stride, intptr_t dst_stride, int width,
1381 function x264_frame_init_lowres_core_neon
1384 ldrd r4, r5, [sp, #96]
1385 ldrd r6, r7, [sp, #104]
1387 sub r10, r6, r7 // dst_stride - width
1393 add r8, r0, r5 // src1 = src0 + src_stride
1394 add r9, r0, r5, lsl #1 // src2 = src1 + src_stride
1396 vld2.8 {d8, d10}, [r6,:128]!
1397 vld2.8 {d12,d14}, [r8,:128]!
1398 vld2.8 {d16,d18}, [r9,:128]!
1403 vld2.8 {d9, d11}, [r6,:128]!
1404 vld2.8 {d13,d15}, [r8,:128]!
1405 vrhadd.u8 q0, q4, q6
1406 vld2.8 {d17,d19}, [r9,:128]!
1407 vrhadd.u8 q5, q5, q7
1408 vld2.8 {d20,d22}, [r6,:128]!
1409 vrhadd.u8 q1, q6, q8
1410 vld2.8 {d24,d26}, [r8,:128]!
1411 vrhadd.u8 q7, q7, q9
1412 vext.8 q4, q4, q10, #1
1413 vrhadd.u8 q0, q0, q5
1414 vext.8 q6, q6, q12, #1
1415 vrhadd.u8 q1, q1, q7
1416 vld2.8 {d28,d30}, [r9,:128]!
1417 vrhadd.u8 q4, q4, q6
1418 vext.8 q8, q8, q14, #1
1419 vrhadd.u8 q6, q6, q8
1420 vst1.64 {d0-d1}, [r1,:128]!
1421 vrhadd.u8 q2, q4, q5
1422 vst1.64 {d2-d3}, [r3,:128]!
1423 vrhadd.u8 q3, q6, q7
1424 vst1.64 {d4-d5}, [r2,:128]!
1425 vst1.64 {d6-d7}, [r4,:128]!
1427 ble lowres_xloop_end
1430 vld2.8 {d21,d23}, [r6,:128]!
1431 vld2.8 {d25,d27}, [r8,:128]!
1432 vrhadd.u8 q0, q10, q12
1433 vld2.8 {d29,d31}, [r9,:128]!
1434 vrhadd.u8 q11, q11, q13
1435 vld2.8 {d8, d10}, [r6,:128]!
1436 vrhadd.u8 q1, q12, q14
1437 vld2.8 {d12,d14}, [r8,:128]!
1438 vrhadd.u8 q13, q13, q15
1439 vext.8 q10, q10, q4, #1
1440 vrhadd.u8 q0, q0, q11
1441 vext.8 q12, q12, q6, #1
1442 vrhadd.u8 q1, q1, q13
1443 vld2.8 {d16,d18}, [r9,:128]!
1444 vrhadd.u8 q10, q10, q12
1445 vext.8 q14, q14, q8, #1
1446 vrhadd.u8 q12, q12, q14
1447 vst1.64 {d0-d1}, [r1,:128]!
1448 vrhadd.u8 q2, q10, q11
1449 vst1.64 {d2-d3}, [r3,:128]!
1450 vrhadd.u8 q3, q12, q13
1451 vst1.64 {d4-d5}, [r2,:128]!
1452 vst1.64 {d6-d7}, [r4,:128]!
1458 add r0, r0, r5, lsl #1
1469 function x264_load_deinterleave_chroma_fdec_neon
1470 mov ip, #FDEC_STRIDE/2
1472 vld2.8 {d0-d1}, [r1,:128], r2
1475 vst1.8 {d0}, [r0,:64], ip
1476 vst1.8 {d1}, [r0,:64], ip
1482 function x264_load_deinterleave_chroma_fenc_neon
1483 mov ip, #FENC_STRIDE/2
1485 vld2.8 {d0-d1}, [r1,:128], r2
1488 vst1.8 {d0}, [r0,:64], ip
1489 vst1.8 {d1}, [r0,:64], ip
1495 function x264_plane_copy_deinterleave_neon
1497 ldrd r6, r7, [sp, #28]
1498 ldrd r4, r5, [sp, #20]
1503 sub r5, r5, lr, lsl #1
1505 vld2.8 {d0-d3}, [r4,:128]!
1521 function x264_plane_copy_deinterleave_rgb_neon
1522 push {r4-r8, r10, r11, lr}
1523 ldrd r4, r5, [sp, #32]
1524 ldrd r6, r7, [sp, #40]
1526 ldrd r10, r11, [sp, #52]
1530 sub r7, r7, lr, lsl #1
1534 subne r7, r7, lr, lsl #1
1538 vld3.8 {d0,d1,d2}, [r6]!
1553 pop {r4-r8, r10, r11, pc}
1555 vld4.8 {d0,d1,d2,d3}, [r6]!
1570 pop {r4-r8, r10, r11, pc}
1573 function x264_plane_copy_interleave_neon
1575 ldrd r6, r7, [sp, #28]
1576 ldrd r4, r5, [sp, #20]
1579 sub r1, r1, lr, lsl #1
1586 vst2.8 {d0,d2}, [r0]!
1587 vst2.8 {d1,d3}, [r0]!
1600 function x264_store_interleave_chroma_neon
1603 mov ip, #FDEC_STRIDE
1605 vld1.8 {d0}, [r2], ip
1606 vld1.8 {d1}, [r3], ip
1608 vst2.8 {d0,d1}, [r0,:128], r1