/***************************************************************************** * pixel.S: arm pixel metrics ***************************************************************************** * Copyright (C) 2009-2015 x264 project * * Authors: David Conrad * Janne Grunau * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. * * This program is also available under a commercial proprietary license. * For more information, contact us at licensing@x264.com. *****************************************************************************/ #include "asm.S" .section .rodata .align 4 .rept 16 .byte 0xff .endr mask_ff: .rept 16 .byte 0 .endr mask_ac4: .short 0, -1, -1, -1, 0, -1, -1, -1 mask_ac8: .short 0, -1, -1, -1, -1, -1, -1, -1 .text .macro SAD4_ARMV6 h function x264_pixel_sad_4x\h\()_armv6 push {r4-r6,lr} ldr r4, [r2], r3 ldr r5, [r0], r1 ldr r6, [r2], r3 ldr lr, [r0], r1 usad8 ip, r4, r5 .rept (\h - 2)/2 ldr r4, [r2], r3 ldr r5, [r0], r1 usada8 ip, r6, lr, ip ldr r6, [r2], r3 ldr lr, [r0], r1 usada8 ip, r4, r5, ip .endr usada8 r0, r6, lr, ip pop {r4-r6,pc} endfunc .endm SAD4_ARMV6 4 SAD4_ARMV6 8 .macro SAD_START_4 align:vararg vld1.32 {d1[]}, [r2\align], r3 vld1.32 {d0[]}, [r0,:32], r1 vabdl.u8 q8, d0, d1 .endm .macro SAD_4 align:vararg vld1.32 {d1[]}, [r2\align], r3 vld1.32 {d0[]}, [r0,:32], r1 vabal.u8 q8, d0, d1 .endm .macro SAD_START_8 align:vararg vld1.64 {d1}, [r2\align], r3 vld1.64 {d0}, [r0,:64], r1 vabdl.u8 q8, d0, d1 .endm .macro SAD_8 align:vararg vld1.64 {d1}, [r2\align], r3 vld1.64 {d0}, [r0,:64], r1 vabal.u8 q8, d0, d1 .endm .macro SAD_START_16 align:vararg vld1.64 {d2-d3}, [r2\align], r3 vld1.64 {d0-d1}, [r0,:128], r1 vabdl.u8 q8, d0, d2 vld1.64 {d6-d7}, [r2\align], r3 vabdl.u8 q9, d1, d3 vld1.64 {d4-d5}, [r0,:128], r1 .endm .macro SAD_16 align:vararg vabal.u8 q8, d4, d6 vld1.64 {d2-d3}, [r2\align], r3 vabal.u8 q9, d5, d7 vld1.64 {d0-d1}, [r0,:128], r1 vabal.u8 q8, d0, d2 vld1.64 {d6-d7}, [r2\align], r3 vabal.u8 q9, d1, d3 vld1.64 {d4-d5}, [r0,:128], r1 .endm .macro SAD_FUNC w, h, name, align:vararg function x264_pixel_sad\name\()_\w\()x\h\()_neon SAD_START_\w \align .if \w == 16 .rept \h / 2 - 1 SAD_\w \align .endr .else .rept \h - 1 SAD_\w \align .endr .endif .if \w > 8 vabal.u8 q8, d4, d6 vabal.u8 q9, d5, d7 vadd.u16 q8, q8, q9 .endif .if \w > 4 vadd.u16 d16, d16, d17 .endif vpadd.u16 d0, d16, d16 vpaddl.u16 d0, d0 vmov.u32 r0, d0[0] bx lr endfunc .endm SAD_FUNC 4, 4 SAD_FUNC 4, 8 SAD_FUNC 8, 4 SAD_FUNC 8, 8 SAD_FUNC 8, 16 SAD_FUNC 16, 8 SAD_FUNC 16, 16 SAD_FUNC 4, 4, _aligned, ,:32 SAD_FUNC 4, 8, _aligned, ,:32 SAD_FUNC 8, 4, _aligned, ,:64 SAD_FUNC 8, 8, _aligned, ,:64 SAD_FUNC 8, 16, _aligned, ,:64 SAD_FUNC 16, 8, _aligned, ,:128 SAD_FUNC 16, 16, _aligned, ,:128 // If dual issue is possible, use additional accumulators to avoid // stalls from vadal's latency. This only matters for aligned. .macro SAD_DUAL_START_8 SAD_START_8 ,:64 vld1.64 {d3}, [r2,:64], r3 vld1.64 {d2}, [r0,:64], r1 vabdl.u8 q9, d2, d3 .endm .macro SAD_DUAL_8 align:vararg vld1.64 {d1}, [r2,:64], r3 vld1.64 {d0}, [r0,:64], r1 vabal.u8 q8, d0, d1 vld1.64 {d3}, [r2,:64], r3 vld1.64 {d2}, [r0,:64], r1 vabal.u8 q9, d2, d3 .endm .macro SAD_DUAL_START_16 SAD_START_16 ,:128 vabdl.u8 q10, d4, d6 vld1.64 {d2-d3}, [r2,:128], r3 vabdl.u8 q11, d5, d7 vld1.64 {d0-d1}, [r0,:128], r1 .endm .macro SAD_DUAL_16 vabal.u8 q8, d0, d2 vld1.64 {d6-d7}, [r2,:128], r3 vabal.u8 q9, d1, d3 vld1.64 {d4-d5}, [r0,:128], r1 vabal.u8 q10, d4, d6 vld1.64 {d2-d3}, [r2,:128], r3 vabal.u8 q11, d5, d7 vld1.64 {d0-d1}, [r0,:128], r1 .endm .macro SAD_DUAL_END_16 vabal.u8 q8, d0, d2 vld1.64 {d6-d7}, [r2,:128], r3 vabal.u8 q9, d1, d3 vld1.64 {d4-d5}, [r0,:128], r1 vabal.u8 q10, d4, d6 vabal.u8 q11, d5, d7 .endm .macro SAD_FUNC_DUAL w, h function x264_pixel_sad_aligned_\w\()x\h\()_neon_dual SAD_DUAL_START_\w .rept \h / 2 - \w / 8 SAD_DUAL_\w .endr .if \w > 8 SAD_DUAL_END_16 vadd.u16 q8, q8, q9 vadd.u16 q9, q10, q11 .endif .if \w > 4 vadd.u16 q8, q8, q9 vadd.u16 d16, d16, d17 .endif vpadd.u16 d0, d16, d16 vpaddl.u16 d0, d0 vmov.u32 r0, d0[0] bx lr endfunc .endm SAD_FUNC_DUAL 8, 4 SAD_FUNC_DUAL 8, 8 SAD_FUNC_DUAL 8, 16 SAD_FUNC_DUAL 16, 8 SAD_FUNC_DUAL 16, 16 .macro SAD_X_START_4 x vld1.32 {d0[]}, [r0,:32], lr vld1.32 {d1[]}, [r1], r6 vabdl.u8 q8, d1, d0 vld1.32 {d2[]}, [r2], r6 vabdl.u8 q9, d2, d0 vld1.32 {d3[]}, [r3], r6 vabdl.u8 q10, d3, d0 .if \x == 4 vld1.32 {d4[]}, [r12], r6 vabdl.u8 q11, d4, d0 .endif .endm .macro SAD_X_4 x vld1.32 {d0[]}, [r0,:32], lr vld1.32 {d1[]}, [r1], r6 vabal.u8 q8, d1, d0 vld1.32 {d2[]}, [r2], r6 vabal.u8 q9, d2, d0 vld1.32 {d3[]}, [r3], r6 vabal.u8 q10, d3, d0 .if \x == 4 vld1.32 {d4[]}, [r12], r6 vabal.u8 q11, d4, d0 .endif .endm .macro SAD_X_START_8 x vld1.64 {d0}, [r0,:64], lr vld1.64 {d1}, [r1], r6 vabdl.u8 q8, d1, d0 vld1.64 {d2}, [r2], r6 vabdl.u8 q9, d2, d0 vld1.64 {d3}, [r3], r6 vabdl.u8 q10, d3, d0 .if \x == 4 vld1.64 {d4}, [r12], r6 vabdl.u8 q11, d4, d0 .endif .endm .macro SAD_X_8 x vld1.64 {d0}, [r0,:64], lr vld1.64 {d1}, [r1], r6 vabal.u8 q8, d1, d0 vld1.64 {d2}, [r2], r6 vabal.u8 q9, d2, d0 vld1.64 {d3}, [r3], r6 vabal.u8 q10, d3, d0 .if \x == 4 vld1.64 {d4}, [r12], r6 vabal.u8 q11, d4, d0 .endif .endm .macro SAD_X_START_16 x vld1.64 {d0-d1}, [r0,:128], lr vld1.64 {d2-d3}, [r1], r6 vabdl.u8 q8, d2, d0 vabdl.u8 q12, d3, d1 vld1.64 {d4-d5}, [r2], r6 vabdl.u8 q9, d4, d0 vabdl.u8 q13, d5, d1 vld1.64 {d6-d7}, [r3], r6 vabdl.u8 q10, d6, d0 vabdl.u8 q14, d7, d1 .if \x == 4 vld1.64 {d2-d3}, [r12], r6 vabdl.u8 q11, d2, d0 vabdl.u8 q15, d3, d1 .endif .endm .macro SAD_X_16 x vld1.64 {d0-d1}, [r0,:128], lr vld1.64 {d2-d3}, [r1], r6 vabal.u8 q8, d2, d0 vabal.u8 q12, d3, d1 vld1.64 {d4-d5}, [r2], r6 vabal.u8 q9, d4, d0 vabal.u8 q13, d5, d1 vld1.64 {d6-d7}, [r3], r6 vabal.u8 q10, d6, d0 vabal.u8 q14, d7, d1 .if \x == 4 vld1.64 {d2-d3}, [r12], r6 vabal.u8 q11, d2, d0 vabal.u8 q15, d3, d1 .endif .endm .macro SAD_X_FUNC x, w, h function x264_pixel_sad_x\x\()_\w\()x\h\()_neon push {r6-r7,lr} .if \x == 3 ldrd r6, r7, [sp, #12] .else ldrd r6, r7, [sp, #16] ldr r12, [sp, #12] .endif mov lr, #FENC_STRIDE SAD_X_START_\w \x .rept \h - 1 SAD_X_\w \x .endr // add up the sads .if \w > 8 vadd.u16 q8, q8, q12 vadd.u16 q9, q9, q13 vadd.u16 q10, q10, q14 .if \x == 4 vadd.u16 q11, q11, q15 .endif .endif .if \w > 4 vadd.u16 d16, d16, d17 vadd.u16 d18, d18, d19 vadd.u16 d20, d20, d21 .if \x == 4 vadd.u16 d22, d22, d23 .endif .endif vpadd.u16 d0, d16, d18 vpadd.u16 d1, d20, d22 vpaddl.u16 q0, q0 .if \x == 3 vst1.32 {d0}, [r7]! vst1.32 {d1[0]}, [r7,:32] .else vst1.32 {d0-d1}, [r7] .endif pop {r6-r7,pc} endfunc .endm SAD_X_FUNC 3, 4, 4 SAD_X_FUNC 3, 4, 8 SAD_X_FUNC 3, 8, 4 SAD_X_FUNC 3, 8, 8 SAD_X_FUNC 3, 8, 16 SAD_X_FUNC 3, 16, 8 SAD_X_FUNC 3, 16, 16 SAD_X_FUNC 4, 4, 4 SAD_X_FUNC 4, 4, 8 SAD_X_FUNC 4, 8, 4 SAD_X_FUNC 4, 8, 8 SAD_X_FUNC 4, 8, 16 SAD_X_FUNC 4, 16, 8 SAD_X_FUNC 4, 16, 16 function x264_pixel_vsad_neon subs r2, r2, #2 vld1.8 {q0}, [r0], r1 vld1.8 {q1}, [r0], r1 vabdl.u8 q2, d0, d2 vabdl.u8 q3, d1, d3 ble 2f 1: subs r2, r2, #2 vld1.8 {q0}, [r0], r1 vabal.u8 q2, d2, d0 vabal.u8 q3, d3, d1 vld1.8 {q1}, [r0], r1 blt 2f vabal.u8 q2, d0, d2 vabal.u8 q3, d1, d3 bgt 1b 2: vadd.u16 q0, q2, q3 HORIZ_ADD d0, d0, d1 vmov.32 r0, d0[0] bx lr endfunc function x264_pixel_asd8_neon ldr r12, [sp, #0] sub r12, r12, #2 vld1.8 {d0}, [r0], r1 vld1.8 {d1}, [r2], r3 vld1.8 {d2}, [r0], r1 vld1.8 {d3}, [r2], r3 vsubl.u8 q8, d0, d1 1: subs r12, r12, #2 vld1.8 {d4}, [r0], r1 vld1.8 {d5}, [r2], r3 vsubl.u8 q9, d2, d3 vsubl.u8 q10, d4, d5 vadd.s16 q8, q9 vld1.8 {d2}, [r0], r1 vld1.8 {d3}, [r2], r3 vadd.s16 q8, q10 bgt 1b vsubl.u8 q9, d2, d3 vadd.s16 q8, q9 vpaddl.s16 q8, q8 vpadd.s32 d16, d16, d17 vpadd.s32 d16, d16, d17 vabs.s32 d16, d16 vmov.32 r0, d16[0] bx lr endfunc .macro SSD_START_4 vld1.32 {d16[]}, [r0,:32], r1 vld1.32 {d17[]}, [r2,:32], r3 vsubl.u8 q2, d16, d17 vld1.32 {d16[]}, [r0,:32], r1 vmull.s16 q0, d4, d4 vld1.32 {d17[]}, [r2,:32], r3 .endm .macro SSD_4 vsubl.u8 q2, d16, d17 vld1.32 {d16[]}, [r0,:32], r1 vmlal.s16 q0, d4, d4 vld1.32 {d17[]}, [r2,:32], r3 .endm .macro SSD_END_4 vsubl.u8 q2, d16, d17 vmlal.s16 q0, d4, d4 .endm .macro SSD_START_8 vld1.64 {d16}, [r0,:64], r1 vld1.64 {d17}, [r2,:64], r3 vsubl.u8 q2, d16, d17 vld1.64 {d16}, [r0,:64], r1 vmull.s16 q0, d4, d4 vmlal.s16 q0, d5, d5 vld1.64 {d17}, [r2,:64], r3 .endm .macro SSD_8 vsubl.u8 q2, d16, d17 vld1.64 {d16}, [r0,:64], r1 vmlal.s16 q0, d4, d4 vmlal.s16 q0, d5, d5 vld1.64 {d17}, [r2,:64], r3 .endm .macro SSD_END_8 vsubl.u8 q2, d16, d17 vmlal.s16 q0, d4, d4 vmlal.s16 q0, d5, d5 .endm .macro SSD_START_16 vld1.64 {d16-d17}, [r0,:128], r1 vld1.64 {d18-d19}, [r2,:128], r3 vsubl.u8 q2, d16, d18 vsubl.u8 q3, d17, d19 vld1.64 {d16-d17}, [r0,:128], r1 vmull.s16 q0, d4, d4 vmlal.s16 q0, d5, d5 vld1.64 {d18-d19}, [r2,:128], r3 vmlal.s16 q0, d6, d6 vmlal.s16 q0, d7, d7 .endm .macro SSD_16 vsubl.u8 q2, d16, d18 vsubl.u8 q3, d17, d19 vld1.64 {d16-d17}, [r0,:128], r1 vmlal.s16 q0, d4, d4 vmlal.s16 q0, d5, d5 vld1.64 {d18-d19}, [r2,:128], r3 vmlal.s16 q0, d6, d6 vmlal.s16 q0, d7, d7 .endm .macro SSD_END_16 vsubl.u8 q2, d16, d18 vsubl.u8 q3, d17, d19 vmlal.s16 q0, d4, d4 vmlal.s16 q0, d5, d5 vmlal.s16 q0, d6, d6 vmlal.s16 q0, d7, d7 .endm .macro SSD_FUNC w h function x264_pixel_ssd_\w\()x\h\()_neon SSD_START_\w .rept \h-2 SSD_\w .endr SSD_END_\w vadd.s32 d0, d0, d1 vpadd.s32 d0, d0, d0 vmov.32 r0, d0[0] bx lr endfunc .endm SSD_FUNC 4, 4 SSD_FUNC 4, 8 SSD_FUNC 8, 4 SSD_FUNC 8, 8 SSD_FUNC 8, 16 SSD_FUNC 16, 8 SSD_FUNC 16, 16 function x264_pixel_ssd_nv12_core_neon push {r4-r5} ldrd r4, r5, [sp, #8] add r12, r4, #8 bic r12, r12, #15 vmov.u64 q8, #0 vmov.u64 q9, #0 sub r1, r1, r12, lsl #1 sub r3, r3, r12, lsl #1 1: subs r12, r4, #16 vld2.8 {d0,d1}, [r0]! vld2.8 {d2,d3}, [r2]! vld2.8 {d4,d5}, [r0]! vld2.8 {d6,d7}, [r2]! vsubl.u8 q10, d0, d2 vsubl.u8 q11, d1, d3 vmull.s16 q14, d20, d20 vmull.s16 q15, d22, d22 vsubl.u8 q12, d4, d6 vsubl.u8 q13, d5, d7 vmlal.s16 q14, d21, d21 vmlal.s16 q15, d23, d23 blt 4f beq 3f 2: vmlal.s16 q14, d24, d24 vmlal.s16 q15, d26, d26 vld2.8 {d0,d1}, [r0]! vld2.8 {d2,d3}, [r2]! vmlal.s16 q14, d25, d25 vmlal.s16 q15, d27, d27 subs r12, r12, #16 vsubl.u8 q10, d0, d2 vsubl.u8 q11, d1, d3 vmlal.s16 q14, d20, d20 vmlal.s16 q15, d22, d22 vld2.8 {d4,d5}, [r0]! vld2.8 {d6,d7}, [r2]! vmlal.s16 q14, d21, d21 vmlal.s16 q15, d23, d23 blt 4f vsubl.u8 q12, d4, d6 vsubl.u8 q13, d5, d7 bgt 2b 3: vmlal.s16 q14, d24, d24 vmlal.s16 q15, d26, d26 vmlal.s16 q14, d25, d25 vmlal.s16 q15, d27, d27 4: subs r5, r5, #1 vaddw.s32 q8, q8, d28 vaddw.s32 q9, q9, d30 add r0, r0, r1 add r2, r2, r3 vaddw.s32 q8, q8, d29 vaddw.s32 q9, q9, d31 bgt 1b vadd.u64 d16, d16, d17 vadd.u64 d18, d18, d19 ldrd r4, r5, [sp, #16] vst1.64 {d16}, [r4] vst1.64 {d18}, [r5] pop {r4-r5} bx lr endfunc .macro VAR_SQR_SUM qsqr_sum qsqr_last qsqr dsrc vpadal=vpadal.u16 vmull.u8 \qsqr, \dsrc, \dsrc vaddw.u8 q0, q0, \dsrc \vpadal \qsqr_sum, \qsqr_last .endm function x264_pixel_var_8x8_neon vld1.64 {d16}, [r0,:64], r1 vmull.u8 q1, d16, d16 vmovl.u8 q0, d16 vld1.64 {d18}, [r0,:64], r1 vmull.u8 q2, d18, d18 vaddw.u8 q0, q0, d18 vld1.64 {d20}, [r0,:64], r1 VAR_SQR_SUM q1, q1, q3, d20, vpaddl.u16 vld1.64 {d22}, [r0,:64], r1 VAR_SQR_SUM q2, q2, q8, d22, vpaddl.u16 vld1.64 {d24}, [r0,:64], r1 VAR_SQR_SUM q1, q3, q9, d24 vld1.64 {d26}, [r0,:64], r1 VAR_SQR_SUM q2, q8, q10, d26 vld1.64 {d24}, [r0,:64], r1 VAR_SQR_SUM q1, q9, q14, d24 vld1.64 {d26}, [r0,:64], r1 VAR_SQR_SUM q2, q10, q15, d26 b x264_var_end endfunc function x264_pixel_var_8x16_neon vld1.64 {d16}, [r0,:64], r1 vld1.64 {d18}, [r0,:64], r1 vmull.u8 q1, d16, d16 vmovl.u8 q0, d16 vld1.64 {d20}, [r0,:64], r1 vmull.u8 q2, d18, d18 vaddw.u8 q0, q0, d18 mov ip, #12 vld1.64 {d22}, [r0,:64], r1 VAR_SQR_SUM q1, q1, q14, d20, vpaddl.u16 vld1.64 {d16}, [r0,:64], r1 VAR_SQR_SUM q2, q2, q15, d22, vpaddl.u16 1: subs ip, ip, #4 vld1.64 {d18}, [r0,:64], r1 VAR_SQR_SUM q1, q14, q12, d16 vld1.64 {d20}, [r0,:64], r1 VAR_SQR_SUM q2, q15, q13, d18 vld1.64 {d22}, [r0,:64], r1 VAR_SQR_SUM q1, q12, q14, d20 beq 2f vld1.64 {d16}, [r0,:64], r1 VAR_SQR_SUM q2, q13, q15, d22 b 1b 2: VAR_SQR_SUM q2, q13, q15, d22 b x264_var_end endfunc function x264_pixel_var_16x16_neon vld1.64 {d16-d17}, [r0,:128], r1 vmull.u8 q12, d16, d16 vmovl.u8 q0, d16 vmull.u8 q13, d17, d17 vaddw.u8 q0, q0, d17 vld1.64 {d18-d19}, [r0,:128], r1 VAR_SQR_SUM q1, q12, q14, d18, vpaddl.u16 VAR_SQR_SUM q2, q13, q15, d19, vpaddl.u16 mov ip, #7 var16_loop: subs ip, ip, #1 vld1.64 {d16-d17}, [r0,:128], r1 VAR_SQR_SUM q1, q14, q12, d16 VAR_SQR_SUM q2, q15, q13, d17 vld1.64 {d18-d19}, [r0,:128], r1 VAR_SQR_SUM q1, q12, q14, d18 VAR_SQR_SUM q2, q13, q15, d19 bgt var16_loop endfunc function x264_var_end, export=0 vpaddl.u16 q8, q14 vpaddl.u16 q9, q15 vadd.u32 q1, q1, q8 vadd.u16 d0, d0, d1 vadd.u32 q1, q1, q9 vadd.u32 q1, q1, q2 vpaddl.u16 d0, d0 vadd.u32 d2, d2, d3 vpadd.u32 d0, d0, d2 vmov r0, r1, d0 bx lr endfunc .macro DIFF_SUM diff da db lastdiff vld1.64 {\da}, [r0,:64], r1 vld1.64 {\db}, [r2,:64], r3 .ifnb \lastdiff vadd.s16 q0, q0, \lastdiff .endif vsubl.u8 \diff, \da, \db .endm .macro SQR_ACC acc d0 d1 vmlal=vmlal.s16 \vmlal \acc, \d0, \d0 vmlal.s16 \acc, \d1, \d1 .endm function x264_pixel_var2_8x8_neon DIFF_SUM q0, d0, d1 DIFF_SUM q8, d16, d17 SQR_ACC q1, d0, d1, vmull.s16 DIFF_SUM q9, d18, d19, q8 SQR_ACC q2, d16, d17, vmull.s16 .rept 2 DIFF_SUM q8, d16, d17, q9 SQR_ACC q1, d18, d19 DIFF_SUM q9, d18, d19, q8 SQR_ACC q2, d16, d17 .endr DIFF_SUM q8, d16, d17, q9 SQR_ACC q1, d18, d19 vadd.s16 q0, q0, q8 SQR_ACC q2, d16, d17 ldr ip, [sp] vadd.s16 d0, d0, d1 vadd.s32 q1, q1, q2 vpaddl.s16 d0, d0 vadd.s32 d1, d2, d3 vpadd.s32 d0, d0, d1 vmov r0, r1, d0 vst1.32 {d0[1]}, [ip,:32] mul r0, r0, r0 sub r0, r1, r0, lsr #6 bx lr endfunc function x264_pixel_var2_8x16_neon vld1.64 {d16}, [r0,:64], r1 vld1.64 {d17}, [r2,:64], r3 vld1.64 {d18}, [r0,:64], r1 vld1.64 {d19}, [r2,:64], r3 vsubl.u8 q10, d16, d17 vsubl.u8 q11, d18, d19 SQR_ACC q1, d20, d21, vmull.s16 vld1.64 {d16}, [r0,:64], r1 vadd.s16 q0, q10, q11 vld1.64 {d17}, [r2,:64], r3 SQR_ACC q2, d22, d23, vmull.s16 mov ip, #14 1: subs ip, ip, #2 vld1.64 {d18}, [r0,:64], r1 vsubl.u8 q10, d16, d17 vld1.64 {d19}, [r2,:64], r3 vadd.s16 q0, q0, q10 SQR_ACC q1, d20, d21 vsubl.u8 q11, d18, d19 beq 2f vld1.64 {d16}, [r0,:64], r1 vadd.s16 q0, q0, q11 vld1.64 {d17}, [r2,:64], r3 SQR_ACC q2, d22, d23 b 1b 2: vadd.s16 q0, q0, q11 SQR_ACC q2, d22, d23 ldr ip, [sp] vadd.s16 d0, d0, d1 vadd.s32 q1, q1, q2 vpaddl.s16 d0, d0 vadd.s32 d1, d2, d3 vpadd.s32 d0, d0, d1 vmov r0, r1, d0 vst1.32 {d0[1]}, [ip,:32] mul r0, r0, r0 sub r0, r1, r0, lsr #7 bx lr endfunc .macro LOAD_DIFF_8x4 q0 q1 q2 q3 vld1.32 {d1}, [r2], r3 vld1.32 {d0}, [r0,:64], r1 vsubl.u8 \q0, d0, d1 vld1.32 {d3}, [r2], r3 vld1.32 {d2}, [r0,:64], r1 vsubl.u8 \q1, d2, d3 vld1.32 {d5}, [r2], r3 vld1.32 {d4}, [r0,:64], r1 vsubl.u8 \q2, d4, d5 vld1.32 {d7}, [r2], r3 vld1.32 {d6}, [r0,:64], r1 vsubl.u8 \q3, d6, d7 .endm function x264_pixel_satd_4x4_neon vld1.32 {d1[]}, [r2], r3 vld1.32 {d0[]}, [r0,:32], r1 vld1.32 {d3[]}, [r2], r3 vld1.32 {d2[]}, [r0,:32], r1 vld1.32 {d1[1]}, [r2], r3 vld1.32 {d0[1]}, [r0,:32], r1 vld1.32 {d3[1]}, [r2], r3 vld1.32 {d2[1]}, [r0,:32], r1 vsubl.u8 q0, d0, d1 vsubl.u8 q1, d2, d3 SUMSUB_AB q2, q3, q0, q1 SUMSUB_ABCD d0, d2, d1, d3, d4, d5, d6, d7 HADAMARD 1, sumsub, q2, q3, q0, q1 HADAMARD 2, amax, q0,, q2, q3 HORIZ_ADD d0, d0, d1 vmov.32 r0, d0[0] bx lr endfunc function x264_pixel_satd_4x8_neon vld1.32 {d1[]}, [r2], r3 vld1.32 {d0[]}, [r0,:32], r1 vld1.32 {d3[]}, [r2], r3 vld1.32 {d2[]}, [r0,:32], r1 vld1.32 {d5[]}, [r2], r3 vld1.32 {d4[]}, [r0,:32], r1 vld1.32 {d7[]}, [r2], r3 vld1.32 {d6[]}, [r0,:32], r1 vld1.32 {d1[1]}, [r2], r3 vld1.32 {d0[1]}, [r0,:32], r1 vsubl.u8 q0, d0, d1 vld1.32 {d3[1]}, [r2], r3 vld1.32 {d2[1]}, [r0,:32], r1 vsubl.u8 q1, d2, d3 vld1.32 {d5[1]}, [r2], r3 vld1.32 {d4[1]}, [r0,:32], r1 vsubl.u8 q2, d4, d5 vld1.32 {d7[1]}, [r2], r3 SUMSUB_AB q8, q9, q0, q1 vld1.32 {d6[1]}, [r0,:32], r1 vsubl.u8 q3, d6, d7 SUMSUB_AB q10, q11, q2, q3 b x264_satd_4x8_8x4_end_neon endfunc function x264_pixel_satd_8x4_neon vld1.64 {d1}, [r2], r3 vld1.64 {d0}, [r0,:64], r1 vsubl.u8 q0, d0, d1 vld1.64 {d3}, [r2], r3 vld1.64 {d2}, [r0,:64], r1 vsubl.u8 q1, d2, d3 vld1.64 {d5}, [r2], r3 vld1.64 {d4}, [r0,:64], r1 vsubl.u8 q2, d4, d5 vld1.64 {d7}, [r2], r3 SUMSUB_AB q8, q9, q0, q1 vld1.64 {d6}, [r0,:64], r1 vsubl.u8 q3, d6, d7 SUMSUB_AB q10, q11, q2, q3 endfunc function x264_satd_4x8_8x4_end_neon, export=0 vadd.s16 q0, q8, q10 vadd.s16 q1, q9, q11 vsub.s16 q2, q8, q10 vsub.s16 q3, q9, q11 vtrn.16 q0, q1 vadd.s16 q8, q0, q1 vtrn.16 q2, q3 vsub.s16 q9, q0, q1 vadd.s16 q10, q2, q3 vsub.s16 q11, q2, q3 vtrn.32 q8, q10 vabs.s16 q8, q8 vtrn.32 q9, q11 vabs.s16 q10, q10 vabs.s16 q9, q9 vabs.s16 q11, q11 vmax.u16 q0, q8, q10 vmax.u16 q1, q9, q11 vadd.u16 q0, q0, q1 HORIZ_ADD d0, d0, d1 vmov.32 r0, d0[0] bx lr endfunc function x264_pixel_satd_8x8_neon mov ip, lr bl x264_satd_8x8_neon vadd.u16 q0, q12, q13 vadd.u16 q1, q14, q15 vadd.u16 q0, q0, q1 HORIZ_ADD d0, d0, d1 mov lr, ip vmov.32 r0, d0[0] bx lr endfunc function x264_pixel_satd_8x16_neon vpush {d8-d11} mov ip, lr bl x264_satd_8x8_neon vadd.u16 q4, q12, q13 vadd.u16 q5, q14, q15 bl x264_satd_8x8_neon vadd.u16 q4, q4, q12 vadd.u16 q5, q5, q13 vadd.u16 q4, q4, q14 vadd.u16 q5, q5, q15 vadd.u16 q0, q4, q5 HORIZ_ADD d0, d0, d1 vpop {d8-d11} mov lr, ip vmov.32 r0, d0[0] bx lr endfunc function x264_satd_8x8_neon, export=0 LOAD_DIFF_8x4 q8, q9, q10, q11 vld1.64 {d7}, [r2], r3 SUMSUB_AB q0, q1, q8, q9 vld1.64 {d6}, [r0,:64], r1 vsubl.u8 q12, d6, d7 vld1.64 {d17}, [r2], r3 SUMSUB_AB q2, q3, q10, q11 vld1.64 {d16}, [r0,:64], r1 vsubl.u8 q13, d16, d17 vld1.64 {d19}, [r2], r3 SUMSUB_AB q8, q10, q0, q2 vld1.64 {d18}, [r0,:64], r1 vsubl.u8 q14, d18, d19 vld1.64 {d1}, [r2], r3 SUMSUB_AB q9, q11, q1, q3 vld1.64 {d0}, [r0,:64], r1 vsubl.u8 q15, d0, d1 endfunc // one vertical hadamard pass and two horizontal function x264_satd_8x4v_8x8h_neon, export=0 SUMSUB_ABCD q0, q1, q2, q3, q12, q13, q14, q15 vtrn.16 q8, q9 SUMSUB_AB q12, q14, q0, q2 vtrn.16 q10, q11 SUMSUB_AB q13, q15, q1, q3 SUMSUB_AB q0, q1, q8, q9 vtrn.16 q12, q13 SUMSUB_AB q2, q3, q10, q11 vtrn.16 q14, q15 SUMSUB_AB q8, q9, q12, q13 vtrn.32 q0, q2 SUMSUB_AB q10, q11, q14, q15 vtrn.32 q1, q3 ABS2 q0, q2 vtrn.32 q8, q10 ABS2 q1, q3 vtrn.32 q9, q11 ABS2 q8, q10 ABS2 q9, q11 vmax.s16 q12, q0, q2 vmax.s16 q13, q1, q3 vmax.s16 q14, q8, q10 vmax.s16 q15, q9, q11 bx lr endfunc function x264_pixel_satd_16x8_neon vpush {d8-d11} mov ip, lr bl x264_satd_16x4_neon vadd.u16 q4, q12, q13 vadd.u16 q5, q14, q15 bl x264_satd_16x4_neon vadd.u16 q4, q4, q12 vadd.u16 q5, q5, q13 vadd.u16 q4, q4, q14 vadd.u16 q5, q5, q15 vadd.u16 q0, q4, q5 HORIZ_ADD d0, d0, d1 vpop {d8-d11} mov lr, ip vmov.32 r0, d0[0] bx lr endfunc function x264_pixel_satd_16x16_neon vpush {d8-d11} mov ip, lr bl x264_satd_16x4_neon vadd.u16 q4, q12, q13 vadd.u16 q5, q14, q15 bl x264_satd_16x4_neon vadd.u16 q4, q4, q12 vadd.u16 q5, q5, q13 vadd.u16 q4, q4, q14 vadd.u16 q5, q5, q15 bl x264_satd_16x4_neon vadd.u16 q4, q4, q12 vadd.u16 q5, q5, q13 vadd.u16 q4, q4, q14 vadd.u16 q5, q5, q15 bl x264_satd_16x4_neon vadd.u16 q4, q4, q12 vadd.u16 q5, q5, q13 vadd.u16 q4, q4, q14 vadd.u16 q5, q5, q15 vadd.u16 q0, q4, q5 HORIZ_ADD d0, d0, d1 vpop {d8-d11} mov lr, ip vmov.32 r0, d0[0] bx lr endfunc function x264_satd_16x4_neon, export=0 vld1.64 {d2-d3}, [r2], r3 vld1.64 {d0-d1}, [r0,:128], r1 vsubl.u8 q8, d0, d2 vld1.64 {d6-d7}, [r2], r3 vsubl.u8 q12, d1, d3 vld1.64 {d4-d5}, [r0,:128], r1 vsubl.u8 q9, d4, d6 vld1.64 {d2-d3}, [r2], r3 vsubl.u8 q13, d5, d7 vld1.64 {d0-d1}, [r0,:128], r1 vsubl.u8 q10, d0, d2 vld1.64 {d6-d7}, [r2], r3 vsubl.u8 q14, d1, d3 vadd.s16 q0, q8, q9 vld1.64 {d4-d5}, [r0,:128], r1 vsub.s16 q1, q8, q9 vsubl.u8 q11, d4, d6 vsubl.u8 q15, d5, d7 SUMSUB_AB q2, q3, q10, q11 SUMSUB_ABCD q8, q10, q9, q11, q0, q2, q1, q3 b x264_satd_8x4v_8x8h_neon endfunc function x264_pixel_sa8d_8x8_neon mov ip, lr bl x264_sa8d_8x8_neon vadd.u16 q0, q8, q9 HORIZ_ADD d0, d0, d1 mov lr, ip vmov.32 r0, d0[0] add r0, r0, #1 lsr r0, r0, #1 bx lr endfunc function x264_pixel_sa8d_16x16_neon vpush {d8-d11} mov ip, lr bl x264_sa8d_8x8_neon vpaddl.u16 q4, q8 vpaddl.u16 q5, q9 bl x264_sa8d_8x8_neon vpadal.u16 q4, q8 vpadal.u16 q5, q9 sub r0, r0, r1, lsl #4 sub r2, r2, r3, lsl #4 add r0, r0, #8 add r2, r2, #8 bl x264_sa8d_8x8_neon vpadal.u16 q4, q8 vpadal.u16 q5, q9 bl x264_sa8d_8x8_neon vpaddl.u16 q8, q8 vpaddl.u16 q9, q9 vadd.u32 q0, q4, q8 vadd.u32 q1, q5, q9 vadd.u32 q0, q0, q1 vadd.u32 d0, d0, d1 vpadd.u32 d0, d0, d0 vpop {d8-d11} mov lr, ip vmov.32 r0, d0[0] add r0, r0, #1 lsr r0, r0, #1 bx lr endfunc .macro HADAMARD4_V r1, r2, r3, r4, t1, t2, t3, t4 SUMSUB_ABCD \t1, \t2, \t3, \t4, \r1, \r2, \r3, \r4 SUMSUB_ABCD \r1, \r3, \r2, \r4, \t1, \t3, \t2, \t4 .endm function x264_sa8d_8x8_neon, export=0 LOAD_DIFF_8x4 q8, q9, q10, q11 vld1.64 {d7}, [r2], r3 SUMSUB_AB q0, q1, q8, q9 vld1.64 {d6}, [r0,:64], r1 vsubl.u8 q12, d6, d7 vld1.64 {d17}, [r2], r3 SUMSUB_AB q2, q3, q10, q11 vld1.64 {d16}, [r0,:64], r1 vsubl.u8 q13, d16, d17 vld1.64 {d19}, [r2], r3 SUMSUB_AB q8, q10, q0, q2 vld1.64 {d18}, [r0,:64], r1 vsubl.u8 q14, d18, d19 vld1.64 {d1}, [r2], r3 SUMSUB_AB q9, q11, q1, q3 vld1.64 {d0}, [r0,:64], r1 vsubl.u8 q15, d0, d1 HADAMARD4_V q12, q13, q14, q15, q0, q1, q2, q3 SUMSUB_ABCD q0, q8, q1, q9, q8, q12, q9, q13 SUMSUB_AB q2, q10, q10, q14 vtrn.16 q8, q9 SUMSUB_AB q3, q11, q11, q15 vtrn.16 q0, q1 SUMSUB_AB q12, q13, q8, q9 vtrn.16 q10, q11 SUMSUB_AB q8, q9, q0, q1 vtrn.16 q2, q3 SUMSUB_AB q14, q15, q10, q11 vadd.i16 q10, q2, q3 vtrn.32 q12, q14 vsub.i16 q11, q2, q3 vtrn.32 q13, q15 SUMSUB_AB q0, q2, q12, q14 vtrn.32 q8, q10 SUMSUB_AB q1, q3, q13, q15 vtrn.32 q9, q11 SUMSUB_AB q12, q14, q8, q10 SUMSUB_AB q13, q15, q9, q11 vswp d1, d24 ABS2 q0, q12 vswp d3, d26 ABS2 q1, q13 vswp d5, d28 ABS2 q2, q14 vswp d7, d30 ABS2 q3, q15 vmax.s16 q8, q0, q12 vmax.s16 q9, q1, q13 vmax.s16 q10, q2, q14 vmax.s16 q11, q3, q15 vadd.i16 q8, q8, q9 vadd.i16 q9, q10, q11 bx lr endfunc .macro HADAMARD_AC w h function x264_pixel_hadamard_ac_\w\()x\h\()_neon vpush {d8-d15} movrel ip, mask_ac4 vmov.i8 q4, #0 // note: this assumes mask_ac8 is after mask_ac4 (so don't move it) vld1.64 {d12-d15}, [ip,:128] vmov.i8 q5, #0 mov ip, lr bl x264_hadamard_ac_8x8_neon .if \h > 8 bl x264_hadamard_ac_8x8_neon .endif .if \w > 8 sub r0, r0, r1, lsl #3 add r0, r0, #8 bl x264_hadamard_ac_8x8_neon .endif .if \w * \h == 256 sub r0, r0, r1, lsl #4 bl x264_hadamard_ac_8x8_neon .endif vadd.s32 d8, d8, d9 vadd.s32 d10, d10, d11 vpadd.s32 d0, d8, d10 vpop {d8-d15} mov lr, ip vmov r0, r1, d0 lsr r0, r0, #1 lsr r1, r1, #2 bx lr endfunc .endm HADAMARD_AC 8, 8 HADAMARD_AC 8, 16 HADAMARD_AC 16, 8 HADAMARD_AC 16, 16 // q4: satd q5: sa8d q6: mask_ac4 q7: mask_ac8 function x264_hadamard_ac_8x8_neon, export=0 vld1.64 {d2}, [r0,:64], r1 vld1.64 {d3}, [r0,:64], r1 vaddl.u8 q0, d2, d3 vld1.64 {d6}, [r0,:64], r1 vsubl.u8 q1, d2, d3 vld1.64 {d7}, [r0,:64], r1 vaddl.u8 q2, d6, d7 vld1.64 {d18}, [r0,:64], r1 vsubl.u8 q3, d6, d7 vld1.64 {d19}, [r0,:64], r1 vaddl.u8 q8, d18, d19 vld1.64 {d22}, [r0,:64], r1 vsubl.u8 q9, d18, d19 vld1.64 {d23}, [r0,:64], r1 SUMSUB_ABCD q12, q14, q13, q15, q0, q2, q1, q3 vaddl.u8 q10, d22, d23 vsubl.u8 q11, d22, d23 vtrn.16 q12, q13 SUMSUB_ABCD q0, q2, q1, q3, q8, q10, q9, q11 vtrn.16 q14, q15 SUMSUB_AB q8, q9, q12, q13 vtrn.16 q0, q1 SUMSUB_AB q10, q11, q14, q15 vtrn.16 q2, q3 SUMSUB_AB q12, q13, q0, q1 vtrn.32 q8, q10 SUMSUB_AB q14, q15, q2, q3 vtrn.32 q9, q11 SUMSUB_AB q0, q2, q8, q10 vtrn.32 q12, q14 SUMSUB_AB q1, q3, q9, q11 vtrn.32 q13, q15 SUMSUB_ABCD q8, q10, q9, q11, q12, q14, q13, q15 vabs.s16 q12, q0 vabs.s16 q13, q8 vabs.s16 q15, q1 vadd.s16 q12, q12, q13 vabs.s16 q14, q2 vand.s16 q12, q12, q6 vabs.s16 q13, q3 vadd.s16 q12, q12, q15 vabs.s16 q15, q9 vadd.s16 q12, q12, q14 vabs.s16 q14, q10 vadd.s16 q12, q12, q13 vabs.s16 q13, q11 vadd.s16 q12, q12, q15 vsub.s16 q15, q11, q3 vadd.s16 q12, q12, q14 vadd.s16 q14, q11, q3 vadd.s16 q12, q12, q13 vsub.s16 q13, q10, q2 vadd.s16 q2, q10, q2 vpadal.u16 q4, q12 SUMSUB_AB q10, q11, q9, q1 SUMSUB_AB q9, q8, q0, q8 vswp d29, d30 vabs.s16 q14, q14 vabs.s16 q15, q15 vswp d5, d26 vabs.s16 q2, q2 vabs.s16 q13, q13 vswp d21, d22 vabs.s16 q10, q10 vabs.s16 q11, q11 vmax.s16 q3, q14, q15 vmax.s16 q2, q2, q13 vmax.s16 q1, q10, q11 vswp d19, d16 SUMSUB_AB q14, q15, q9, q8 vadd.s16 q2, q2, q3 vadd.s16 q2, q2, q1 vand q14, q14, q7 vadd.s16 q2, q2, q2 vabs.s16 q15, q15 vabs.s16 q14, q14 vadd.s16 q2, q2, q15 vadd.s16 q2, q2, q14 vpadal.u16 q5, q2 bx lr endfunc .macro SSIM_ITER n ssa s12 ssb lastssa lasts12 lastssb da db dnext vld1.64 {\db}, [r2], r3 vmull.u8 \ssa, \da, \da vmull.u8 \s12, \da, \db .if \n == 1 vpaddl.u16 q2, \lastssa vpaddl.u16 q3, \lasts12 vaddl.u8 q0, d0, \da .else vpadal.u16 q2, \lastssa vpadal.u16 q3, \lasts12 vaddw.u8 q0, q0, \da .endif vpadal.u16 q2, \lastssb .if \n < 3 vld1.64 {\dnext}, [r0], r1 .endif .if \n == 1 vaddl.u8 q1, d2, \db .else vaddw.u8 q1, q1, \db .endif vmull.u8 \ssb, \db, \db .endm function x264_pixel_ssim_4x4x2_core_neon ldr ip, [sp] vld1.64 {d0}, [r0], r1 vld1.64 {d2}, [r2], r3 vmull.u8 q2, d0, d0 vmull.u8 q3, d0, d2 vld1.64 {d28}, [r0], r1 vmull.u8 q15, d2, d2 SSIM_ITER 1, q8, q9, q14, q2, q3, q15, d28, d29, d26 SSIM_ITER 2, q10,q11,q13, q8, q9, q14, d26, d27, d28 SSIM_ITER 3, q8, q9, q15, q10,q11,q13, d28, d29 vpadal.u16 q2, q8 vpaddl.u16 q0, q0 vpaddl.u16 q1, q1 vpadal.u16 q2, q15 vpadal.u16 q3, q9 vpadd.u32 d0, d0, d1 vpadd.u32 d1, d2, d3 vpadd.u32 d2, d4, d5 vpadd.u32 d3, d6, d7 vst4.32 {d0-d3}, [ip] bx lr endfunc // FIXME: see about doing 16x16 -> 32 bit multiplies for s1/s2 function x264_pixel_ssim_end4_neon vld1.32 {d16-d19}, [r0,:128]! vld1.32 {d20-d23}, [r1,:128]! vadd.s32 q0, q8, q10 vadd.s32 q1, q9, q11 vld1.32 {d24-d27}, [r0,:128]! vadd.s32 q0, q0, q1 vld1.32 {d28-d31}, [r1,:128]! vadd.s32 q2, q12, q14 vadd.s32 q3, q13, q15 vld1.32 {d16-d17}, [r0,:128] vadd.s32 q1, q1, q2 vld1.32 {d18-d19}, [r1,:128] vadd.s32 q8, q8, q9 vadd.s32 q2, q2, q3 vadd.s32 q3, q3, q8 vtrn.32 q0, q1 vtrn.32 q2, q3 vswp d1, d4 vswp d3, d6 // s1=q0, s2=q1, ss=q2, s12=q3 vmul.s32 q8, q0, q1 // s1*s2 vmul.s32 q0, q0, q0 vmla.s32 q0, q1, q1 // s1*s1 + s2*s2 vshl.s32 q3, q3, #7 vshl.s32 q2, q2, #6 vadd.s32 q1, q8, q8 mov r3, #416 // ssim_c1 = .01*.01*255*255*64 movconst ip, 235963 // ssim_c2 = .03*.03*255*255*64*63 vdup.32 q14, r3 vdup.32 q15, ip vsub.s32 q2, q2, q0 // vars vsub.s32 q3, q3, q1 // covar*2 vadd.s32 q0, q0, q14 vadd.s32 q2, q2, q15 vadd.s32 q1, q1, q14 vadd.s32 q3, q3, q15 vcvt.f32.s32 q0, q0 vcvt.f32.s32 q2, q2 vcvt.f32.s32 q1, q1 vcvt.f32.s32 q3, q3 vmul.f32 q0, q0, q2 vmul.f32 q1, q1, q3 cmp r2, #4 vdiv.f32 s0, s4, s0 vdiv.f32 s1, s5, s1 vdiv.f32 s2, s6, s2 vdiv.f32 s3, s7, s3 beq ssim_skip movrel r3, mask_ff sub r3, r3, r2, lsl #2 vld1.64 {d6-d7}, [r3] vand q0, q0, q3 ssim_skip: vadd.f32 d0, d0, d1 vpadd.f32 d0, d0, d0 vmov.32 r0, d0[0] bx lr endfunc