2 * Copyright (c) 2014 - 2015 Seppo Tomperi <seppo.tomperi@vtt.fi>
4 * This file is part of FFmpeg.
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 #include "libavutil/arm/asm.S"
24 #define MAX_PB_SIZE #64
48 vld1.8 {q11}, [r2], r3
49 vext.8 d16, d22, d23, #1
50 vext.8 d17, d22, d23, #2
51 vext.8 d18, d22, d23, #3
52 vext.8 d19, d22, d23, #4
53 vext.8 d20, d22, d23, #5
54 vext.8 d21, d22, d23, #6
55 vext.8 d22, d22, d23, #7
60 vld1.8 {d16}, [r2], r3
62 vld1.8 {d17}, [r2], r3
64 vld1.8 {d18}, [r2], r3
66 vld1.8 {d19}, [r2], r3
68 vld1.8 {d20}, [r2], r3
70 vld1.8 {d21}, [r2], r3
72 vld1.8 {d22}, [r2], r3
74 vld1.8 {d23}, [r2], r3
77 .macro qpel_filter_1_32b
80 vmull.s16 q9, d6, d16 // 58 * d0
81 vmull.s16 q10, d7, d16 // 58 * d1
83 vmull.s16 q11, d4, d17 // 10 * c0
84 vmull.s16 q12, d5, d17 // 10 * c1
86 vmull.s16 q13, d8, d16 // 17 * e0
87 vmull.s16 q14, d9, d16 // 17 * e1
88 vmull.s16 q15, d10, d17 // 5 * f0
89 vmull.s16 q8, d11, d17 // 5 * f1
90 vsub.s32 q9, q11 // 58 * d0 - 10 * c0
91 vsub.s32 q10, q12 // 58 * d1 - 10 * c1
92 vshll.s16 q11, d2, #2 // 4 * b0
93 vshll.s16 q12, d3, #2 // 4 * b1
94 vadd.s32 q9, q13 // 58 * d0 - 10 * c0 + 17 * e0
95 vadd.s32 q10, q14 // 58 * d1 - 10 * c1 + 17 * e1
96 vsubl.s16 q13, d12, d0 // g0 - a0
97 vsubl.s16 q14, d13, d1 // g1 - a1
98 vadd.s32 q9, q11 // 58 * d0 - 10 * c0 + 17 * e0 + 4 * b0
99 vadd.s32 q10, q12 // 58 * d1 - 10 * c1 + 17 * e1 + 4 * b1
100 vsub.s32 q13, q15 // g0 - a0 - 5 * f0
101 vsub.s32 q14, q8 // g1 - a1 - 5 * f1
102 vadd.s32 q9, q13 // 58 * d0 - 10 * c0 + 17 * e0 + 4 * b0 + g0 - a0 - 5 * f0
103 vadd.s32 q10, q14 // 58 * d1 - 10 * c1 + 17 * e1 + 4 * b1 + g1 - a1 - 5 * f1
104 vqshrn.s32 d16, q9, #6
105 vqshrn.s32 d17, q10, #6
110 .macro qpel_filter_2_32b
112 vaddl.s16 q9, d6, d8 // d0 + e0
113 vaddl.s16 q10, d7, d9 // d1 + e1
114 vaddl.s16 q11, d4, d10 // c0 + f0
115 vaddl.s16 q12, d5, d11 // c1 + f1
116 vmul.s32 q11, q8 // 11 * (c0 + f0)
117 vmul.s32 q12, q8 // 11 * (c1 + f1)
119 vaddl.s16 q15, d2, d12 // b0 + g0
120 vmul.s32 q9, q8 // 40 * (d0 + e0)
121 vmul.s32 q10, q8 // 40 * (d1 + e1)
122 vaddl.s16 q8, d3, d13 // b1 + g1
123 vaddl.s16 q13, d0, d14 // a0 + h0
124 vaddl.s16 q14, d1, d15 // a1 + h1
125 vshl.s32 q15, #2 // 4*(b0+g0)
126 vshl.s32 q8, #2 // 4*(b1+g1)
127 vadd.s32 q11, q13 // 11 * (c0 + f0) + a0 + h0
128 vadd.s32 q12, q14 // 11 * (c1 + f1) + a1 + h1
129 vadd.s32 q9, q15 // 40 * (d0 + e0) + 4*(b0+g0)
130 vadd.s32 q10, q8 // 40 * (d1 + e1) + 4*(b1+g1)
131 vsub.s32 q9, q11 // 40 * (d0 + e0) + 4*(b0+g0) - (11 * (c0 + f0) + a0 + h0)
132 vsub.s32 q10, q12 // 40 * (d1 + e1) + 4*(b1+g1) - (11 * (c1 + f1) + a1 + h1)
133 vqshrn.s32 d16, q9, #6
134 vqshrn.s32 d17, q10, #6
137 .macro qpel_filter_3_32b
140 vmull.s16 q9, d8, d16 // 58 * d0
141 vmull.s16 q10, d9, d16 // 58 * d1
143 vmull.s16 q11, d10, d17 // 10 * c0
144 vmull.s16 q12, d11, d17 // 10 * c1
146 vmull.s16 q13, d6, d16 // 17 * e0
147 vmull.s16 q14, d7, d16 // 17 * e1
148 vmull.s16 q15, d4, d17 // 5 * f0
149 vmull.s16 q8, d5, d17 // 5 * f1
150 vsub.s32 q9, q11 // 58 * d0 - 10 * c0
151 vsub.s32 q10, q12 // 58 * d1 - 10 * c1
152 vshll.s16 q11, d12, #2 // 4 * b0
153 vshll.s16 q12, d13, #2 // 4 * b1
154 vadd.s32 q9, q13 // 58 * d0 - 10 * c0 + 17 * e0
155 vadd.s32 q10, q14 // 58 * d1 - 10 * c1 + 17 * e1
156 vsubl.s16 q13, d2, d14 // g0 - a0
157 vsubl.s16 q14, d3, d15 // g1 - a1
158 vadd.s32 q9, q11 // 58 * d0 - 10 * c0 + 17 * e0 + 4 * b0
159 vadd.s32 q10, q12 // 58 * d1 - 10 * c1 + 17 * e1 + 4 * b1
160 vsub.s32 q13, q15 // g0 - a0 - 5 * f0
161 vsub.s32 q14, q8 // g1 - a1 - 5 * f1
162 vadd.s32 q9, q13 // 58 * d0 - 10 * c0 + 17 * e0 + 4 * b0 + g0 - a0 - 5 * f0
163 vadd.s32 q10, q14 // 58 * d1 - 10 * c1 + 17 * e1 + 4 * b1 + g1 - a1 - 5 * f1
164 vqshrn.s32 d16, q9, #6
165 vqshrn.s32 d17, q10, #6
168 .macro qpel_filter_1 out=q7
171 vshll.u8 q13, d20, #4 // 16*e
172 vshll.u8 q14, d21, #2 // 4*f
173 vmull.u8 \out, d19, d24 // 58*d
174 vaddw.u8 q13, q13, d20 // 17*e
175 vmull.u8 q15, d18, d25 // 10*c
176 vaddw.u8 q14, q14, d21 // 5*f
177 vsubl.u8 q12, d22, d16 // g - a
178 vadd.u16 \out, q13 // 58d + 17e
179 vshll.u8 q13, d17, #2 // 4*b
180 vadd.u16 q15, q14 // 10*c + 5*f
181 vadd.s16 q13, q12 // - a + 4*b + g
182 vsub.s16 \out, q15 // -10*c + 58*d + 17*e -5*f
183 vadd.s16 \out, q13 // -a + 4*b -10*c + 58*d + 17*e -5*f
186 .macro qpel_filter_2 out=q7
189 vaddl.u8 q13, d19, d20 // d + e
190 vaddl.u8 q15, d18, d21 // c + f
191 vmul.u16 q13, q12 // 10 * (d+e)
192 vmul.u16 q15, q14 // 11 * ( c + f)
193 vaddl.u8 \out, d17, d22 // b + g
194 vaddl.u8 q12, d16, d23 // a + h
195 vadd.u16 \out, q13 // b + 10 * (d + e) + g
197 vshl.u16 \out, #2 // 4 * (b + 10 * (d + e) + g)
201 .macro qpel_filter_3 out=q7
204 vshll.u8 q13, d19, #4 // 16*e
205 vshll.u8 q14, d18, #2 // 4*f
206 vmull.u8 \out, d20, d24 // 58*d
207 vaddw.u8 q13, q13, d19 // 17*e
208 vmull.u8 q15, d21, d25 // 10*c
209 vaddw.u8 q14, q14, d18 // 5*f
210 vsubl.u8 q12, d17, d23 // g - a
211 vadd.u16 \out, q13 // 58d + 17e
212 vshll.u8 q13, d22, #2 // 4*b
213 vadd.u16 q15, q14 // 10*c + 5*f
214 vadd.s16 q13, q12 // - a + 4*b + g
215 vsub.s16 \out, q15 // -10*c + 58*d + 17*e -5*f
216 vadd.s16 \out, q13 // -a + 4*b -10*c + 58*d + 17*e -5*f
219 .macro hevc_put_qpel_vX_neon_8 filter
220 push {r4, r5, r6, r7}
221 ldr r4, [sp, #16] // height
222 ldr r5, [sp, #20] // width
224 sub r2, r2, r3, lsl #1
235 vst1.16 {q7}, [r0], r1
237 vld1.8 {d23}, [r2], r3
249 vst1.16 d14, [r0], r1
251 vld1.32 {d23[0]}, [r2], r3
258 .macro hevc_put_qpel_uw_vX_neon_8 filter
260 ldr r5, [sp, #28] // width
261 ldr r4, [sp, #32] // height
262 ldr r8, [sp, #36] // src2
263 ldr r9, [sp, #40] // src2stride
265 sub r2, r2, r3, lsl #1
277 vqrshrun.s16 d0, q7, #6
280 vld1.8 {d23}, [r2], r3
292 vqrshrun.s16 d0, q7, #6
293 vst1.32 d0[0], [r0], r1
295 vld1.32 {d23[0]}, [r2], r3
305 vld1.16 {q0}, [r8], r9
307 vqrshrun.s16 d0, q0, #7
310 vld1.8 {d23}, [r2], r3
326 vqrshrun.s16 d0, q0, #7
327 vst1.32 d0[0], [r0], r1
329 vld1.32 {d23[0]}, [r2], r3
336 function ff_hevc_put_qpel_v1_neon_8, export=1
337 hevc_put_qpel_vX_neon_8 qpel_filter_1
340 function ff_hevc_put_qpel_v2_neon_8, export=1
341 hevc_put_qpel_vX_neon_8 qpel_filter_2
344 function ff_hevc_put_qpel_v3_neon_8, export=1
345 hevc_put_qpel_vX_neon_8 qpel_filter_3
349 function ff_hevc_put_qpel_uw_v1_neon_8, export=1
350 hevc_put_qpel_uw_vX_neon_8 qpel_filter_1
353 function ff_hevc_put_qpel_uw_v2_neon_8, export=1
354 hevc_put_qpel_uw_vX_neon_8 qpel_filter_2
357 function ff_hevc_put_qpel_uw_v3_neon_8, export=1
358 hevc_put_qpel_uw_vX_neon_8 qpel_filter_3
361 .macro hevc_put_qpel_hX_neon_8 filter
362 push {r4, r5, r6, r7}
363 ldr r4, [sp, #16] // height
364 ldr r5, [sp, #20] // width
377 vst1.16 {q7}, [r0], r1
391 vst1.16 d14, [r0], r1
398 .macro hevc_put_qpel_uw_hX_neon_8 filter
400 ldr r5, [sp, #28] // width
401 ldr r4, [sp, #32] // height
402 ldr r8, [sp, #36] // src2
403 ldr r9, [sp, #40] // src2stride
416 vqrshrun.s16 d0, q7, #6
431 vqrshrun.s16 d0, q7, #6
432 vst1.32 d0[0], [r0], r1
443 vld1.16 {q0}, [r8], r9
445 vqrshrun.s16 d0, q0, #7
464 vqrshrun.s16 d0, q0, #7
465 vst1.32 d0[0], [r0], r1
472 function ff_hevc_put_qpel_h1_neon_8, export=1
473 hevc_put_qpel_hX_neon_8 qpel_filter_1
476 function ff_hevc_put_qpel_h2_neon_8, export=1
477 hevc_put_qpel_hX_neon_8 qpel_filter_2
480 function ff_hevc_put_qpel_h3_neon_8, export=1
481 hevc_put_qpel_hX_neon_8 qpel_filter_3
485 function ff_hevc_put_qpel_uw_h1_neon_8, export=1
486 hevc_put_qpel_uw_hX_neon_8 qpel_filter_1
489 function ff_hevc_put_qpel_uw_h2_neon_8, export=1
490 hevc_put_qpel_uw_hX_neon_8 qpel_filter_2
493 function ff_hevc_put_qpel_uw_h3_neon_8, export=1
494 hevc_put_qpel_uw_hX_neon_8 qpel_filter_3
497 .macro hevc_put_qpel_hXvY_neon_8 filterh filterv
498 push {r4, r5, r6, r7}
499 ldr r4, [sp, #16] // height
500 ldr r5, [sp, #20] // width
504 sub r2, r2, r3, lsl #1
505 sub r2, r3 // extra_before 3
530 vst1.16 {q8}, [r0], r1
545 vst1.16 d16, [r0], r1
555 .macro hevc_put_qpel_uw_hXvY_neon_8 filterh filterv
557 ldr r5, [sp, #28] // width
558 ldr r4, [sp, #32] // height
559 ldr r8, [sp, #36] // src2
560 ldr r9, [sp, #40] // src2stride
563 sub r2, r2, r3, lsl #1
564 sub r2, r3 // extra_before 3
590 vqrshrun.s16 d0, q8, #6
606 vqrshrun.s16 d0, q8, #6
607 vst1.32 d0[0], [r0], r1
635 vld1.16 {q0}, [r8], r9
637 vqrshrun.s16 d0, q0, #7
657 vqrshrun.s16 d0, q0, #7
658 vst1.32 d0[0], [r0], r1
669 function ff_hevc_put_qpel_h1v1_neon_8, export=1
670 hevc_put_qpel_hXvY_neon_8 qpel_filter_1 qpel_filter_1_32b
673 function ff_hevc_put_qpel_h2v1_neon_8, export=1
674 hevc_put_qpel_hXvY_neon_8 qpel_filter_2 qpel_filter_1_32b
677 function ff_hevc_put_qpel_h3v1_neon_8, export=1
678 hevc_put_qpel_hXvY_neon_8 qpel_filter_3 qpel_filter_1_32b
681 function ff_hevc_put_qpel_h1v2_neon_8, export=1
682 hevc_put_qpel_hXvY_neon_8 qpel_filter_1 qpel_filter_2_32b
685 function ff_hevc_put_qpel_h2v2_neon_8, export=1
686 hevc_put_qpel_hXvY_neon_8 qpel_filter_2 qpel_filter_2_32b
689 function ff_hevc_put_qpel_h3v2_neon_8, export=1
690 hevc_put_qpel_hXvY_neon_8 qpel_filter_3 qpel_filter_2_32b
693 function ff_hevc_put_qpel_h1v3_neon_8, export=1
694 hevc_put_qpel_hXvY_neon_8 qpel_filter_1 qpel_filter_3_32b
697 function ff_hevc_put_qpel_h2v3_neon_8, export=1
698 hevc_put_qpel_hXvY_neon_8 qpel_filter_2 qpel_filter_3_32b
701 function ff_hevc_put_qpel_h3v3_neon_8, export=1
702 hevc_put_qpel_hXvY_neon_8 qpel_filter_3 qpel_filter_3_32b
706 function ff_hevc_put_qpel_uw_h1v1_neon_8, export=1
707 hevc_put_qpel_uw_hXvY_neon_8 qpel_filter_1 qpel_filter_1_32b
710 function ff_hevc_put_qpel_uw_h2v1_neon_8, export=1
711 hevc_put_qpel_uw_hXvY_neon_8 qpel_filter_2 qpel_filter_1_32b
714 function ff_hevc_put_qpel_uw_h3v1_neon_8, export=1
715 hevc_put_qpel_uw_hXvY_neon_8 qpel_filter_3 qpel_filter_1_32b
718 function ff_hevc_put_qpel_uw_h1v2_neon_8, export=1
719 hevc_put_qpel_uw_hXvY_neon_8 qpel_filter_1 qpel_filter_2_32b
722 function ff_hevc_put_qpel_uw_h2v2_neon_8, export=1
723 hevc_put_qpel_uw_hXvY_neon_8 qpel_filter_2 qpel_filter_2_32b
726 function ff_hevc_put_qpel_uw_h3v2_neon_8, export=1
727 hevc_put_qpel_uw_hXvY_neon_8 qpel_filter_3 qpel_filter_2_32b
730 function ff_hevc_put_qpel_uw_h1v3_neon_8, export=1
731 hevc_put_qpel_uw_hXvY_neon_8 qpel_filter_1 qpel_filter_3_32b
734 function ff_hevc_put_qpel_uw_h2v3_neon_8, export=1
735 hevc_put_qpel_uw_hXvY_neon_8 qpel_filter_2 qpel_filter_3_32b
738 function ff_hevc_put_qpel_uw_h3v3_neon_8, export=1
739 hevc_put_qpel_uw_hXvY_neon_8 qpel_filter_3 qpel_filter_3_32b
742 .macro init_put_pixels
749 function ff_hevc_put_pixels_w2_neon_8, export=1
754 vld1.32 {d0[0]}, [r1], r2
759 vst1.32 d6, [r0], r12
764 function ff_hevc_put_pixels_w4_neon_8, export=1
767 vld1.32 {d0[0]}, [r1], r2
768 vld1.32 {d0[1]}, [r1], r2
772 vst1.64 {d0}, [r0], r12
773 vst1.64 {d1}, [r0], r12
778 function ff_hevc_put_pixels_w6_neon_8, export=1
783 vld1.16 {d0}, [r1], r2
788 vst1.8 {q12}, [r0], r12
793 function ff_hevc_put_pixels_w8_neon_8, export=1
796 vld1.8 {d0}, [r1], r2
797 vld1.8 {d2}, [r1], r2
802 vst1.16 {q0}, [r0], r12
803 vst1.16 {q1}, [r0], r12
808 function ff_hevc_put_pixels_w12_neon_8, export=1
813 vld1.32 {d1[0]}, [r1], r2
817 vld1.32 {d1[1]}, [r1], r2
825 vst1.64 {d16, d17, d18}, [r0], r12
826 vst1.64 {d20, d21, d22}, [r0], r12
831 function ff_hevc_put_pixels_w16_neon_8, export=1
834 vld1.8 {q0}, [r1], r2
835 vld1.8 {q1}, [r1], r2
842 vst1.8 {q8, q9}, [r0], r12
843 vst1.8 {q10, q11}, [r0], r12
848 function ff_hevc_put_pixels_w24_neon_8, export=1
851 vld1.8 {d0, d1, d2}, [r1], r2
856 vstm r0, {q10, q11, q12}
862 function ff_hevc_put_pixels_w32_neon_8, export=1
865 vld1.8 {q0, q1}, [r1], r2
871 vstm r0, {q8, q9, q10, q11}
877 function ff_hevc_put_pixels_w48_neon_8, export=1
880 vld1.8 {q0, q1}, [r1]
882 vld1.8 {q2}, [r1], r2
891 vstm r0, {q8, q9, q10, q11, q12, q13}
897 function ff_hevc_put_pixels_w64_neon_8, export=1
900 vld1.8 {q0, q1}, [r1]
902 vld1.8 {q2, q3}, [r1], r2
913 vstm r0, {q8, q9, q10, q11, q12, q13, q14, q15}
919 function ff_hevc_put_qpel_uw_pixels_neon_8, export=1
921 ldr r5, [sp, #24] // width
922 ldr r4, [sp, #28] // height
923 ldr r8, [sp, #32] // src2
924 ldr r9, [sp, #36] // src2stride
929 vld1.8 {d0}, [r2], r3
936 vld1.8 {d0}, [r2], r3
937 vld1.16 {q1}, [r8], r9
940 vqrshrun.s16 d0, q0, #7
948 .macro put_qpel_uw_pixels width, regs, regs2, regs3, regs4
949 function ff_hevc_put_qpel_uw_pixels_w\width\()_neon_8, export=1
950 ldr r12, [sp] // height
952 vld1.32 {\regs} , [r2], r3
953 vld1.32 {\regs2} , [r2], r3
954 vld1.32 {\regs3} , [r2], r3
955 vld1.32 {\regs4} , [r2], r3
956 vst1.32 {\regs} , [r0], r1
957 vst1.32 {\regs2} , [r0], r1
958 vst1.32 {\regs3} , [r0], r1
959 vst1.32 {\regs4} , [r0], r1
965 .macro put_qpel_uw_pixels_m width, regs, regs2, regs3, regs4
966 function ff_hevc_put_qpel_uw_pixels_w\width\()_neon_8, export=1
968 ldr r12, [sp, #8] // height
971 vld1.32 {\regs} , [r2]!
972 vld1.32 {\regs2} , [r2]
975 vld1.32 {\regs3} , [r2]!
976 vld1.32 {\regs4} , [r2]
979 vst1.32 {\regs} , [r0]!
980 vst1.32 {\regs2} , [r0]
983 vst1.32 {\regs3} , [r0]!
984 vst1.32 {\regs4} , [r0]
992 put_qpel_uw_pixels 4, d0[0], d0[1], d1[0], d1[1]
993 put_qpel_uw_pixels 8, d0, d1, d2, d3
994 put_qpel_uw_pixels_m 12, d0, d1[0], d2, d3[0]
995 put_qpel_uw_pixels 16, q0, q1, q2, q3
996 put_qpel_uw_pixels 24, d0-d2, d3-d5, d16-d18, d19-d21
997 put_qpel_uw_pixels 32, q0-q1, q2-q3, q8-q9, q10-q11
998 put_qpel_uw_pixels_m 48, q0-q1, q2, q8-q9, q10
999 put_qpel_uw_pixels_m 64, q0-q1, q2-q3, q8-q9, q10-q11