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 *****************************************************************************/
32 // note: prefetch stuff assumes 64-byte cacheline, true for the Cortex-A8
33 // They also use nothing above armv5te, but we don't care about pre-armv6
35 // void prefetch_ref( uint8_t *pix, intptr_t stride, int parity )
36 function x264_prefetch_ref_arm
40 add r0, r0, r2, lsl #3
41 add r2, r1, r1, lsl #1
45 add r3, r0, r1, lsl #2
54 // void prefetch_fenc( uint8_t *pix_y, intptr_t stride_y,
55 // uint8_t *pix_uv, intptr_t stride_uv, int mb_x )
56 function x264_prefetch_fenc_arm
60 smulbb lr, lr, r1 // note: this assumes stride_y is <= 16 bits signed
65 add r0, r0, lr, lsl #2
67 add lr, r0, r1, lsl #1
70 add r2, r2, ip, lsl #2
73 add ip, r2, r3, lsl #1
81 // void *x264_memcpy_aligned( void *dst, const void *src, size_t n )
82 function x264_memcpy_aligned_neon
83 orr r3, r0, r1, lsr #1
84 movrel ip, memcpy_table
89 .macro MEMCPY_ALIGNED srcalign dstalign
90 function memcpy_aligned_\dstalign\()_\srcalign\()_neon, export=0
92 .if \srcalign == 8 && \dstalign == 8
94 vld1.64 {d0}, [r1,:64]!
95 vst1.64 {d0}, [r3,:64]!
99 .set r1align, \srcalign * 8
100 .set r3align, \dstalign * 8
105 vld1.64 {d0-d1}, [r1,:r1align]!
106 vst1.64 {d0-d1}, [r3,:r3align]!
107 32: // n is a multiple of 32
111 vld1.64 {d0-d3}, [r1,:r1align]!
112 vst1.64 {d0-d3}, [r3,:r3align]!
113 640: // n is a multiple of 64
118 vld1.64 {d0-d3}, [r1,:r1align]!
119 vld1.64 {d4-d7}, [r1,:r1align]!
120 vst1.64 {d0-d3}, [r3,:r3align]!
121 vst1.64 {d4-d7}, [r3,:r3align]!
124 .if \srcalign == 8 && \dstalign == 8
125 vld1.64 {d0}, [r1,:64]!
126 vst1.64 {d0}, [r3,:64]!
132 MEMCPY_ALIGNED 16, 16
139 .word memcpy_aligned_16_16_neon
140 .word memcpy_aligned_16_8_neon
141 .word memcpy_aligned_8_16_neon
142 .word memcpy_aligned_8_8_neon
147 // void x264_memzero_aligned( void *dst, size_t n )
148 function x264_memzero_aligned_neon
154 vst1.64 {d0-d3}, [r0,:128]!
161 // void pixel_avg( uint8_t *dst, intptr_t dst_stride,
162 // uint8_t *src1, intptr_t src1_stride,
163 // uint8_t *src2, intptr_t src2_stride, int weight );
165 function x264_pixel_avg_\w\()x\h\()_neon
169 ldrd r4, r5, [sp, #16]
171 beq x264_pixel_avg_w\w\()_neon
173 blt x264_pixel_avg_weight_w\w\()_add_sub_neon // weight > 64
175 bge x264_pixel_avg_weight_w\w\()_add_add_neon
176 b x264_pixel_avg_weight_w\w\()_sub_add_neon // weight < 0
191 .macro load_weights_add_add
196 .macro load_add_add d1 d2
197 vld1.32 {\d1}, [r2], r3
198 vld1.32 {\d2}, [r4], r5
201 .macro weight_add_add dst s1 s2
202 vmull.u8 \dst, \s1, d30
203 vmlal.u8 \dst, \s2, d31
207 .macro load_weights_add_sub
213 .macro load_add_sub d1 d2
214 vld1.32 {\d1}, [r2], r3
215 vld1.32 {\d2}, [r4], r5
218 .macro weight_add_sub dst s1 s2
219 vmull.u8 \dst, \s1, d30
220 vmlsl.u8 \dst, \s2, d31
224 .macro load_weights_sub_add
230 .macro load_sub_add d1 d2
231 vld1.32 {\d2}, [r4], r5
232 vld1.32 {\d1}, [r2], r3
235 .macro weight_sub_add dst s1 s2
236 vmull.u8 \dst, \s2, d31
237 vmlsl.u8 \dst, \s1, d30
240 .macro AVG_WEIGHT ext
241 function x264_pixel_avg_weight_w4_\ext\()_neon, export=0
246 weight_\ext q8, d0, d1
248 vqrshrun.s16 d0, q8, #6
249 weight_\ext q9, d2, d3
250 vst1.32 {d0[0]}, [r0,:32], r1
251 vqrshrun.s16 d1, q9, #6
252 vst1.32 {d1[0]}, [r0,:32], r1
257 function x264_pixel_avg_weight_w8_\ext\()_neon, export=0
262 weight_\ext q8, d0, d1
264 weight_\ext q9, d2, d3
266 weight_\ext q10, d4, d5
268 weight_\ext q11, d6, d7
269 vqrshrun.s16 d0, q8, #6
270 vqrshrun.s16 d1, q9, #6
271 vqrshrun.s16 d2, q10, #6
272 vqrshrun.s16 d3, q11, #6
273 vst1.64 {d0}, [r0,:64], r1
274 vst1.64 {d1}, [r0,:64], r1
275 vst1.64 {d2}, [r0,:64], r1
276 vst1.64 {d3}, [r0,:64], r1
281 function x264_pixel_avg_weight_w16_\ext\()_neon, export=0
285 load_\ext d0-d1, d2-d3
286 weight_\ext q8, d0, d2
287 weight_\ext q9, d1, d3
288 load_\ext d4-d5, d6-d7
289 weight_\ext q10, d4, d6
290 weight_\ext q11, d5, d7
291 vqrshrun.s16 d0, q8, #6
292 vqrshrun.s16 d1, q9, #6
293 vqrshrun.s16 d2, q10, #6
294 vqrshrun.s16 d3, q11, #6
295 vst1.64 {d0-d1}, [r0,:128], r1
296 vst1.64 {d2-d3}, [r0,:128], r1
306 function x264_pixel_avg_w4_neon, export=0
308 vld1.32 {d0[]}, [r2], r3
309 vld1.32 {d2[]}, [r4], r5
311 vld1.32 {d1[]}, [r2], r3
312 vld1.32 {d3[]}, [r4], r5
314 vst1.32 {d0[0]}, [r0,:32], r1
315 vst1.32 {d1[0]}, [r0,:32], r1
316 bgt x264_pixel_avg_w4_neon
320 function x264_pixel_avg_w8_neon, export=0
322 vld1.64 {d0}, [r2], r3
323 vld1.64 {d2}, [r4], r5
325 vld1.64 {d1}, [r2], r3
326 vld1.64 {d3}, [r4], r5
328 vst1.64 {d0}, [r0,:64], r1
329 vld1.64 {d2}, [r2], r3
330 vld1.64 {d4}, [r4], r5
332 vst1.64 {d1}, [r0,:64], r1
333 vld1.64 {d3}, [r2], r3
334 vld1.64 {d5}, [r4], r5
336 vst1.64 {d2}, [r0,:64], r1
337 vst1.64 {d3}, [r0,:64], r1
338 bgt x264_pixel_avg_w8_neon
342 function x264_pixel_avg_w16_neon, export=0
344 vld1.64 {d0-d1}, [r2], r3
345 vld1.64 {d2-d3}, [r4], r5
347 vld1.64 {d2-d3}, [r2], r3
348 vld1.64 {d4-d5}, [r4], r5
350 vst1.64 {d0-d1}, [r0,:128], r1
351 vld1.64 {d4-d5}, [r2], r3
352 vld1.64 {d6-d7}, [r4], r5
354 vst1.64 {d2-d3}, [r0,:128], r1
355 vld1.64 {d6-d7}, [r2], r3
356 vld1.64 {d0-d1}, [r4], r5
358 vst1.64 {d4-d5}, [r0,:128], r1
359 vst1.64 {d6-d7}, [r0,:128], r1
360 bgt x264_pixel_avg_w16_neon
365 function x264_pixel_avg2_w4_neon
371 vld1.32 {d0[]}, [r2], r3
372 vld1.32 {d2[]}, [lr], r3
374 vld1.32 {d1[]}, [r2], r3
375 vld1.32 {d3[]}, [lr], r3
377 vst1.32 {d0[0]}, [r0,:32], r1
378 vst1.32 {d1[0]}, [r0,:32], r1
383 function x264_pixel_avg2_w8_neon
389 vld1.64 {d0}, [r2], r3
390 vld1.64 {d2}, [lr], r3
392 vld1.64 {d1}, [r2], r3
393 vld1.64 {d3}, [lr], r3
395 vst1.64 {d0}, [r0,:64], r1
396 vst1.64 {d1}, [r0,:64], r1
401 function x264_pixel_avg2_w16_neon
407 vld1.64 {d0-d1}, [r2], r3
408 vld1.64 {d2-d3}, [lr], r3
410 vld1.64 {d4-d5}, [r2], r3
411 vld1.64 {d6-d7}, [lr], r3
413 vst1.64 {d0-d1}, [r0,:128], r1
414 vst1.64 {d4-d5}, [r0,:128], r1
419 function x264_pixel_avg2_w20_neon
426 vld1.64 {d0-d2}, [r2], r3
427 vld1.64 {d4-d6}, [lr], r3
430 vld1.64 {d4-d6}, [r2], r3
431 vld1.64 {d16-d18},[lr], r3
433 vst1.64 {d0-d1}, [r0,:128]!
434 vrhadd.u8 d6, d6, d18
435 vst1.32 {d2[0]}, [r0,:32], r1
436 vst1.64 {d4-d5}, [r0,:128]!
437 vst1.32 {d6[0]}, [r0,:32], r1
443 .macro weight_prologue type
445 ldr r4, [sp, #4*3] // weight_t
446 ldr ip, [sp, #4*3+4] // h
448 ldr lr, [r4, #32] // denom
450 ldrd r4, r5, [r4, #32+4] // scale, offset
459 // void mc_weight( uint8_t *src, intptr_t src_stride, uint8_t *dst, intptr_t dst_stride,
460 // const x264_weight_t *weight, int height )
461 function x264_mc_weight_w20_neon
466 vld1.8 {d17-d19}, [r2], r3
470 vld1.8 {d16-d18}, [r2], r3
474 vmul.s16 q10, q10, q0
475 vmul.s16 q11, q11, q0
476 vmul.s16 q12, q12, q0
477 vmul.s16 q13, q13, q0
478 vmul.s16 d28, d28, d0
479 vmul.s16 d29, d30, d0
480 vrshl.s16 q10, q10, q2
481 vrshl.s16 q11, q11, q2
482 vrshl.s16 q12, q12, q2
483 vrshl.s16 q13, q13, q2
484 vrshl.s16 q14, q14, q2
485 vadd.s16 q10, q10, q1
486 vadd.s16 q11, q11, q1
487 vadd.s16 q12, q12, q1
488 vadd.s16 q13, q13, q1
489 vadd.s16 q14, q14, q1
495 vst1.8 {d16-d17}, [r0,:128]!
496 vst1.32 {d20[0]}, [r0,:32], r1
497 vst1.8 {d18-d19}, [r0,:128]!
498 vst1.32 {d20[1]}, [r0,:32], r1
503 function x264_mc_weight_w16_neon
507 vld1.8 {d16-d17}, [r2], r3
508 vld1.8 {d18-d19}, [r2], r3
513 vmul.s16 q10, q10, q0
514 vmul.s16 q11, q11, q0
515 vmul.s16 q12, q12, q0
516 vmul.s16 q13, q13, q0
517 vrshl.s16 q10, q10, q2
518 vrshl.s16 q11, q11, q2
519 vrshl.s16 q12, q12, q2
520 vrshl.s16 q13, q13, q2
521 vadd.s16 q10, q10, q1
522 vadd.s16 q11, q11, q1
523 vadd.s16 q12, q12, q1
524 vadd.s16 q13, q13, q1
529 vst1.8 {d16-d17}, [r0,:128], r1
530 vst1.8 {d18-d19}, [r0,:128], r1
535 function x264_mc_weight_w8_neon
539 vld1.8 {d16}, [r2], r3
540 vld1.8 {d18}, [r2], r3
551 vst1.8 {d16}, [r0,:64], r1
552 vst1.8 {d18}, [r0,:64], r1
557 function x264_mc_weight_w4_neon
561 vld1.32 {d16[]}, [r2], r3
562 vld1.32 {d18[]}, [r2], r3
565 vmul.s16 d16, d16, d0
566 vmul.s16 d17, d18, d0
570 vst1.32 {d16[0]}, [r0,:32], r1
571 vst1.32 {d16[1]}, [r0,:32], r1
576 function x264_mc_weight_w20_nodenom_neon
577 weight_prologue nodenom
579 weight20_nodenom_loop:
581 vld1.8 {d17-d19}, [r2], r3
585 vld1.8 {d16-d18}, [r2], r3
595 vmla.s16 q10, q12, q0
596 vmla.s16 q11, q13, q0
598 vmla.s16 d24, d28, d0
599 vmla.s16 d25, d30, d0
605 vst1.8 {d16-d17}, [r0,:128]!
606 vst1.32 {d20[0]}, [r0,:32], r1
607 vst1.8 {d18-d19}, [r0,:128]!
608 vst1.32 {d20[1]}, [r0,:32], r1
609 bgt weight20_nodenom_loop
613 function x264_mc_weight_w16_nodenom_neon
614 weight_prologue nodenom
615 weight16_nodenom_loop:
617 vld1.8 {d16-d17}, [r2], r3
618 vld1.8 {d18-d19}, [r2], r3
629 vmla.s16 q10, q14, q0
630 vmla.s16 q11, q15, q0
635 vst1.8 {d16-d17}, [r0,:128], r1
636 vst1.8 {d18-d19}, [r0,:128], r1
637 bgt weight16_nodenom_loop
641 function x264_mc_weight_w8_nodenom_neon
642 weight_prologue nodenom
643 weight8_nodenom_loop:
645 vld1.8 {d16}, [r2], r3
646 vld1.8 {d18}, [r2], r3
655 vst1.8 {d16}, [r0,:64], r1
656 vst1.8 {d17}, [r0,:64], r1
657 bgt weight8_nodenom_loop
661 function x264_mc_weight_w4_nodenom_neon
662 weight_prologue nodenom
663 weight4_nodenom_loop:
665 vld1.32 {d16[]}, [r2], r3
666 vld1.32 {d18[]}, [r2], r3
670 vmla.s16 d20, d16, d0
671 vmla.s16 d21, d18, d0
673 vst1.32 {d16[0]}, [r0,:32], r1
674 vst1.32 {d16[1]}, [r0,:32], r1
675 bgt weight4_nodenom_loop
679 .macro weight_simple_prologue
681 ldr lr, [sp, #4] // weight_t
682 ldr ip, [sp, #8] // h
683 ldr lr, [lr] // offset
687 .macro weight_simple name op
688 function x264_mc_weight_w20_\name\()_neon
689 weight_simple_prologue
690 weight20_\name\()_loop:
692 vld1.8 {d16-d18}, [r2], r3
693 vld1.8 {d19-d21}, [r2], r3
697 vst1.8 {d16-d18}, [r0,:64], r1
698 vst1.8 {d19-d21}, [r0,:64], r1
699 bgt weight20_\name\()_loop
703 function x264_mc_weight_w16_\name\()_neon
704 weight_simple_prologue
705 weight16_\name\()_loop:
707 vld1.8 {d16-d17}, [r2], r3
708 vld1.8 {d18-d19}, [r2], r3
711 vst1.8 {d16-d17}, [r0,:128], r1
712 vst1.8 {d18-d19}, [r0,:128], r1
713 bgt weight16_\name\()_loop
717 function x264_mc_weight_w8_\name\()_neon
718 weight_simple_prologue
719 weight8_\name\()_loop:
721 vld1.8 {d16}, [r2], r3
722 vld1.8 {d17}, [r2], r3
724 vst1.8 {d16}, [r0,:64], r1
725 vst1.8 {d17}, [r0,:64], r1
726 bgt weight8_\name\()_loop
730 function x264_mc_weight_w4_\name\()_neon
731 weight_simple_prologue
732 weight4_\name\()_loop:
734 vld1.32 {d16[]}, [r2], r3
735 vld1.32 {d17[]}, [r2], r3
737 vst1.32 {d16[0]}, [r0,:32], r1
738 vst1.32 {d17[0]}, [r0,:32], r1
739 bgt weight4_\name\()_loop
744 weight_simple offsetadd, vqadd.u8
745 weight_simple offsetsub, vqsub.u8
748 // void mc_copy( uint8_t *dst, intptr_t dst_stride, uint8_t *src, intptr_t src_stride, int height )
749 function x264_mc_copy_w4_neon
753 vld1.32 {d0[]}, [r2], r3
754 vld1.32 {d1[]}, [r2], r3
755 vld1.32 {d2[]}, [r2], r3
756 vld1.32 {d3[]}, [r2], r3
757 vst1.32 {d0[0]}, [r0,:32], r1
758 vst1.32 {d1[0]}, [r0,:32], r1
759 vst1.32 {d2[0]}, [r0,:32], r1
760 vst1.32 {d3[0]}, [r0,:32], r1
765 function x264_mc_copy_w8_neon
769 vld1.32 {d0}, [r2], r3
770 vld1.32 {d1}, [r2], r3
771 vld1.32 {d2}, [r2], r3
772 vld1.32 {d3}, [r2], r3
773 vst1.32 {d0}, [r0,:64], r1
774 vst1.32 {d1}, [r0,:64], r1
775 vst1.32 {d2}, [r0,:64], r1
776 vst1.32 {d3}, [r0,:64], r1
781 function x264_mc_copy_w16_neon
785 vld1.32 {d0-d1}, [r2], r3
786 vld1.32 {d2-d3}, [r2], r3
787 vld1.32 {d4-d5}, [r2], r3
788 vld1.32 {d6-d7}, [r2], r3
789 vst1.32 {d0-d1}, [r0,:128], r1
790 vst1.32 {d2-d3}, [r0,:128], r1
791 vst1.32 {d4-d5}, [r0,:128], r1
792 vst1.32 {d6-d7}, [r0,:128], r1
797 function x264_mc_copy_w16_aligned_neon
799 copy_w16_aligned_loop:
801 vld1.32 {d0-d1}, [r2,:128], r3
802 vld1.32 {d2-d3}, [r2,:128], r3
803 vld1.32 {d4-d5}, [r2,:128], r3
804 vld1.32 {d6-d7}, [r2,:128], r3
805 vst1.32 {d0-d1}, [r0,:128], r1
806 vst1.32 {d2-d3}, [r0,:128], r1
807 vst1.32 {d4-d5}, [r0,:128], r1
808 vst1.32 {d6-d7}, [r0,:128], r1
809 bgt copy_w16_aligned_loop
814 // void x264_mc_chroma_neon( uint8_t *dst, intptr_t i_dst_stride,
815 // uint8_t *src, intptr_t i_src_stride,
816 // int dx, int dy, int i_width, int i_height );
818 function x264_mc_chroma_neon
821 ldrd r4, r5, [sp, #56]
822 ldrd r6, r7, [sp, #64]
826 add r3, r3, r5, asr #2
841 .macro CHROMA_MC_START r00, r01, r10, r11
843 rsb r7, lr, r6, lsl #3
844 rsb ip, lr, r5, lsl #3
845 sub r5, lr, r5, lsl #3
846 sub r5, r5, r6, lsl #3
850 vld2.8 {\r00-\r01}, [r3], r4
856 vld2.8 {\r10-\r11}, [r3], r4
861 .macro CHROMA_MC width, align
863 CHROMA_MC_START d4, d5, d8, d9
864 vext.8 d6, d4, d6, #1
865 vext.8 d7, d5, d7, #1
866 vext.8 d10, d8, d10, #1
867 vext.8 d11, d9, d11, #1
868 // since the element size varies, there's a different index for the 2nd store
883 1: // height loop, interpolate xy
890 vld2.8 {d4-d5}, [r3], r4
892 vext.8 d6, d4, d6, #1
893 vext.8 d7, d5, d7, #1
895 vadd.i16 d16, d16, d17
896 vadd.i16 d17, d18, d19
906 vld2.8 {d8-d9}, [r3], r4
908 vrshrn.u16 d16, q8, #6
910 vext.8 d10, d8, d10, #1
911 vext.8 d11, d9, d11, #1
913 vadd.i16 d18, d20, d21
914 vadd.i16 d19, d22, d23
919 vrshrn.u16 d18, q9, #6
926 vst1.\align {d16[0]}, [r0,:\align], r2
927 vst1.\align {d16[st2]}, [r1,:\align], r2
928 vst1.\align {d18[0]}, [r0,:\align], r2
929 vst1.\align {d18[st2]}, [r1,:\align], r2
944 vld1.64 {d4}, [r3], r4
945 vld1.64 {d6}, [r3], r4
947 3: // vertical interpolation loop
952 vld1.64 {d4}, [r3], r4
954 vld1.64 {d6}, [r3], r4
956 vrshrn.u16 d16, q8, #6 // uvuvuvuv
957 vrshrn.u16 d17, q9, #6 // uvuvuvuv
959 vuzp.8 d16, d17 // d16=uuuu|uuuu, d17=vvvv|vvvv
964 vst1.\align {d16[0]}, [r0,:\align], r2
965 vst1.\align {d16[st2]}, [r0,:\align], r2
966 vst1.\align {d17[0]}, [r1,:\align], r2
967 vst1.\align {d17[st2]}, [r1,:\align], r2
975 vld1.64 {d4-d5}, [r3], r4
976 vld1.64 {d6-d7}, [r3], r4
978 vext.8 d5, d4, d5, #2
979 vext.8 d7, d6, d7, #2
981 5: // horizontal interpolation loop
989 vld1.64 {d4-d5}, [r3], r4
990 vld1.64 {d6-d7}, [r3], r4
991 vext.8 d5, d4, d5, #2
992 vrshrn.u16 d16, q8, #6
993 vrshrn.u16 d17, q9, #6
994 vext.8 d7, d6, d7, #2
1000 vst1.\align {d16[0]}, [r0,:\align], r2
1001 vst1.\align {d16[st2]}, [r0,:\align], r2
1002 vst1.\align {d17[0]}, [r1,:\align], r2
1003 vst1.\align {d17[st2]}, [r1,:\align], r2
1014 CHROMA_MC_START d4, d7, d8, d11
1015 vext.8 d5, d4, d5, #1
1016 vext.8 d9, d8, d9, #1
1017 vext.8 d7, d6, d7, #1
1018 vext.8 d11, d10, d11, #1
1020 1: // height loop, interpolate xy
1028 vmlal.u8 q9, d10, d2
1029 vmlal.u8 q9, d11, d3
1031 vld2.8 {d4-d7}, [r3], r4
1033 vext.8 d5, d4, d5, #1
1034 vext.8 d7, d6, d7, #1
1036 vmull.u8 q10, d8, d0
1037 vmlal.u8 q10, d9, d1
1038 vmlal.u8 q10, d4, d2
1039 vmlal.u8 q10, d5, d3
1041 vmull.u8 q11, d10, d0
1042 vmlal.u8 q11, d11, d1
1043 vmlal.u8 q11, d6, d2
1044 vmlal.u8 q11, d7, d3
1047 vld2.8 {d8-d11}, [r3], r4
1049 vrshrn.u16 d16, q8, #6
1050 vrshrn.u16 d17, q9, #6
1051 vrshrn.u16 d18, q10, #6
1052 vext.8 d9, d8, d9, #1
1053 vrshrn.u16 d19, q11, #6
1054 vext.8 d11, d10, d11, #1
1059 vst1.64 {d16}, [r0,:64], r2
1060 vst1.64 {d17}, [r1,:64], r2
1061 vst1.64 {d18}, [r0,:64], r2
1062 vst1.64 {d19}, [r1,:64], r2
1069 2: // dx or dy are 0
1078 vld2.8 {d4-d5}, [r3], r4
1079 vld2.8 {d6-d7}, [r3], r4
1081 3: // vertical interpolation loop
1082 vmull.u8 q8, d4, d0 //U
1084 vmull.u8 q9, d5, d0 //V
1087 vld2.8 {d4-d5}, [r3], r4
1089 vmull.u8 q10, d6, d0
1090 vmlal.u8 q10, d4, d1
1091 vmull.u8 q11, d7, d0
1092 vmlal.u8 q11, d5, d1
1094 vld2.8 {d6-d7}, [r3], r4
1096 vrshrn.u16 d16, q8, #6
1097 vrshrn.u16 d17, q9, #6
1098 vrshrn.u16 d18, q10, #6
1099 vrshrn.u16 d19, q11, #6
1105 vst1.64 {d16}, [r0,:64], r2
1106 vst1.64 {d17}, [r1,:64], r2
1107 vst1.64 {d18}, [r0,:64], r2
1108 vst1.64 {d19}, [r1,:64], r2
1117 vld2.8 {d4-d7}, [r3], r4
1118 vld2.8 {d8-d11}, [r3], r4
1119 vext.8 d5, d4, d5, #1
1120 vext.8 d7, d6, d7, #1
1121 vext.8 d9, d8, d9, #1
1122 vext.8 d11, d10, d11, #1
1124 5: // horizontal interpolation loop
1126 vmull.u8 q8, d4, d0 //U
1128 vmull.u8 q9, d6, d0 //V
1131 vld2.8 {d4-d7}, [r3], r4
1133 vmull.u8 q10, d8, d0
1134 vmlal.u8 q10, d9, d1
1135 vmull.u8 q11, d10, d0
1136 vmlal.u8 q11, d11, d1
1138 vld2.8 {d8-d11}, [r3], r4
1140 vext.8 d5, d4, d5, #1
1141 vrshrn.u16 d16, q8, #6
1142 vext.8 d7, d6, d7, #1
1143 vrshrn.u16 d17, q9, #6
1144 vext.8 d9, d8, d9, #1
1145 vrshrn.u16 d18, q10, #6
1146 vext.8 d11, d10, d11, #1
1147 vrshrn.u16 d19, q11, #6
1152 vst1.64 {d16}, [r0,:64], r2
1153 vst1.64 {d17}, [r1,:64], r2
1154 vst1.64 {d18}, [r0,:64], r2
1155 vst1.64 {d19}, [r1,:64], r2
1164 // hpel_filter_v( uint8_t *dst, uint8_t *src, int16_t *buf, intptr_t stride, int width )
1165 function x264_hpel_filter_v_neon
1167 sub r1, r1, r3, lsl #1
1175 vld1.64 {d0-d1}, [r1,:128], r3
1176 vld1.64 {d2-d3}, [r1,:128], r3
1177 vld1.64 {d4-d5}, [r1,:128], r3
1178 vld1.64 {d6-d7}, [r1,:128], r3
1179 vld1.64 {d16-d17}, [r1,:128], r3
1180 vld1.64 {d18-d19}, [r1,:128], r3
1183 vaddl.u8 q10, d0, d18
1184 vmlsl.u8 q10, d2, d30
1185 vmlal.u8 q10, d4, d31
1186 vmlal.u8 q10, d6, d31
1187 vmlsl.u8 q10, d16, d30
1189 vaddl.u8 q11, d1, d19
1190 vmlsl.u8 q11, d3, d30
1191 vmlal.u8 q11, d5, d31
1192 vmlal.u8 q11, d7, d31
1193 vmlsl.u8 q11, d17, d30
1195 vqrshrun.s16 d0, q10, #5
1196 vst1.64 {d20-d21}, [r2,:128]!
1197 vqrshrun.s16 d1, q11, #5
1198 vst1.64 {d22-d23}, [r2,:128]!
1199 vst1.64 {d0-d1}, [r0,:128]!
1204 // hpel_filter_c( uint8_t *dst, int16_t *buf, int width );
1205 function x264_hpel_filter_c_neon
1207 vld1.64 {d0-d3}, [r1,:128]!
1209 // unrolled 2x: 4% faster
1212 vld1.64 {d4-d7}, [r1,:128]!
1213 vext.16 q8, q0, q1, #6
1214 vext.16 q12, q1, q2, #3
1215 vadd.s16 q8, q8, q12
1216 vext.16 q9, q0, q1, #7
1217 vext.16 q11, q1, q2, #2
1218 vadd.s16 q9, q9, q11
1219 vext.16 q10, q1, q2, #1
1220 vext.16 q11, q1, q2, #6
1221 vadd.s16 q10, q1, q10
1222 vsub.s16 q8, q8, q9 // a-b
1223 vext.16 q15, q2, q3, #3
1224 vsub.s16 q9, q9, q10 // b-c
1226 vext.16 q12, q1, q2, #7
1227 vshr.s16 q8, q8, #2 // (a-b)/4
1228 vadd.s16 q11, q11, q15
1229 vext.16 q14, q2, q3, #2
1230 vsub.s16 q8, q8, q9 // (a-b)/4-b+c
1231 vadd.s16 q12, q12, q14
1232 vext.16 q13, q2, q3, #1
1234 vshr.s16 q8, q8, #2 // ((a-b)/4-b+c)/4
1235 vadd.s16 q13, q2, q13
1236 vadd.s16 q8, q8, q10 // ((a-b)/4-b+c)/4+c = (a-5*b+20*c)/16
1237 vsub.s16 q11, q11, q12 // a-b
1238 vsub.s16 q12, q12, q13 // b-c
1239 vshr.s16 q11, q11, #2 // (a-b)/4
1240 vqrshrun.s16 d30, q8, #6
1241 vsub.s16 q11, q11, q12 // (a-b)/4-b+c
1242 vshr.s16 q11, q11, #2 // ((a-b)/4-b+c)/4
1243 vld1.64 {d0-d3}, [r1,:128]!
1244 vadd.s16 q11, q11, q13 // ((a-b)/4-b+c)/4+c = (a-5*b+20*c)/16
1246 vext.16 q8, q2, q3, #6
1247 vqrshrun.s16 d31, q11, #6
1248 vext.16 q12, q3, q0, #3
1249 vadd.s16 q8, q8, q12
1250 vext.16 q9, q2, q3, #7
1251 vst1.64 {d30-d31}, [r0,:128]!
1255 vext.16 q11, q3, q0, #2
1256 vadd.s16 q9, q9, q11
1257 vext.16 q10, q3, q0, #1
1258 vext.16 q11, q3, q0, #6
1259 vadd.s16 q10, q3, q10
1260 vsub.s16 q8, q8, q9 // a-b
1261 vext.16 q15, q0, q1, #3
1262 vsub.s16 q9, q9, q10 // b-c
1264 vext.16 q12, q3, q0, #7
1265 vshr.s16 q8, q8, #2 // (a-b)/4
1266 vadd.s16 q11, q11, q15
1267 vext.16 q14, q0, q1, #2
1268 vsub.s16 q8, q8, q9 // (a-b)/4-b+c
1269 vadd.s16 q12, q12, q14
1270 vext.16 q13, q0, q1, #1
1272 vshr.s16 q8, q8, #2 // ((a-b)/4-b+c)/4
1273 vadd.s16 q13, q0, q13
1274 vadd.s16 q8, q8, q10 // ((a-b)/4-b+c)/4+c = (a-5*b+20*c)/16
1275 vsub.s16 q11, q11, q12 // a-b
1276 vsub.s16 q12, q12, q13 // b-c
1277 vshr.s16 q11, q11, #2 // (a-b)/4
1278 vqrshrun.s16 d30, q8, #6
1279 vsub.s16 q11, q11, q12 // (a-b)/4-b+c
1280 vshr.s16 q11, q11, #2 // ((a-b)/4-b+c)/4
1281 vadd.s16 q11, q11, q13 // ((a-b)/4-b+c)/4+c = (a-5*b+20*c)/16
1283 vqrshrun.s16 d31, q11, #6
1284 vst1.64 {d30-d31}, [r0,:128]!
1289 // hpel_filter_h( uint8_t *dst, uint8_t *src, int width );
1290 function x264_hpel_filter_h_neon
1293 vld1.64 {d0-d3}, [r1,:128]!
1296 // unrolled 3x because it's 5% faster, due to mitigating
1297 // the high latency of multiplication and vqrshrun
1300 vld1.64 {d4-d5}, [r1,:128]!
1301 vext.8 q8, q0, q1, #14
1302 vext.8 q12, q1, q2, #3
1303 vaddl.u8 q13, d16, d24
1304 vext.8 q9, q0, q1, #15
1305 vaddl.u8 q14, d17, d25
1307 vext.8 q10, q1, q2, #1
1308 vmlal.u8 q13, d2, d31
1309 vmlsl.u8 q13, d18, d30
1310 vext.8 q11, q1, q2, #2
1311 vmlal.u8 q13, d20, d31
1312 vmlsl.u8 q13, d22, d30
1314 vmlsl.u8 q14, d19, d30
1315 vmlal.u8 q14, d3, d31
1316 vmlal.u8 q14, d21, d31
1317 vmlsl.u8 q14, d23, d30
1318 vqrshrun.s16 d6, q13, #5
1320 vld1.64 {d0-d1}, [r1,:128]!
1321 vext.8 q8, q1, q2, #14
1322 vext.8 q12, q2, q0, #3
1323 vaddl.u8 q13, d16, d24
1324 vqrshrun.s16 d7, q14, #5
1325 vext.8 q9, q1, q2, #15
1326 vaddl.u8 q14, d17, d25
1328 vst1.64 {d6-d7}, [r0,:128]!
1332 vext.8 q10, q2, q0, #1
1333 vmlal.u8 q13, d4, d31
1334 vmlsl.u8 q13, d18, d30
1335 vext.8 q11, q2, q0, #2
1336 vmlal.u8 q13, d20, d31
1337 vmlsl.u8 q13, d22, d30
1339 vmlsl.u8 q14, d19, d30
1340 vmlal.u8 q14, d5, d31
1341 vmlal.u8 q14, d21, d31
1342 vmlsl.u8 q14, d23, d30
1343 vqrshrun.s16 d6, q13, #5
1345 vld1.64 {d2-d3}, [r1,:128]!
1346 vext.8 q8, q2, q0, #14
1347 vext.8 q12, q0, q1, #3
1348 vaddl.u8 q13, d16, d24
1349 vqrshrun.s16 d7, q14, #5
1350 vext.8 q9, q2, q0, #15
1351 vaddl.u8 q14, d17, d25
1353 vst1.64 {d6-d7}, [r0,:128]!
1357 vext.8 q10, q0, q1, #1
1358 vmlal.u8 q13, d0, d31
1359 vmlsl.u8 q13, d18, d30
1360 vext.8 q11, q0, q1, #2
1361 vmlal.u8 q13, d20, d31
1362 vmlsl.u8 q13, d22, d30
1364 vmlsl.u8 q14, d19, d30
1365 vmlal.u8 q14, d1, d31
1366 vmlal.u8 q14, d21, d31
1367 vmlsl.u8 q14, d23, d30
1369 vqrshrun.s16 d6, q13, #5
1370 vqrshrun.s16 d7, q14, #5
1371 vst1.64 {d6-d7}, [r0,:128]!
1377 // frame_init_lowres_core( uint8_t *src0, uint8_t *dst0, uint8_t *dsth, uint8_t *dstv,
1378 // uint8_t *dstc, intptr_t src_stride, intptr_t dst_stride, int width,
1380 function x264_frame_init_lowres_core_neon
1383 ldrd r4, r5, [sp, #96]
1384 ldrd r6, r7, [sp, #104]
1386 sub r10, r6, r7 // dst_stride - width
1392 add r8, r0, r5 // src1 = src0 + src_stride
1393 add r9, r0, r5, lsl #1 // src2 = src1 + src_stride
1395 vld2.8 {d8, d10}, [r6,:128]!
1396 vld2.8 {d12,d14}, [r8,:128]!
1397 vld2.8 {d16,d18}, [r9,:128]!
1402 vld2.8 {d9, d11}, [r6,:128]!
1403 vld2.8 {d13,d15}, [r8,:128]!
1404 vrhadd.u8 q0, q4, q6
1405 vld2.8 {d17,d19}, [r9,:128]!
1406 vrhadd.u8 q5, q5, q7
1407 vld2.8 {d20,d22}, [r6,:128]!
1408 vrhadd.u8 q1, q6, q8
1409 vld2.8 {d24,d26}, [r8,:128]!
1410 vrhadd.u8 q7, q7, q9
1411 vext.8 q4, q4, q10, #1
1412 vrhadd.u8 q0, q0, q5
1413 vext.8 q6, q6, q12, #1
1414 vrhadd.u8 q1, q1, q7
1415 vld2.8 {d28,d30}, [r9,:128]!
1416 vrhadd.u8 q4, q4, q6
1417 vext.8 q8, q8, q14, #1
1418 vrhadd.u8 q6, q6, q8
1419 vst1.64 {d0-d1}, [r1,:128]!
1420 vrhadd.u8 q2, q4, q5
1421 vst1.64 {d2-d3}, [r3,:128]!
1422 vrhadd.u8 q3, q6, q7
1423 vst1.64 {d4-d5}, [r2,:128]!
1424 vst1.64 {d6-d7}, [r4,:128]!
1426 ble lowres_xloop_end
1429 vld2.8 {d21,d23}, [r6,:128]!
1430 vld2.8 {d25,d27}, [r8,:128]!
1431 vrhadd.u8 q0, q10, q12
1432 vld2.8 {d29,d31}, [r9,:128]!
1433 vrhadd.u8 q11, q11, q13
1434 vld2.8 {d8, d10}, [r6,:128]!
1435 vrhadd.u8 q1, q12, q14
1436 vld2.8 {d12,d14}, [r8,:128]!
1437 vrhadd.u8 q13, q13, q15
1438 vext.8 q10, q10, q4, #1
1439 vrhadd.u8 q0, q0, q11
1440 vext.8 q12, q12, q6, #1
1441 vrhadd.u8 q1, q1, q13
1442 vld2.8 {d16,d18}, [r9,:128]!
1443 vrhadd.u8 q10, q10, q12
1444 vext.8 q14, q14, q8, #1
1445 vrhadd.u8 q12, q12, q14
1446 vst1.64 {d0-d1}, [r1,:128]!
1447 vrhadd.u8 q2, q10, q11
1448 vst1.64 {d2-d3}, [r3,:128]!
1449 vrhadd.u8 q3, q12, q13
1450 vst1.64 {d4-d5}, [r2,:128]!
1451 vst1.64 {d6-d7}, [r4,:128]!
1457 add r0, r0, r5, lsl #1
1468 function x264_load_deinterleave_chroma_fdec_neon
1469 mov ip, #FDEC_STRIDE/2
1471 vld2.8 {d0-d1}, [r1,:128], r2
1474 vst1.8 {d0}, [r0,:64], ip
1475 vst1.8 {d1}, [r0,:64], ip
1481 function x264_load_deinterleave_chroma_fenc_neon
1482 mov ip, #FENC_STRIDE/2
1484 vld2.8 {d0-d1}, [r1,:128], r2
1487 vst1.8 {d0}, [r0,:64], ip
1488 vst1.8 {d1}, [r0,:64], ip
1494 function x264_plane_copy_deinterleave_neon
1496 ldrd r6, r7, [sp, #28]
1497 ldrd r4, r5, [sp, #20]
1502 sub r5, r5, lr, lsl #1
1504 vld2.8 {d0-d3}, [r4,:128]!
1520 function x264_plane_copy_deinterleave_rgb_neon
1521 push {r4-r8, r10, r11, lr}
1522 ldrd r4, r5, [sp, #32]
1523 ldrd r6, r7, [sp, #40]
1525 ldrd r10, r11, [sp, #52]
1529 sub r7, r7, lr, lsl #1
1533 subne r7, r7, lr, lsl #1
1537 vld3.8 {d0,d1,d2}, [r6]!
1552 pop {r4-r8, r10, r11, pc}
1554 vld4.8 {d0,d1,d2,d3}, [r6]!
1569 pop {r4-r8, r10, r11, pc}
1572 function x264_plane_copy_interleave_neon
1574 ldrd r6, r7, [sp, #28]
1575 ldrd r4, r5, [sp, #20]
1578 sub r1, r1, lr, lsl #1
1585 vst2.8 {d0,d2}, [r0]!
1586 vst2.8 {d1,d3}, [r0]!
1599 function x264_store_interleave_chroma_neon
1602 mov ip, #FDEC_STRIDE
1604 vld1.8 {d0}, [r2], ip
1605 vld1.8 {d1}, [r3], ip
1607 vst2.8 {d0,d1}, [r0,:128], r1