From d8de3cd6cd17821eac3ea98a285e4d813ab6e410 Mon Sep 17 00:00:00 2001 From: Leo Ma Date: Wed, 30 Aug 2017 17:50:50 +0800 Subject: [PATCH] Upgrade libx264 Signed-off-by: Leo Ma --- library/src/main/cpp/libx264/Makefile | 3 +- .../main/cpp/libx264/common/aarch64/pixel-a.S | 72 +- .../main/cpp/libx264/common/aarch64/pixel.h | 4 +- library/src/main/cpp/libx264/common/arm/asm.S | 23 +- .../src/main/cpp/libx264/common/arm/dct-a.S | 6 +- .../src/main/cpp/libx264/common/arm/mc-a.S | 7 +- .../src/main/cpp/libx264/common/arm/pixel-a.S | 132 +-- .../src/main/cpp/libx264/common/arm/pixel.h | 4 +- .../main/cpp/libx264/common/arm/predict-a.S | 7 +- .../src/main/cpp/libx264/common/arm/quant-a.S | 11 +- .../src/main/cpp/libx264/common/bitstream.c | 42 +- library/src/main/cpp/libx264/common/cabac.h | 2 +- library/src/main/cpp/libx264/common/common.c | 4 +- library/src/main/cpp/libx264/common/common.h | 38 +- library/src/main/cpp/libx264/common/cpu.c | 68 +- library/src/main/cpp/libx264/common/cpu.h | 4 +- library/src/main/cpp/libx264/common/dct.c | 34 + library/src/main/cpp/libx264/common/dct.h | 1 - library/src/main/cpp/libx264/common/deblock.c | 35 +- library/src/main/cpp/libx264/common/frame.c | 18 +- .../src/main/cpp/libx264/common/macroblock.c | 18 +- library/src/main/cpp/libx264/common/mc.c | 18 +- library/src/main/cpp/libx264/common/mc.h | 35 + library/src/main/cpp/libx264/common/osdep.h | 40 +- library/src/main/cpp/libx264/common/pixel.c | 89 +- library/src/main/cpp/libx264/common/pixel.h | 3 +- library/src/main/cpp/libx264/common/ppc/dct.c | 20 +- library/src/main/cpp/libx264/common/ppc/mc.c | 13 - library/src/main/cpp/libx264/common/quant.c | 105 ++- .../main/cpp/libx264/common/x86/cabac-a.asm | 120 +-- .../src/main/cpp/libx264/common/x86/cpu-a.asm | 22 +- .../src/main/cpp/libx264/common/x86/dct-a.asm | 405 ++++++++- library/src/main/cpp/libx264/common/x86/dct.h | 61 +- .../main/cpp/libx264/common/x86/deblock-a.asm | 315 +++---- .../src/main/cpp/libx264/common/x86/mc-a.asm | 99 ++- .../src/main/cpp/libx264/common/x86/mc-a2.asm | 375 +++++--- .../src/main/cpp/libx264/common/x86/mc-c.c | 128 ++- .../main/cpp/libx264/common/x86/pixel-a.asm | 825 +++++++++++++----- .../src/main/cpp/libx264/common/x86/pixel.h | 31 +- .../main/cpp/libx264/common/x86/predict-a.asm | 4 +- .../main/cpp/libx264/common/x86/predict-c.c | 6 +- .../src/main/cpp/libx264/common/x86/predict.h | 6 +- .../main/cpp/libx264/common/x86/quant-a.asm | 702 ++++++++++----- .../src/main/cpp/libx264/common/x86/quant.h | 41 +- .../src/main/cpp/libx264/common/x86/sad-a.asm | 498 ++++++++--- .../main/cpp/libx264/common/x86/x86inc.asm | 252 ++++-- .../main/cpp/libx264/common/x86/x86util.asm | 26 +- .../src/main/cpp/libx264/encoder/analyse.c | 118 ++- library/src/main/cpp/libx264/encoder/cabac.c | 42 +- .../src/main/cpp/libx264/encoder/encoder.c | 35 +- .../src/main/cpp/libx264/encoder/macroblock.c | 58 +- .../src/main/cpp/libx264/encoder/macroblock.h | 7 +- library/src/main/cpp/libx264/encoder/me.c | 12 +- library/src/main/cpp/libx264/encoder/me.h | 10 +- .../main/cpp/libx264/encoder/ratecontrol.c | 6 +- .../main/cpp/libx264/encoder/ratecontrol.h | 2 - library/src/main/cpp/libx264/encoder/rdo.c | 11 +- library/src/main/cpp/libx264/encoder/set.c | 37 +- .../src/main/cpp/libx264/encoder/slicetype.c | 23 +- .../main/cpp/libx264/filters/video/resize.c | 6 +- library/src/main/cpp/libx264/input/input.c | 2 + library/src/main/cpp/libx264/input/raw.c | 1 + library/src/main/cpp/libx264/input/y4m.c | 1 + .../cpp/libx264/libs/armeabi-v7a/libx264.a | Bin 1190058 -> 1077706 bytes .../src/main/cpp/libx264/libs/x86/libx264.a | Bin 1680312 -> 1160866 bytes .../src/main/cpp/libx264/tools/checkasm-a.asm | 15 + .../main/cpp/libx264/tools/checkasm-aarch64.S | 10 +- .../src/main/cpp/libx264/tools/checkasm-arm.S | 8 +- library/src/main/cpp/libx264/tools/checkasm.c | 243 +++--- .../cpp/libx264/tools/gas-preprocessor.pl | 46 +- .../src/main/cpp/libx264/tools/msvsdepend.sh | 6 + library/src/main/cpp/libx264/x264.c | 60 +- library/src/main/cpp/libx264/x264.h | 99 +-- library/src/main/cpp/libx264/x264_config.h | 2 +- 74 files changed, 3804 insertions(+), 1828 deletions(-) diff --git a/library/src/main/cpp/libx264/Makefile b/library/src/main/cpp/libx264/Makefile index d0b1633..81bce65 100644 --- a/library/src/main/cpp/libx264/Makefile +++ b/library/src/main/cpp/libx264/Makefile @@ -278,7 +278,8 @@ clean: rm -f $(SRC2:%.c=%.gcda) $(SRC2:%.c=%.gcno) *.dyn pgopti.dpi pgopti.dpi.lock *.pgd *.pgc distclean: clean - rm -f config.mak x264_config.h config.h config.log x264.pc x264.def conftest* + rm -f config.mak x264_config.h config.h config.log x264.pc x264.def + rm -rf conftest* install-cli: cli $(INSTALL) -d $(DESTDIR)$(bindir) diff --git a/library/src/main/cpp/libx264/common/aarch64/pixel-a.S b/library/src/main/cpp/libx264/common/aarch64/pixel-a.S index 48209b2..047d3db 100644 --- a/library/src/main/cpp/libx264/common/aarch64/pixel-a.S +++ b/library/src/main/cpp/libx264/common/aarch64/pixel-a.S @@ -569,57 +569,65 @@ endfunc .macro pixel_var2_8 h function x264_pixel_var2_8x\h\()_neon, export=1 - ld1 {v16.8b}, [x0], x1 - ld1 {v18.8b}, [x2], x3 - ld1 {v17.8b}, [x0], x1 - ld1 {v19.8b}, [x2], x3 - mov x5, \h - 4 - usubl v6.8h, v16.8b, v18.8b - usubl v7.8h, v17.8b, v19.8b - ld1 {v16.8b}, [x0], x1 - ld1 {v18.8b}, [x2], x3 - smull v2.4s, v6.4h, v6.4h - smull2 v3.4s, v6.8h, v6.8h - add v0.8h, v6.8h, v7.8h - smlal v2.4s, v7.4h, v7.4h - smlal2 v3.4s, v7.8h, v7.8h + mov x3, #16 + ld1 {v16.8b}, [x0], #8 + ld1 {v18.8b}, [x1], x3 + ld1 {v17.8b}, [x0], #8 + ld1 {v19.8b}, [x1], x3 + mov x5, \h - 2 + usubl v0.8h, v16.8b, v18.8b + usubl v1.8h, v17.8b, v19.8b + ld1 {v16.8b}, [x0], #8 + ld1 {v18.8b}, [x1], x3 + smull v2.4s, v0.4h, v0.4h + smull2 v3.4s, v0.8h, v0.8h + smull v4.4s, v1.4h, v1.4h + smull2 v5.4s, v1.8h, v1.8h usubl v6.8h, v16.8b, v18.8b -1: subs x5, x5, #2 - ld1 {v17.8b}, [x0], x1 - ld1 {v19.8b}, [x2], x3 +1: subs x5, x5, #1 + ld1 {v17.8b}, [x0], #8 + ld1 {v19.8b}, [x1], x3 smlal v2.4s, v6.4h, v6.4h smlal2 v3.4s, v6.8h, v6.8h usubl v7.8h, v17.8b, v19.8b add v0.8h, v0.8h, v6.8h - ld1 {v16.8b}, [x0], x1 - ld1 {v18.8b}, [x2], x3 - smlal v2.4s, v7.4h, v7.4h - smlal2 v3.4s, v7.8h, v7.8h + ld1 {v16.8b}, [x0], #8 + ld1 {v18.8b}, [x1], x3 + smlal v4.4s, v7.4h, v7.4h + smlal2 v5.4s, v7.8h, v7.8h usubl v6.8h, v16.8b, v18.8b - add v0.8h, v0.8h, v7.8h + add v1.8h, v1.8h, v7.8h b.gt 1b - ld1 {v17.8b}, [x0], x1 - ld1 {v19.8b}, [x2], x3 + ld1 {v17.8b}, [x0], #8 + ld1 {v19.8b}, [x1], x3 smlal v2.4s, v6.4h, v6.4h smlal2 v3.4s, v6.8h, v6.8h usubl v7.8h, v17.8b, v19.8b add v0.8h, v0.8h, v6.8h - smlal v2.4s, v7.4h, v7.4h - add v0.8h, v0.8h, v7.8h - smlal2 v3.4s, v7.8h, v7.8h + smlal v4.4s, v7.4h, v7.4h + add v1.8h, v1.8h, v7.8h + smlal2 v5.4s, v7.8h, v7.8h saddlv s0, v0.8h + saddlv s1, v1.8h add v2.4s, v2.4s, v3.4s + add v4.4s, v4.4s, v5.4s mov w0, v0.s[0] - addv s1, v2.4s - sxtw x0, w0 mov w1, v1.s[0] - mul x0, x0, x0 - str w1, [x4] - sub x0, x1, x0, lsr # 6 + (\h >> 4) + addv s2, v2.4s + addv s4, v4.4s + mul w0, w0, w0 + mul w1, w1, w1 + mov w3, v2.s[0] + mov w4, v4.s[0] + sub w0, w3, w0, lsr # 6 + (\h >> 4) + sub w1, w4, w1, lsr # 6 + (\h >> 4) + str w3, [x2] + add w0, w0, w1 + str w4, [x2, #4] ret endfunc diff --git a/library/src/main/cpp/libx264/common/aarch64/pixel.h b/library/src/main/cpp/libx264/common/aarch64/pixel.h index 8a7b83e..5206a0c 100644 --- a/library/src/main/cpp/libx264/common/aarch64/pixel.h +++ b/library/src/main/cpp/libx264/common/aarch64/pixel.h @@ -61,8 +61,8 @@ uint64_t x264_pixel_sa8d_satd_16x16_neon( uint8_t *, intptr_t, uint8_t *, intptr uint64_t x264_pixel_var_8x8_neon ( uint8_t *, intptr_t ); uint64_t x264_pixel_var_8x16_neon ( uint8_t *, intptr_t ); uint64_t x264_pixel_var_16x16_neon( uint8_t *, intptr_t ); -int x264_pixel_var2_8x8_neon ( uint8_t *, intptr_t, uint8_t *, intptr_t, int * ); -int x264_pixel_var2_8x16_neon( uint8_t *, intptr_t, uint8_t *, intptr_t, int * ); +int x264_pixel_var2_8x8_neon ( uint8_t *, uint8_t *, int * ); +int x264_pixel_var2_8x16_neon( uint8_t *, uint8_t *, int * ); uint64_t x264_pixel_hadamard_ac_8x8_neon ( uint8_t *, intptr_t ); uint64_t x264_pixel_hadamard_ac_8x16_neon ( uint8_t *, intptr_t ); diff --git a/library/src/main/cpp/libx264/common/arm/asm.S b/library/src/main/cpp/libx264/common/arm/asm.S index 62a5e57..0472d11 100644 --- a/library/src/main/cpp/libx264/common/arm/asm.S +++ b/library/src/main/cpp/libx264/common/arm/asm.S @@ -28,15 +28,10 @@ .syntax unified -#if HAVE_NEON - .arch armv7-a -#elif HAVE_ARMV6T2 - .arch armv6t2 -#elif HAVE_ARMV6 - .arch armv6 -#endif - +#ifndef __APPLE__ +.arch armv7-a .fpu neon +#endif #ifdef PREFIX # define EXTERN_ASM _ @@ -50,6 +45,14 @@ # define ELF @ #endif +#ifdef __MACH__ +# define MACH +# define NONMACH @ +#else +# define MACH @ +# define NONMACH +#endif + #if HAVE_AS_FUNC # define FUNC #else @@ -76,6 +79,7 @@ ELF .size \name, . - \name FUNC .endfunc .purgem endfunc .endm + .text .align 2 .if \export == 1 .global EXTERN_ASM\name @@ -99,7 +103,8 @@ ELF .size \name, . - \name .if HAVE_SECTION_DATA_REL_RO && \relocate .section .data.rel.ro .else - .section .rodata +NONMACH .section .rodata +MACH .const_data .endif .align \align \name: diff --git a/library/src/main/cpp/libx264/common/arm/dct-a.S b/library/src/main/cpp/libx264/common/arm/dct-a.S index 13d5061..48a3498 100644 --- a/library/src/main/cpp/libx264/common/arm/dct-a.S +++ b/library/src/main/cpp/libx264/common/arm/dct-a.S @@ -26,14 +26,12 @@ #include "asm.S" -.section .rodata -.align 4 - -scan4x4_frame: +const scan4x4_frame, align=4 .byte 0,1, 8,9, 2,3, 4,5 .byte 2,3, 8,9, 16,17, 10,11 .byte 12,13, 6,7, 14,15, 20,21 .byte 10,11, 12,13, 6,7, 14,15 +endconst .text diff --git a/library/src/main/cpp/libx264/common/arm/mc-a.S b/library/src/main/cpp/libx264/common/arm/mc-a.S index e8d3d03..2d6dc2e 100644 --- a/library/src/main/cpp/libx264/common/arm/mc-a.S +++ b/library/src/main/cpp/libx264/common/arm/mc-a.S @@ -28,10 +28,9 @@ #include "asm.S" -.section .rodata -.align 4 -pw_0to15: +const pw_0to15, align=4 .short 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 +endconst .text @@ -140,7 +139,7 @@ MEMCPY_ALIGNED 16, 8 MEMCPY_ALIGNED 8, 16 MEMCPY_ALIGNED 8, 8 -const memcpy_table align=2, relocate=1 +const memcpy_table, align=2, relocate=1 .word memcpy_aligned_16_16_neon .word memcpy_aligned_16_8_neon .word memcpy_aligned_8_16_neon diff --git a/library/src/main/cpp/libx264/common/arm/pixel-a.S b/library/src/main/cpp/libx264/common/arm/pixel-a.S index a1a0673..155e1cf 100644 --- a/library/src/main/cpp/libx264/common/arm/pixel-a.S +++ b/library/src/main/cpp/libx264/common/arm/pixel-a.S @@ -26,9 +26,7 @@ #include "asm.S" -.section .rodata -.align 4 - +const mask_array, align=4 .rept 16 .byte 0xff .endr @@ -36,11 +34,14 @@ mask_ff: .rept 16 .byte 0 .endr +endconst -mask_ac4: +const mask_ac4, align=4 .short 0, -1, -1, -1, 0, -1, -1, -1 -mask_ac8: +endconst +const mask_ac8, align=4 .short 0, -1, -1, -1, -1, -1, -1, -1 +endconst .text @@ -718,13 +719,24 @@ function x264_var_end, export=0 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 +.macro DIFF_SUM diff1 diff2 da1 db1 da2 db2 lastdiff1 lastdiff2 acc1 acc2 + vld1.64 {\da1}, [r0,:64]! + vld1.64 {\db1}, [r1,:64], r3 +.ifnb \lastdiff1 + vadd.s16 \acc1, \acc1, \lastdiff1 + vadd.s16 \acc2, \acc2, \lastdiff2 .endif - vsubl.u8 \diff, \da, \db + vld1.64 {\da2}, [r0,:64]! + vld1.64 {\db2}, [r1,:64], r3 + vsubl.u8 \diff1, \da1, \db1 + vsubl.u8 \diff2, \da2, \db2 +.endm + +.macro SQR_ACC_DOUBLE acc1 acc2 d0 d1 d2 d3 vmlal=vmlal.s16 + \vmlal \acc1, \d0, \d0 + vmlal.s16 \acc1, \d1, \d1 + \vmlal \acc2, \d2, \d2 + vmlal.s16 \acc2, \d3, \d3 .endm .macro SQR_ACC acc d0 d1 vmlal=vmlal.s16 @@ -733,77 +745,89 @@ endfunc .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 + mov r3, #16 + DIFF_SUM q0, q10, d0, d1, d20, d21 + DIFF_SUM q8, q11, d16, d17, d22, d23 + SQR_ACC_DOUBLE q1, q13, d0, d1, d20, d21, vmull.s16 + DIFF_SUM q9, q12, d18, d19, d24, d25, q8, q11, q0, q10 + SQR_ACC_DOUBLE q2, q14, d16, d17, d22, d23, 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 + DIFF_SUM q8, q11, d16, d17, d22, d23, q9, q12, q0, q10 + SQR_ACC_DOUBLE q1, q13, d18, d19, d24, d25 + DIFF_SUM q9, q12, d18, d19, d24, d25, q8, q11, q0, q10 + SQR_ACC_DOUBLE q2, q14, d16, d17, d22, d23 .endr - DIFF_SUM q8, d16, d17, q9 - SQR_ACC q1, d18, d19 + DIFF_SUM q8, q11, d16, d17, d22, d23, q9, q12, q0, q10 + SQR_ACC_DOUBLE q1, q13, d18, d19, d24, d25 vadd.s16 q0, q0, q8 - SQR_ACC q2, d16, d17 + vadd.s16 q10, q10, q11 + SQR_ACC_DOUBLE q2, q14, d16, d17, d22, d23 - ldr ip, [sp] vadd.s16 d0, d0, d1 + vadd.s16 d20, d20, d21 vadd.s32 q1, q1, q2 + vadd.s32 q13, q13, q14 vpaddl.s16 d0, d0 + vpaddl.s16 d20, d20 vadd.s32 d1, d2, d3 - vpadd.s32 d0, d0, d1 + vadd.s32 d26, d26, d27 + vpadd.s32 d0, d0, d20 @ sum + vpadd.s32 d1, d1, d26 @ sqr + vmul.s32 d0, d0, d0 @ sum*sum + vshr.s32 d0, d0, #6 + vsub.s32 d0, d1, d0 + vpadd.s32 d0, d0, d0 vmov r0, r1, d0 - vst1.32 {d0[1]}, [ip,:32] - mul r0, r0, r0 - sub r0, r1, r0, lsr #6 + vst1.32 {d1}, [r2,:64] 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 + mov r3, #16 + vld1.64 {d16}, [r0,:64]! + vld1.64 {d17}, [r1,:64], r3 + vld1.64 {d18}, [r0,:64]! + vld1.64 {d19}, [r1,:64], r3 + vsubl.u8 q0, d16, d17 + vsubl.u8 q3, d18, d19 + SQR_ACC q1, d0, d1, vmull.s16 + vld1.64 {d16}, [r0,:64]! + mov ip, #15 + vld1.64 {d17}, [r1,:64], r3 + SQR_ACC q2, d6, d7, vmull.s16 +1: subs ip, ip, #1 + vld1.64 {d18}, [r0,:64]! vsubl.u8 q10, d16, d17 - vld1.64 {d19}, [r2,:64], r3 + vld1.64 {d19}, [r1,: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 + vld1.64 {d16}, [r0,:64]! + vadd.s16 q3, q3, q11 + vld1.64 {d17}, [r1,:64], r3 SQR_ACC q2, d22, d23 b 1b 2: - vadd.s16 q0, q0, q11 + vadd.s16 q3, q3, q11 SQR_ACC q2, d22, d23 - ldr ip, [sp] vadd.s16 d0, d0, d1 - vadd.s32 q1, q1, q2 + vadd.s16 d6, d6, d7 vpaddl.s16 d0, d0 - vadd.s32 d1, d2, d3 - vpadd.s32 d0, d0, d1 + vpaddl.s16 d6, d6 + vadd.s32 d2, d2, d3 + vadd.s32 d4, d4, d5 + vpadd.s32 d0, d0, d6 @ sum + vpadd.s32 d2, d2, d4 @ sqr + vmul.s32 d0, d0, d0 @ sum*sum + vshr.s32 d0, d0, #7 + vsub.s32 d0, d2, d0 + vpadd.s32 d0, d0, d0 vmov r0, r1, d0 - vst1.32 {d0[1]}, [ip,:32] - mul r0, r0, r0 - sub r0, r1, r0, lsr #7 + vst1.32 {d2}, [r2,:64] bx lr endfunc diff --git a/library/src/main/cpp/libx264/common/arm/pixel.h b/library/src/main/cpp/libx264/common/arm/pixel.h index 8a6751b..d9b02c4 100644 --- a/library/src/main/cpp/libx264/common/arm/pixel.h +++ b/library/src/main/cpp/libx264/common/arm/pixel.h @@ -63,8 +63,8 @@ uint64_t x264_pixel_sa8d_satd_16x16_neon( uint8_t *, intptr_t, uint8_t *, intptr uint64_t x264_pixel_var_8x8_neon ( uint8_t *, intptr_t ); uint64_t x264_pixel_var_8x16_neon ( uint8_t *, intptr_t ); uint64_t x264_pixel_var_16x16_neon( uint8_t *, intptr_t ); -int x264_pixel_var2_8x8_neon ( uint8_t *, intptr_t, uint8_t *, intptr_t, int * ); -int x264_pixel_var2_8x16_neon( uint8_t *, intptr_t, uint8_t *, intptr_t, int * ); +int x264_pixel_var2_8x8_neon ( uint8_t *, uint8_t *, int * ); +int x264_pixel_var2_8x16_neon( uint8_t *, uint8_t *, int * ); uint64_t x264_pixel_hadamard_ac_8x8_neon ( uint8_t *, intptr_t ); uint64_t x264_pixel_hadamard_ac_8x16_neon ( uint8_t *, intptr_t ); diff --git a/library/src/main/cpp/libx264/common/arm/predict-a.S b/library/src/main/cpp/libx264/common/arm/predict-a.S index a7d9f10..06366cc 100644 --- a/library/src/main/cpp/libx264/common/arm/predict-a.S +++ b/library/src/main/cpp/libx264/common/arm/predict-a.S @@ -27,10 +27,9 @@ #include "asm.S" -.section .rodata -.align 4 - -p16weight: .short 1,2,3,4,5,6,7,8 +const p16weight, align=4 +.short 1,2,3,4,5,6,7,8 +endconst .text diff --git a/library/src/main/cpp/libx264/common/arm/quant-a.S b/library/src/main/cpp/libx264/common/arm/quant-a.S index eb3fd36..a7f6cd2 100644 --- a/library/src/main/cpp/libx264/common/arm/quant-a.S +++ b/library/src/main/cpp/libx264/common/arm/quant-a.S @@ -26,19 +26,20 @@ #include "asm.S" -.section .rodata -.align 4 -pmovmskb_byte: +const pmovmskb_byte, align=4 .byte 1,2,4,8,16,32,64,128 .byte 1,2,4,8,16,32,64,128 +endconst -mask_2bit: +const mask_2bit, align=4 .byte 3,12,48,192,3,12,48,192 .byte 3,12,48,192,3,12,48,192 +endconst -mask_1bit: +const mask_1bit, align=4 .byte 128,64,32,16,8,4,2,1 .byte 128,64,32,16,8,4,2,1 +endconst .text diff --git a/library/src/main/cpp/libx264/common/bitstream.c b/library/src/main/cpp/libx264/common/bitstream.c index d6c1c2c..cc76300 100644 --- a/library/src/main/cpp/libx264/common/bitstream.c +++ b/library/src/main/cpp/libx264/common/bitstream.c @@ -43,16 +43,19 @@ uint8_t *x264_nal_escape_mmx2( uint8_t *dst, uint8_t *src, uint8_t *end ); uint8_t *x264_nal_escape_sse2( uint8_t *dst, uint8_t *src, uint8_t *end ); uint8_t *x264_nal_escape_avx2( uint8_t *dst, uint8_t *src, uint8_t *end ); void x264_cabac_block_residual_rd_internal_sse2 ( dctcoef *l, int b_interlaced, intptr_t ctx_block_cat, x264_cabac_t *cb ); -void x264_cabac_block_residual_rd_internal_sse2_lzcnt ( dctcoef *l, int b_interlaced, intptr_t ctx_block_cat, x264_cabac_t *cb ); +void x264_cabac_block_residual_rd_internal_lzcnt ( dctcoef *l, int b_interlaced, intptr_t ctx_block_cat, x264_cabac_t *cb ); void x264_cabac_block_residual_rd_internal_ssse3 ( dctcoef *l, int b_interlaced, intptr_t ctx_block_cat, x264_cabac_t *cb ); void x264_cabac_block_residual_rd_internal_ssse3_lzcnt( dctcoef *l, int b_interlaced, intptr_t ctx_block_cat, x264_cabac_t *cb ); +void x264_cabac_block_residual_rd_internal_avx512 ( dctcoef *l, int b_interlaced, intptr_t ctx_block_cat, x264_cabac_t *cb ); void x264_cabac_block_residual_8x8_rd_internal_sse2 ( dctcoef *l, int b_interlaced, intptr_t ctx_block_cat, x264_cabac_t *cb ); -void x264_cabac_block_residual_8x8_rd_internal_sse2_lzcnt ( dctcoef *l, int b_interlaced, intptr_t ctx_block_cat, x264_cabac_t *cb ); +void x264_cabac_block_residual_8x8_rd_internal_lzcnt ( dctcoef *l, int b_interlaced, intptr_t ctx_block_cat, x264_cabac_t *cb ); void x264_cabac_block_residual_8x8_rd_internal_ssse3 ( dctcoef *l, int b_interlaced, intptr_t ctx_block_cat, x264_cabac_t *cb ); void x264_cabac_block_residual_8x8_rd_internal_ssse3_lzcnt( dctcoef *l, int b_interlaced, intptr_t ctx_block_cat, x264_cabac_t *cb ); -void x264_cabac_block_residual_internal_sse2 ( dctcoef *l, int b_interlaced, intptr_t ctx_block_cat, x264_cabac_t *cb ); -void x264_cabac_block_residual_internal_sse2_lzcnt( dctcoef *l, int b_interlaced, intptr_t ctx_block_cat, x264_cabac_t *cb ); -void x264_cabac_block_residual_internal_avx2_bmi2 ( dctcoef *l, int b_interlaced, intptr_t ctx_block_cat, x264_cabac_t *cb ); +void x264_cabac_block_residual_8x8_rd_internal_avx512 ( dctcoef *l, int b_interlaced, intptr_t ctx_block_cat, x264_cabac_t *cb ); +void x264_cabac_block_residual_internal_sse2 ( dctcoef *l, int b_interlaced, intptr_t ctx_block_cat, x264_cabac_t *cb ); +void x264_cabac_block_residual_internal_lzcnt ( dctcoef *l, int b_interlaced, intptr_t ctx_block_cat, x264_cabac_t *cb ); +void x264_cabac_block_residual_internal_avx2 ( dctcoef *l, int b_interlaced, intptr_t ctx_block_cat, x264_cabac_t *cb ); +void x264_cabac_block_residual_internal_avx512( dctcoef *l, int b_interlaced, intptr_t ctx_block_cat, x264_cabac_t *cb ); uint8_t *x264_nal_escape_neon( uint8_t *dst, uint8_t *src, uint8_t *end ); @@ -116,7 +119,7 @@ void x264_bitstream_init( int cpu, x264_bitstream_function_t *pf ) pf->nal_escape = x264_nal_escape_c; #if HAVE_MMX -#if ARCH_X86_64 +#if ARCH_X86_64 && !defined( __MACH__ ) pf->cabac_block_residual_internal = x264_cabac_block_residual_internal_sse2; pf->cabac_block_residual_rd_internal = x264_cabac_block_residual_rd_internal_sse2; pf->cabac_block_residual_8x8_rd_internal = x264_cabac_block_residual_8x8_rd_internal_sse2; @@ -126,18 +129,17 @@ void x264_bitstream_init( int cpu, x264_bitstream_function_t *pf ) pf->nal_escape = x264_nal_escape_mmx2; if( cpu&X264_CPU_SSE2 ) { -#if ARCH_X86_64 - if( cpu&X264_CPU_LZCNT ) - { - pf->cabac_block_residual_internal = x264_cabac_block_residual_internal_sse2_lzcnt; - pf->cabac_block_residual_rd_internal = x264_cabac_block_residual_rd_internal_sse2_lzcnt; - pf->cabac_block_residual_8x8_rd_internal = x264_cabac_block_residual_8x8_rd_internal_sse2_lzcnt; - } -#endif if( cpu&X264_CPU_SSE2_IS_FAST ) pf->nal_escape = x264_nal_escape_sse2; } -#if ARCH_X86_64 +#if ARCH_X86_64 && !defined( __MACH__ ) + if( cpu&X264_CPU_LZCNT ) + { + pf->cabac_block_residual_internal = x264_cabac_block_residual_internal_lzcnt; + pf->cabac_block_residual_rd_internal = x264_cabac_block_residual_rd_internal_lzcnt; + pf->cabac_block_residual_8x8_rd_internal = x264_cabac_block_residual_8x8_rd_internal_lzcnt; + } + if( cpu&X264_CPU_SSSE3 ) { pf->cabac_block_residual_rd_internal = x264_cabac_block_residual_rd_internal_ssse3; @@ -152,8 +154,14 @@ void x264_bitstream_init( int cpu, x264_bitstream_function_t *pf ) if( cpu&X264_CPU_AVX2 ) { pf->nal_escape = x264_nal_escape_avx2; - if( cpu&X264_CPU_BMI2 ) - pf->cabac_block_residual_internal = x264_cabac_block_residual_internal_avx2_bmi2; + pf->cabac_block_residual_internal = x264_cabac_block_residual_internal_avx2; + } + + if( cpu&X264_CPU_AVX512 ) + { + pf->cabac_block_residual_internal = x264_cabac_block_residual_internal_avx512; + pf->cabac_block_residual_rd_internal = x264_cabac_block_residual_rd_internal_avx512; + pf->cabac_block_residual_8x8_rd_internal = x264_cabac_block_residual_8x8_rd_internal_avx512; } #endif #endif diff --git a/library/src/main/cpp/libx264/common/cabac.h b/library/src/main/cpp/libx264/common/cabac.h index 5af856a..1378834 100644 --- a/library/src/main/cpp/libx264/common/cabac.h +++ b/library/src/main/cpp/libx264/common/cabac.h @@ -42,7 +42,7 @@ typedef struct uint8_t *p_end; /* aligned for memcpy_aligned starting here */ - ALIGNED_16( int f8_bits_encoded ); // only if using x264_cabac_size_decision() + ALIGNED_64( int f8_bits_encoded ); // only if using x264_cabac_size_decision() /* context */ uint8_t state[1024]; diff --git a/library/src/main/cpp/libx264/common/common.c b/library/src/main/cpp/libx264/common/common.c index 14d4670..561212d 100644 --- a/library/src/main/cpp/libx264/common/common.c +++ b/library/src/main/cpp/libx264/common/common.c @@ -669,7 +669,7 @@ int x264_param_parse( x264_param_t *p, const char *name, const char *value ) { if( !strcmp(value, "1b") ) p->i_level_idc = 9; - else if( atof(value) < 6 ) + else if( atof(value) < 7 ) p->i_level_idc = (int)(10*atof(value)+.5); else p->i_level_idc = atoi(value); @@ -1143,6 +1143,8 @@ int x264_picture_alloc( x264_picture_t *pic, int i_csp, int i_width, int i_heigh [X264_CSP_I422] = { 3, { 256*1, 256/2, 256/2 }, { 256*1, 256*1, 256*1 } }, [X264_CSP_YV16] = { 3, { 256*1, 256/2, 256/2 }, { 256*1, 256*1, 256*1 } }, [X264_CSP_NV16] = { 2, { 256*1, 256*1 }, { 256*1, 256*1 }, }, + [X264_CSP_YUYV] = { 1, { 256*2 }, { 256*1 }, }, + [X264_CSP_UYVY] = { 1, { 256*2 }, { 256*1 }, }, [X264_CSP_I444] = { 3, { 256*1, 256*1, 256*1 }, { 256*1, 256*1, 256*1 } }, [X264_CSP_YV24] = { 3, { 256*1, 256*1, 256*1 }, { 256*1, 256*1, 256*1 } }, [X264_CSP_BGR] = { 1, { 256*3 }, { 256*1 }, }, diff --git a/library/src/main/cpp/libx264/common/common.h b/library/src/main/cpp/libx264/common/common.h index c7850ca..867b207 100644 --- a/library/src/main/cpp/libx264/common/common.h +++ b/library/src/main/cpp/libx264/common/common.h @@ -635,11 +635,11 @@ struct x264_t /* Current MB DCT coeffs */ struct { - ALIGNED_N( dctcoef luma16x16_dc[3][16] ); + ALIGNED_64( dctcoef luma16x16_dc[3][16] ); ALIGNED_16( dctcoef chroma_dc[2][8] ); // FIXME share memory? - ALIGNED_N( dctcoef luma8x8[12][64] ); - ALIGNED_N( dctcoef luma4x4[16*3][16] ); + ALIGNED_64( dctcoef luma8x8[12][64] ); + ALIGNED_64( dctcoef luma4x4[16*3][16] ); } dct; /* MB table and cache for current frame/mb */ @@ -729,7 +729,7 @@ struct x264_t int8_t *type; /* mb type */ uint8_t *partition; /* mb partition */ int8_t *qp; /* mb qp */ - int16_t *cbp; /* mb cbp: 0x0?: luma, 0x?0: chroma, 0x100: luma dc, 0x0200 and 0x0400: chroma dc (all set for PCM)*/ + int16_t *cbp; /* mb cbp: 0x0?: luma, 0x?0: chroma, 0x100: luma dc, 0x200 and 0x400: chroma dc, 0x1000 PCM (all set for PCM) */ int8_t (*intra4x4_pred_mode)[8]; /* intra4x4 pred mode. for non I4x4 set to I_PRED_4x4_DC(2) */ /* actually has only 7 entries; set to 8 for write-combining optimizations */ uint8_t (*non_zero_count)[16*3]; /* nzc. for I_PCM set to 16 */ @@ -740,8 +740,7 @@ struct x264_t int16_t (*mvr[2][X264_REF_MAX*2])[2];/* 16x16 mv for each possible ref */ int8_t *skipbp; /* block pattern for SKIP or DIRECT (sub)mbs. B-frames + cabac only */ int8_t *mb_transform_size; /* transform_size_8x8_flag of each mb */ - uint16_t *slice_table; /* sh->first_mb of the slice that the indexed mb is part of - * NOTE: this will fail on resolutions above 2^16 MBs... */ + uint32_t *slice_table; /* sh->first_mb of the slice that the indexed mb is part of */ uint8_t *field; /* buffer for weighted versions of the reference frames */ @@ -778,26 +777,27 @@ struct x264_t /* space for p_fenc and p_fdec */ #define FENC_STRIDE 16 #define FDEC_STRIDE 32 - ALIGNED_N( pixel fenc_buf[48*FENC_STRIDE] ); - ALIGNED_N( pixel fdec_buf[52*FDEC_STRIDE] ); + ALIGNED_64( pixel fenc_buf[48*FENC_STRIDE] ); + ALIGNED_64( pixel fdec_buf[54*FDEC_STRIDE] ); /* i4x4 and i8x8 backup data, for skipping the encode stage when possible */ ALIGNED_16( pixel i4x4_fdec_buf[16*16] ); ALIGNED_16( pixel i8x8_fdec_buf[16*16] ); - ALIGNED_16( dctcoef i8x8_dct_buf[3][64] ); - ALIGNED_16( dctcoef i4x4_dct_buf[15][16] ); + ALIGNED_64( dctcoef i8x8_dct_buf[3][64] ); + ALIGNED_64( dctcoef i4x4_dct_buf[15][16] ); uint32_t i4x4_nnz_buf[4]; uint32_t i8x8_nnz_buf[4]; - int i4x4_cbp; - int i8x8_cbp; /* Psy trellis DCT data */ ALIGNED_16( dctcoef fenc_dct8[4][64] ); ALIGNED_16( dctcoef fenc_dct4[16][16] ); /* Psy RD SATD/SA8D scores cache */ - ALIGNED_N( uint64_t fenc_hadamard_cache[9] ); - ALIGNED_N( uint32_t fenc_satd_cache[32] ); + ALIGNED_64( uint32_t fenc_satd_cache[32] ); + ALIGNED_16( uint64_t fenc_hadamard_cache[9] ); + + int i4x4_cbp; + int i8x8_cbp; /* pointer over mb of the frame to be compressed */ pixel *p_fenc[3]; /* y,u,v */ @@ -822,10 +822,10 @@ struct x264_t struct { /* real intra4x4_pred_mode if I_4X4 or I_8X8, I_PRED_4x4_DC if mb available, -1 if not */ - ALIGNED_8( int8_t intra4x4_pred_mode[X264_SCAN8_LUMA_SIZE] ); + ALIGNED_16( int8_t intra4x4_pred_mode[X264_SCAN8_LUMA_SIZE] ); - /* i_non_zero_count if available else 0x80 */ - ALIGNED_16( uint8_t non_zero_count[X264_SCAN8_SIZE] ); + /* i_non_zero_count if available else 0x80. intentionally misaligned by 8 for asm */ + ALIGNED_8( uint8_t non_zero_count[X264_SCAN8_SIZE] ); /* -1 if unused, -2 if unavailable */ ALIGNED_4( int8_t ref[2][X264_SCAN8_LUMA_SIZE] ); @@ -930,8 +930,8 @@ struct x264_t uint32_t (*nr_residual_sum)[64]; uint32_t *nr_count; - ALIGNED_N( udctcoef nr_offset_denoise[4][64] ); - ALIGNED_N( uint32_t nr_residual_sum_buf[2][4][64] ); + ALIGNED_32( udctcoef nr_offset_denoise[4][64] ); + ALIGNED_32( uint32_t nr_residual_sum_buf[2][4][64] ); uint32_t nr_count_buf[2][4]; uint8_t luma2chroma_pixel[7]; /* Subsampled pixel size */ diff --git a/library/src/main/cpp/libx264/common/cpu.c b/library/src/main/cpp/libx264/common/cpu.c index 636a40c..8638186 100644 --- a/library/src/main/cpp/libx264/common/cpu.c +++ b/library/src/main/cpp/libx264/common/cpu.c @@ -47,8 +47,7 @@ const x264_cpu_name_t x264_cpu_names[] = { #if HAVE_MMX // {"MMX", X264_CPU_MMX}, // we don't support asm on mmx1 cpus anymore -// {"CMOV", X264_CPU_CMOV}, // we require this unconditionally, so don't print it -#define MMX2 X264_CPU_MMX|X264_CPU_MMX2|X264_CPU_CMOV +#define MMX2 X264_CPU_MMX|X264_CPU_MMX2 {"MMX2", MMX2}, {"MMXEXT", MMX2}, {"SSE", MMX2|X264_CPU_SSE}, @@ -56,6 +55,7 @@ const x264_cpu_name_t x264_cpu_names[] = {"SSE2Slow", SSE2|X264_CPU_SSE2_IS_SLOW}, {"SSE2", SSE2}, {"SSE2Fast", SSE2|X264_CPU_SSE2_IS_FAST}, + {"LZCNT", SSE2|X264_CPU_LZCNT}, {"SSE3", SSE2|X264_CPU_SSE3}, {"SSSE3", SSE2|X264_CPU_SSE3|X264_CPU_SSSE3}, {"SSE4.1", SSE2|X264_CPU_SSE3|X264_CPU_SSSE3|X264_CPU_SSE4}, @@ -66,16 +66,17 @@ const x264_cpu_name_t x264_cpu_names[] = {"XOP", AVX|X264_CPU_XOP}, {"FMA4", AVX|X264_CPU_FMA4}, {"FMA3", AVX|X264_CPU_FMA3}, - {"AVX2", AVX|X264_CPU_FMA3|X264_CPU_AVX2}, + {"BMI1", AVX|X264_CPU_LZCNT|X264_CPU_BMI1}, + {"BMI2", AVX|X264_CPU_LZCNT|X264_CPU_BMI1|X264_CPU_BMI2}, +#define AVX2 AVX|X264_CPU_FMA3|X264_CPU_LZCNT|X264_CPU_BMI1|X264_CPU_BMI2|X264_CPU_AVX2 + {"AVX2", AVX2}, + {"AVX512", AVX2|X264_CPU_AVX512}, +#undef AVX2 #undef AVX #undef SSE2 #undef MMX2 {"Cache32", X264_CPU_CACHELINE_32}, {"Cache64", X264_CPU_CACHELINE_64}, - {"LZCNT", X264_CPU_LZCNT}, - {"BMI1", X264_CPU_BMI1}, - {"BMI2", X264_CPU_BMI1|X264_CPU_BMI2}, - {"SlowCTZ", X264_CPU_SLOW_CTZ}, {"SlowAtom", X264_CPU_SLOW_ATOM}, {"SlowPshufb", X264_CPU_SLOW_PSHUFB}, {"SlowPalignr", X264_CPU_SLOW_PALIGNR}, @@ -118,7 +119,7 @@ static void sigill_handler( int sig ) #if HAVE_MMX int x264_cpu_cpuid_test( void ); void x264_cpu_cpuid( uint32_t op, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx ); -void x264_cpu_xgetbv( uint32_t op, uint32_t *eax, uint32_t *edx ); +uint64_t x264_cpu_xgetbv( int xcr ); uint32_t x264_cpu_detect( void ) { @@ -126,15 +127,14 @@ uint32_t x264_cpu_detect( void ) uint32_t eax, ebx, ecx, edx; uint32_t vendor[4] = {0}; uint32_t max_extended_cap, max_basic_cap; - int cache; + uint64_t xcr0 = 0; #if !ARCH_X86_64 if( !x264_cpu_cpuid_test() ) return 0; #endif - x264_cpu_cpuid( 0, &eax, vendor+0, vendor+2, vendor+1 ); - max_basic_cap = eax; + x264_cpu_cpuid( 0, &max_basic_cap, vendor+0, vendor+2, vendor+1 ); if( max_basic_cap == 0 ) return 0; @@ -145,28 +145,24 @@ uint32_t x264_cpu_detect( void ) return cpu; if( edx&0x02000000 ) cpu |= X264_CPU_MMX2|X264_CPU_SSE; - if( edx&0x00008000 ) - cpu |= X264_CPU_CMOV; - else - return cpu; if( edx&0x04000000 ) cpu |= X264_CPU_SSE2; if( ecx&0x00000001 ) cpu |= X264_CPU_SSE3; if( ecx&0x00000200 ) - cpu |= X264_CPU_SSSE3; + cpu |= X264_CPU_SSSE3|X264_CPU_SSE2_IS_FAST; if( ecx&0x00080000 ) cpu |= X264_CPU_SSE4; if( ecx&0x00100000 ) cpu |= X264_CPU_SSE42; - /* Check OXSAVE and AVX bits */ - if( (ecx&0x18000000) == 0x18000000 ) + + if( ecx&0x08000000 ) /* XGETBV supported and XSAVE enabled by OS */ { - /* Check for OS support */ - x264_cpu_xgetbv( 0, &eax, &edx ); - if( (eax&0x6) == 0x6 ) + xcr0 = x264_cpu_xgetbv( 0 ); + if( (xcr0&0x6) == 0x6 ) /* XMM/YMM state */ { - cpu |= X264_CPU_AVX; + if( ecx&0x10000000 ) + cpu |= X264_CPU_AVX; if( ecx&0x00001000 ) cpu |= X264_CPU_FMA3; } @@ -175,20 +171,25 @@ uint32_t x264_cpu_detect( void ) if( max_basic_cap >= 7 ) { x264_cpu_cpuid( 7, &eax, &ebx, &ecx, &edx ); - /* AVX2 requires OS support, but BMI1/2 don't. */ - if( (cpu&X264_CPU_AVX) && (ebx&0x00000020) ) - cpu |= X264_CPU_AVX2; + if( ebx&0x00000008 ) - { cpu |= X264_CPU_BMI1; - if( ebx&0x00000100 ) - cpu |= X264_CPU_BMI2; + if( ebx&0x00000100 ) + cpu |= X264_CPU_BMI2; + + if( (xcr0&0x6) == 0x6 ) /* XMM/YMM state */ + { + if( ebx&0x00000020 ) + cpu |= X264_CPU_AVX2; + + if( (xcr0&0xE0) == 0xE0 ) /* OPMASK/ZMM state */ + { + if( (ebx&0xD0030000) == 0xD0030000 ) + cpu |= X264_CPU_AVX512; + } } } - if( cpu & X264_CPU_SSSE3 ) - cpu |= X264_CPU_SSE2_IS_FAST; - x264_cpu_cpuid( 0x80000000, &eax, &ebx, &ecx, &edx ); max_extended_cap = eax; @@ -228,8 +229,6 @@ uint32_t x264_cpu_detect( void ) { if( edx&0x00400000 ) cpu |= X264_CPU_MMX2; - if( !(cpu&X264_CPU_LZCNT) ) - cpu |= X264_CPU_SLOW_CTZ; if( (cpu&X264_CPU_SSE2) && !(cpu&X264_CPU_SSE2_IS_FAST) ) cpu |= X264_CPU_SSE2_IS_SLOW; /* AMD CPUs come in two types: terrible at SSE and great at it */ } @@ -254,7 +253,6 @@ uint32_t x264_cpu_detect( void ) else if( model == 28 ) { cpu |= X264_CPU_SLOW_ATOM; - cpu |= X264_CPU_SLOW_CTZ; cpu |= X264_CPU_SLOW_PSHUFB; } /* Conroe has a slow shuffle unit. Check the model number to make sure not @@ -268,7 +266,7 @@ uint32_t x264_cpu_detect( void ) { /* cacheline size is specified in 3 places, any of which may be missing */ x264_cpu_cpuid( 1, &eax, &ebx, &ecx, &edx ); - cache = (ebx&0xff00)>>5; // cflush size + int cache = (ebx&0xff00)>>5; // cflush size if( !cache && max_extended_cap >= 0x80000006 ) { x264_cpu_cpuid( 0x80000006, &eax, &ebx, &ecx, &edx ); diff --git a/library/src/main/cpp/libx264/common/cpu.h b/library/src/main/cpp/libx264/common/cpu.h index eec1be2..845034c 100644 --- a/library/src/main/cpp/libx264/common/cpu.h +++ b/library/src/main/cpp/libx264/common/cpu.h @@ -56,7 +56,7 @@ void x264_cpu_sfence( void ); * alignment between functions (osdep.h handles manual alignment of arrays * if it doesn't). */ -#if (ARCH_X86 || STACK_ALIGNMENT > 16) && HAVE_MMX +#if HAVE_MMX && (STACK_ALIGNMENT > 16 || (ARCH_X86 && STACK_ALIGNMENT > 4)) intptr_t x264_stack_align( void (*func)(), ... ); #define x264_stack_align(func,...) x264_stack_align((void (*)())func, __VA_ARGS__) #else @@ -65,7 +65,7 @@ intptr_t x264_stack_align( void (*func)(), ... ); typedef struct { - const char name[16]; + const char *name; uint32_t flags; } x264_cpu_name_t; extern const x264_cpu_name_t x264_cpu_names[]; diff --git a/library/src/main/cpp/libx264/common/dct.c b/library/src/main/cpp/libx264/common/dct.c index a270c4c..70853bf 100644 --- a/library/src/main/cpp/libx264/common/dct.c +++ b/library/src/main/cpp/libx264/common/dct.c @@ -711,6 +711,16 @@ void x264_dct_init( int cpu, x264_dct_function_t *dctf ) dctf->sub16x16_dct8 = x264_sub16x16_dct8_avx2; #endif } + + if( cpu&X264_CPU_AVX512 ) + { + dctf->sub4x4_dct = x264_sub4x4_dct_avx512; + dctf->sub8x8_dct = x264_sub8x8_dct_avx512; + dctf->sub16x16_dct = x264_sub16x16_dct_avx512; + dctf->sub8x8_dct_dc = x264_sub8x8_dct_dc_avx512; + dctf->sub8x16_dct_dc = x264_sub8x16_dct_dc_avx512; + dctf->add8x8_idct = x264_add8x8_idct_avx512; + } #endif //HAVE_MMX #if HAVE_ALTIVEC @@ -986,6 +996,13 @@ void x264_zigzag_init( int cpu, x264_zigzag_function_t *pf_progressive, x264_zig pf_progressive->scan_8x8 = x264_zigzag_scan_8x8_frame_avx; } #endif // ARCH_X86_64 + if( cpu&X264_CPU_AVX512 ) + { + pf_interlaced->scan_4x4 = x264_zigzag_scan_4x4_field_avx512; + pf_progressive->scan_4x4 = x264_zigzag_scan_4x4_frame_avx512; + pf_interlaced->scan_8x8 = x264_zigzag_scan_8x8_field_avx512; + pf_progressive->scan_8x8 = x264_zigzag_scan_8x8_frame_avx512; + } #endif // HAVE_MMX #else #if HAVE_MMX @@ -1026,6 +1043,13 @@ void x264_zigzag_init( int cpu, x264_zigzag_function_t *pf_progressive, x264_zig pf_progressive->scan_8x8 = x264_zigzag_scan_8x8_frame_xop; pf_interlaced->scan_8x8 = x264_zigzag_scan_8x8_field_xop; } + if( cpu&X264_CPU_AVX512 ) + { + pf_interlaced->scan_4x4 = x264_zigzag_scan_4x4_field_avx512; + pf_progressive->scan_4x4 = x264_zigzag_scan_4x4_frame_avx512; + pf_interlaced->scan_8x8 = x264_zigzag_scan_8x8_field_avx512; + pf_progressive->scan_8x8 = x264_zigzag_scan_8x8_frame_avx512; + } #endif // HAVE_MMX #if HAVE_ALTIVEC if( cpu&X264_CPU_ALTIVEC ) @@ -1068,6 +1092,11 @@ void x264_zigzag_init( int cpu, x264_zigzag_function_t *pf_progressive, x264_zig pf_interlaced->interleave_8x8_cavlc = pf_progressive->interleave_8x8_cavlc = x264_zigzag_interleave_8x8_cavlc_avx; } + if( cpu&X264_CPU_AVX512 ) + { + pf_interlaced->interleave_8x8_cavlc = + pf_progressive->interleave_8x8_cavlc = x264_zigzag_interleave_8x8_cavlc_avx512; + } #else if( cpu&X264_CPU_MMX ) { @@ -1091,6 +1120,11 @@ void x264_zigzag_init( int cpu, x264_zigzag_function_t *pf_progressive, x264_zig pf_interlaced->interleave_8x8_cavlc = pf_progressive->interleave_8x8_cavlc = x264_zigzag_interleave_8x8_cavlc_avx2; } + if( cpu&X264_CPU_AVX512 ) + { + pf_interlaced->interleave_8x8_cavlc = + pf_progressive->interleave_8x8_cavlc = x264_zigzag_interleave_8x8_cavlc_avx512; + } #endif // HIGH_BIT_DEPTH #endif #if !HIGH_BIT_DEPTH diff --git a/library/src/main/cpp/libx264/common/dct.h b/library/src/main/cpp/libx264/common/dct.h index fc8434b..d443e22 100644 --- a/library/src/main/cpp/libx264/common/dct.h +++ b/library/src/main/cpp/libx264/common/dct.h @@ -75,7 +75,6 @@ typedef struct } x264_zigzag_function_t; void x264_dct_init( int cpu, x264_dct_function_t *dctf ); -void x264_dct_init_weights( void ); void x264_zigzag_init( int cpu, x264_zigzag_function_t *pf_progressive, x264_zigzag_function_t *pf_interlaced ); #endif diff --git a/library/src/main/cpp/libx264/common/deblock.c b/library/src/main/cpp/libx264/common/deblock.c index 659fb35..0c7f128 100644 --- a/library/src/main/cpp/libx264/common/deblock.c +++ b/library/src/main/cpp/libx264/common/deblock.c @@ -676,21 +676,21 @@ void x264_deblock_h_chroma_intra_avx ( pixel *pix, intptr_t stride, int alpha, i void x264_deblock_h_chroma_422_intra_mmx2( pixel *pix, intptr_t stride, int alpha, int beta ); void x264_deblock_h_chroma_422_intra_sse2( pixel *pix, intptr_t stride, int alpha, int beta ); void x264_deblock_h_chroma_422_intra_avx ( pixel *pix, intptr_t stride, int alpha, int beta ); -void x264_deblock_strength_mmx2 ( uint8_t nnz[X264_SCAN8_SIZE], int8_t ref[2][X264_SCAN8_LUMA_SIZE], - int16_t mv[2][X264_SCAN8_LUMA_SIZE][2], uint8_t bs[2][8][4], - int mvy_limit, int bframe ); -void x264_deblock_strength_sse2 ( uint8_t nnz[X264_SCAN8_SIZE], int8_t ref[2][X264_SCAN8_LUMA_SIZE], - int16_t mv[2][X264_SCAN8_LUMA_SIZE][2], uint8_t bs[2][8][4], - int mvy_limit, int bframe ); -void x264_deblock_strength_ssse3( uint8_t nnz[X264_SCAN8_SIZE], int8_t ref[2][X264_SCAN8_LUMA_SIZE], - int16_t mv[2][X264_SCAN8_LUMA_SIZE][2], uint8_t bs[2][8][4], - int mvy_limit, int bframe ); -void x264_deblock_strength_avx ( uint8_t nnz[X264_SCAN8_SIZE], int8_t ref[2][X264_SCAN8_LUMA_SIZE], - int16_t mv[2][X264_SCAN8_LUMA_SIZE][2], uint8_t bs[2][8][4], - int mvy_limit, int bframe ); -void x264_deblock_strength_avx2 ( uint8_t nnz[X264_SCAN8_SIZE], int8_t ref[2][X264_SCAN8_LUMA_SIZE], - int16_t mv[2][X264_SCAN8_LUMA_SIZE][2], uint8_t bs[2][8][4], - int mvy_limit, int bframe ); +void x264_deblock_strength_sse2 ( uint8_t nnz[X264_SCAN8_SIZE], int8_t ref[2][X264_SCAN8_LUMA_SIZE], + int16_t mv[2][X264_SCAN8_LUMA_SIZE][2], uint8_t bs[2][8][4], + int mvy_limit, int bframe ); +void x264_deblock_strength_ssse3 ( uint8_t nnz[X264_SCAN8_SIZE], int8_t ref[2][X264_SCAN8_LUMA_SIZE], + int16_t mv[2][X264_SCAN8_LUMA_SIZE][2], uint8_t bs[2][8][4], + int mvy_limit, int bframe ); +void x264_deblock_strength_avx ( uint8_t nnz[X264_SCAN8_SIZE], int8_t ref[2][X264_SCAN8_LUMA_SIZE], + int16_t mv[2][X264_SCAN8_LUMA_SIZE][2], uint8_t bs[2][8][4], + int mvy_limit, int bframe ); +void x264_deblock_strength_avx2 ( uint8_t nnz[X264_SCAN8_SIZE], int8_t ref[2][X264_SCAN8_LUMA_SIZE], + int16_t mv[2][X264_SCAN8_LUMA_SIZE][2], uint8_t bs[2][8][4], + int mvy_limit, int bframe ); +void x264_deblock_strength_avx512( uint8_t nnz[X264_SCAN8_SIZE], int8_t ref[2][X264_SCAN8_LUMA_SIZE], + int16_t mv[2][X264_SCAN8_LUMA_SIZE][2], uint8_t bs[2][8][4], + int mvy_limit, int bframe ); void x264_deblock_h_chroma_intra_mbaff_mmx2( pixel *pix, intptr_t stride, int alpha, int beta ); void x264_deblock_h_chroma_intra_mbaff_sse2( pixel *pix, intptr_t stride, int alpha, int beta ); @@ -803,7 +803,6 @@ void x264_deblock_init( int cpu, x264_deblock_function_t *pf, int b_mbaff ) #if !HIGH_BIT_DEPTH pf->deblock_chroma_420_intra_mbaff = x264_deblock_h_chroma_intra_mbaff_mmx2; #endif - pf->deblock_strength = x264_deblock_strength_mmx2; if( cpu&X264_CPU_SSE2 ) { pf->deblock_strength = x264_deblock_strength_sse2; @@ -852,6 +851,10 @@ void x264_deblock_init( int cpu, x264_deblock_function_t *pf, int b_mbaff ) { pf->deblock_strength = x264_deblock_strength_avx2; } + if( cpu&X264_CPU_AVX512 ) + { + pf->deblock_strength = x264_deblock_strength_avx512; + } } #endif diff --git a/library/src/main/cpp/libx264/common/frame.c b/library/src/main/cpp/libx264/common/frame.c index e15c1a3..4d80cbb 100644 --- a/library/src/main/cpp/libx264/common/frame.c +++ b/library/src/main/cpp/libx264/common/frame.c @@ -54,6 +54,8 @@ static int x264_frame_internal_csp( int external_csp ) case X264_CSP_NV16: case X264_CSP_I422: case X264_CSP_YV16: + case X264_CSP_YUYV: + case X264_CSP_UYVY: case X264_CSP_V210: return X264_CSP_NV16; case X264_CSP_I444: @@ -76,7 +78,7 @@ static x264_frame_t *x264_frame_new( x264_t *h, int b_fdec ) int i_padv = PADV << PARAM_INTERLACED; int align = 16; #if ARCH_X86 || ARCH_X86_64 - if( h->param.cpu&X264_CPU_CACHELINE_64 ) + if( h->param.cpu&X264_CPU_CACHELINE_64 || h->param.cpu&X264_CPU_AVX512 ) align = 64; else if( h->param.cpu&X264_CPU_CACHELINE_32 || h->param.cpu&X264_CPU_AVX ) align = 32; @@ -221,11 +223,13 @@ static x264_frame_t *x264_frame_new( x264_t *h, int b_fdec ) PREALLOC( frame->lowres_mvs[j][i], 2*h->mb.i_mb_count*sizeof(int16_t) ); PREALLOC( frame->lowres_mv_costs[j][i], h->mb.i_mb_count*sizeof(int) ); } - PREALLOC( frame->i_propagate_cost, (i_mb_count+7) * sizeof(uint16_t) ); + PREALLOC( frame->i_propagate_cost, i_mb_count * sizeof(uint16_t) ); for( int j = 0; j <= h->param.i_bframe+1; j++ ) for( int i = 0; i <= h->param.i_bframe+1; i++ ) - PREALLOC( frame->lowres_costs[j][i], (i_mb_count+3) * sizeof(uint16_t) ); + PREALLOC( frame->lowres_costs[j][i], i_mb_count * sizeof(uint16_t) ); + /* mbtree asm can overread the input buffers, make sure we don't read outside of allocated memory. */ + prealloc_size += NATIVE_ALIGN; } if( h->param.rc.i_aq_mode ) { @@ -408,7 +412,13 @@ int x264_frame_copy_picture( x264_t *h, x264_frame_t *dst, x264_picture_t *src ) uint8_t *pix[3]; int stride[3]; - if( i_csp == X264_CSP_V210 ) + if( i_csp == X264_CSP_YUYV || i_csp == X264_CSP_UYVY ) + { + int p = i_csp == X264_CSP_UYVY; + h->mc.plane_copy_deinterleave_yuyv( dst->plane[p], dst->i_stride[p], dst->plane[p^1], dst->i_stride[p^1], + (pixel*)src->img.plane[0], src->img.i_stride[0], h->param.i_width, h->param.i_height ); + } + else if( i_csp == X264_CSP_V210 ) { stride[0] = src->img.i_stride[0]; pix[0] = src->img.plane[0]; diff --git a/library/src/main/cpp/libx264/common/macroblock.c b/library/src/main/cpp/libx264/common/macroblock.c index 661e678..6168671 100644 --- a/library/src/main/cpp/libx264/common/macroblock.c +++ b/library/src/main/cpp/libx264/common/macroblock.c @@ -121,8 +121,8 @@ static NOINLINE void x264_mb_mc_01xywh( x264_t *h, int x, int y, int width, int int mvy1 = x264_clip3( h->mb.cache.mv[1][i8][1], h->mb.mv_min[1], h->mb.mv_max[1] ) + 4*4*y; int i_mode = x264_size2pixel[height][width]; intptr_t i_stride0 = 16, i_stride1 = 16; - ALIGNED_ARRAY_N( pixel, tmp0,[16*16] ); - ALIGNED_ARRAY_N( pixel, tmp1,[16*16] ); + ALIGNED_ARRAY_32( pixel, tmp0,[16*16] ); + ALIGNED_ARRAY_32( pixel, tmp1,[16*16] ); pixel *src0, *src1; MC_LUMA_BI( 0 ); @@ -260,7 +260,7 @@ int x264_macroblock_cache_allocate( x264_t *h ) PREALLOC( h->mb.qp, i_mb_count * sizeof(int8_t) ); PREALLOC( h->mb.cbp, i_mb_count * sizeof(int16_t) ); PREALLOC( h->mb.mb_transform_size, i_mb_count * sizeof(int8_t) ); - PREALLOC( h->mb.slice_table, i_mb_count * sizeof(uint16_t) ); + PREALLOC( h->mb.slice_table, i_mb_count * sizeof(uint32_t) ); /* 0 -> 3 top(4), 4 -> 6 : left(3) */ PREALLOC( h->mb.intra4x4_pred_mode, i_mb_count * 8 * sizeof(int8_t) ); @@ -326,7 +326,7 @@ int x264_macroblock_cache_allocate( x264_t *h ) PREALLOC_END( h->mb.base ); - memset( h->mb.slice_table, -1, i_mb_count * sizeof(uint16_t) ); + memset( h->mb.slice_table, -1, i_mb_count * sizeof(uint32_t) ); for( int i = 0; i < 2; i++ ) { @@ -388,7 +388,7 @@ int x264_macroblock_thread_allocate( x264_t *h, int b_lookahead ) ((me_range*2+24) * sizeof(int16_t) + (me_range+4) * (me_range+1) * 4 * sizeof(mvsad_t)); scratch_size = X264_MAX3( buf_hpel, buf_ssim, buf_tesa ); } - int buf_mbtree = h->param.rc.b_mb_tree * ((h->mb.i_mb_width+7)&~7) * sizeof(int16_t); + int buf_mbtree = h->param.rc.b_mb_tree * ((h->mb.i_mb_width+15)&~15) * sizeof(int16_t); scratch_size = X264_MAX( scratch_size, buf_mbtree ); if( scratch_size ) CHECKED_MALLOC( h->scratch_buffer, scratch_size ); @@ -532,16 +532,16 @@ void x264_macroblock_thread_init( x264_t *h ) h->mb.pic.p_fenc[0] = h->mb.pic.fenc_buf; h->mb.pic.p_fdec[0] = h->mb.pic.fdec_buf + 2*FDEC_STRIDE; h->mb.pic.p_fenc[1] = h->mb.pic.fenc_buf + 16*FENC_STRIDE; - h->mb.pic.p_fdec[1] = h->mb.pic.fdec_buf + 19*FDEC_STRIDE; + h->mb.pic.p_fdec[1] = h->mb.pic.fdec_buf + 20*FDEC_STRIDE; if( CHROMA444 ) { h->mb.pic.p_fenc[2] = h->mb.pic.fenc_buf + 32*FENC_STRIDE; - h->mb.pic.p_fdec[2] = h->mb.pic.fdec_buf + 36*FDEC_STRIDE; + h->mb.pic.p_fdec[2] = h->mb.pic.fdec_buf + 38*FDEC_STRIDE; } else { h->mb.pic.p_fenc[2] = h->mb.pic.fenc_buf + 16*FENC_STRIDE + 8; - h->mb.pic.p_fdec[2] = h->mb.pic.fdec_buf + 19*FDEC_STRIDE + 16; + h->mb.pic.p_fdec[2] = h->mb.pic.fdec_buf + 20*FDEC_STRIDE + 16; } } @@ -1738,7 +1738,7 @@ void x264_macroblock_cache_save( x264_t *h ) h->mb.i_last_dqp = 0; h->mb.i_cbp_chroma = CHROMA444 ? 0 : 2; h->mb.i_cbp_luma = 0xf; - h->mb.cbp[i_mb_xy] = (h->mb.i_cbp_chroma << 4) | h->mb.i_cbp_luma | 0x700; + h->mb.cbp[i_mb_xy] = (h->mb.i_cbp_chroma << 4) | h->mb.i_cbp_luma | 0x1700; h->mb.b_transform_8x8 = 0; for( int i = 0; i < 48; i++ ) h->mb.cache.non_zero_count[x264_scan8[i]] = h->param.b_cabac ? 1 : 16; diff --git a/library/src/main/cpp/libx264/common/mc.c b/library/src/main/cpp/libx264/common/mc.c index 543a05c..65af5b9 100644 --- a/library/src/main/cpp/libx264/common/mc.c +++ b/library/src/main/cpp/libx264/common/mc.c @@ -325,15 +325,14 @@ void x264_plane_copy_interleave_c( pixel *dst, intptr_t i_dst, } } -static void x264_plane_copy_deinterleave_c( pixel *dstu, intptr_t i_dstu, - pixel *dstv, intptr_t i_dstv, - pixel *src, intptr_t i_src, int w, int h ) +void x264_plane_copy_deinterleave_c( pixel *dsta, intptr_t i_dsta, pixel *dstb, intptr_t i_dstb, + pixel *src, intptr_t i_src, int w, int h ) { - for( int y=0; yplane_copy_swap = x264_plane_copy_swap_c; pf->plane_copy_interleave = x264_plane_copy_interleave_c; pf->plane_copy_deinterleave = x264_plane_copy_deinterleave_c; + pf->plane_copy_deinterleave_yuyv = x264_plane_copy_deinterleave_c; pf->plane_copy_deinterleave_rgb = x264_plane_copy_deinterleave_rgb_c; pf->plane_copy_deinterleave_v210 = x264_plane_copy_deinterleave_v210_c; diff --git a/library/src/main/cpp/libx264/common/mc.h b/library/src/main/cpp/libx264/common/mc.h index 8f9a772..f3e7079 100644 --- a/library/src/main/cpp/libx264/common/mc.h +++ b/library/src/main/cpp/libx264/common/mc.h @@ -160,6 +160,39 @@ static void x264_plane_copy_swap_##cpu( pixel *dst, intptr_t i_dst, pixel *src, x264_plane_copy_swap_c( dst, i_dst, src, i_src, w, h );\ } +void x264_plane_copy_deinterleave_c( pixel *dsta, intptr_t i_dsta, pixel *dstb, intptr_t i_dstb, + pixel *src, intptr_t i_src, int w, int h ); + +/* We can utilize existing plane_copy_deinterleave() functions for YUYV/UYUV + * input with the additional constraint that we cannot overread src. */ +#define PLANE_COPY_YUYV(align, cpu)\ +static void x264_plane_copy_deinterleave_yuyv_##cpu( pixel *dsta, intptr_t i_dsta, pixel *dstb, intptr_t i_dstb,\ + pixel *src, intptr_t i_src, int w, int h )\ +{\ + int c_w = (align>>1) / sizeof(pixel) - 1;\ + if( !(w&c_w) )\ + x264_plane_copy_deinterleave_##cpu( dsta, i_dsta, dstb, i_dstb, src, i_src, w, h );\ + else if( w > c_w )\ + {\ + if( --h > 0 )\ + {\ + if( i_src > 0 )\ + {\ + x264_plane_copy_deinterleave_##cpu( dsta, i_dsta, dstb, i_dstb, src, i_src, w, h );\ + dsta += i_dsta * h;\ + dstb += i_dstb * h;\ + src += i_src * h;\ + }\ + else\ + x264_plane_copy_deinterleave_##cpu( dsta+i_dsta, i_dsta, dstb+i_dstb, i_dstb,\ + src+i_src, i_src, w, h );\ + }\ + x264_plane_copy_deinterleave_c( dsta, 0, dstb, 0, src, 0, w, 1 );\ + }\ + else\ + x264_plane_copy_deinterleave_c( dsta, i_dsta, dstb, i_dstb, src, i_src, w, h );\ +} + void x264_plane_copy_interleave_c( pixel *dst, intptr_t i_dst, pixel *srcu, intptr_t i_srcu, pixel *srcv, intptr_t i_srcv, int w, int h ); @@ -260,6 +293,8 @@ typedef struct /* may write up to 15 pixels off the end of each plane */ void (*plane_copy_deinterleave)( pixel *dstu, intptr_t i_dstu, pixel *dstv, intptr_t i_dstv, pixel *src, intptr_t i_src, int w, int h ); + void (*plane_copy_deinterleave_yuyv)( pixel *dsta, intptr_t i_dsta, pixel *dstb, intptr_t i_dstb, + pixel *src, intptr_t i_src, int w, int h ); void (*plane_copy_deinterleave_rgb)( pixel *dsta, intptr_t i_dsta, pixel *dstb, intptr_t i_dstb, pixel *dstc, intptr_t i_dstc, pixel *src, intptr_t i_src, int pw, int w, int h ); void (*plane_copy_deinterleave_v210)( pixel *dsty, intptr_t i_dsty, diff --git a/library/src/main/cpp/libx264/common/osdep.h b/library/src/main/cpp/libx264/common/osdep.h index ed3ed59..ca2455d 100644 --- a/library/src/main/cpp/libx264/common/osdep.h +++ b/library/src/main/cpp/libx264/common/osdep.h @@ -108,10 +108,10 @@ int x264_is_pipe( const char *path ); #else #define DECLARE_ALIGNED( var, n ) var __attribute__((aligned(n))) #endif -#define ALIGNED_32( var ) DECLARE_ALIGNED( var, 32 ) -#define ALIGNED_16( var ) DECLARE_ALIGNED( var, 16 ) -#define ALIGNED_8( var ) DECLARE_ALIGNED( var, 8 ) + #define ALIGNED_4( var ) DECLARE_ALIGNED( var, 4 ) +#define ALIGNED_8( var ) DECLARE_ALIGNED( var, 8 ) +#define ALIGNED_16( var ) DECLARE_ALIGNED( var, 16 ) // ARM compiliers don't reliably align stack variables // - EABI requires only 8 byte stack alignment to be maintained @@ -125,39 +125,39 @@ int x264_is_pipe( const char *path ); type (*name) __VA_ARGS__ = (void*)((intptr_t)(name##_u+mask) & ~mask) #if ARCH_ARM && SYS_MACOSX -#define ALIGNED_ARRAY_8( ... ) ALIGNED_ARRAY_EMU( 7, __VA_ARGS__ ) +#define ALIGNED_ARRAY_8( ... ) EXPAND( ALIGNED_ARRAY_EMU( 7, __VA_ARGS__ ) ) #else -#define ALIGNED_ARRAY_8( type, name, sub1, ... )\ - ALIGNED_8( type name sub1 __VA_ARGS__ ) +#define ALIGNED_ARRAY_8( type, name, sub1, ... ) ALIGNED_8( type name sub1 __VA_ARGS__ ) #endif #if ARCH_ARM -#define ALIGNED_ARRAY_16( ... ) ALIGNED_ARRAY_EMU( 15, __VA_ARGS__ ) +#define ALIGNED_ARRAY_16( ... ) EXPAND( ALIGNED_ARRAY_EMU( 15, __VA_ARGS__ ) ) #else -#define ALIGNED_ARRAY_16( type, name, sub1, ... )\ - ALIGNED_16( type name sub1 __VA_ARGS__ ) +#define ALIGNED_ARRAY_16( type, name, sub1, ... ) ALIGNED_16( type name sub1 __VA_ARGS__ ) #endif #define EXPAND(x) x +#if ARCH_X86 || ARCH_X86_64 +#define NATIVE_ALIGN 64 +#define ALIGNED_32( var ) DECLARE_ALIGNED( var, 32 ) +#define ALIGNED_64( var ) DECLARE_ALIGNED( var, 64 ) #if STACK_ALIGNMENT >= 32 -#define ALIGNED_ARRAY_32( type, name, sub1, ... )\ - ALIGNED_32( type name sub1 __VA_ARGS__ ) +#define ALIGNED_ARRAY_32( type, name, sub1, ... ) ALIGNED_32( type name sub1 __VA_ARGS__ ) #else #define ALIGNED_ARRAY_32( ... ) EXPAND( ALIGNED_ARRAY_EMU( 31, __VA_ARGS__ ) ) #endif - +#if STACK_ALIGNMENT >= 64 +#define ALIGNED_ARRAY_64( type, name, sub1, ... ) ALIGNED_64( type name sub1 __VA_ARGS__ ) +#else #define ALIGNED_ARRAY_64( ... ) EXPAND( ALIGNED_ARRAY_EMU( 63, __VA_ARGS__ ) ) - -/* For AVX2 */ -#if ARCH_X86 || ARCH_X86_64 -#define NATIVE_ALIGN 32 -#define ALIGNED_N ALIGNED_32 -#define ALIGNED_ARRAY_N ALIGNED_ARRAY_32 +#endif #else #define NATIVE_ALIGN 16 -#define ALIGNED_N ALIGNED_16 -#define ALIGNED_ARRAY_N ALIGNED_ARRAY_16 +#define ALIGNED_32 ALIGNED_16 +#define ALIGNED_64 ALIGNED_16 +#define ALIGNED_ARRAY_32 ALIGNED_ARRAY_16 +#define ALIGNED_ARRAY_64 ALIGNED_ARRAY_16 #endif #if defined(__GNUC__) && (__GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ > 0) diff --git a/library/src/main/cpp/libx264/common/pixel.c b/library/src/main/cpp/libx264/common/pixel.c index c5edc9e..00c1412 100644 --- a/library/src/main/cpp/libx264/common/pixel.c +++ b/library/src/main/cpp/libx264/common/pixel.c @@ -201,28 +201,32 @@ PIXEL_VAR_C( x264_pixel_var_8x8, 8, 8 ) /**************************************************************************** * pixel_var2_wxh ****************************************************************************/ -#define PIXEL_VAR2_C( name, w, h, shift ) \ -static int name( pixel *pix1, intptr_t i_stride1, pixel *pix2, intptr_t i_stride2, int *ssd ) \ +#define PIXEL_VAR2_C( name, h, shift ) \ +static int name( pixel *fenc, pixel *fdec, int ssd[2] ) \ { \ - int var = 0, sum = 0, sqr = 0; \ + int sum_u = 0, sum_v = 0, sqr_u = 0, sqr_v = 0; \ for( int y = 0; y < h; y++ ) \ { \ - for( int x = 0; x < w; x++ ) \ + for( int x = 0; x < 8; x++ ) \ { \ - int diff = pix1[x] - pix2[x]; \ - sum += diff; \ - sqr += diff * diff; \ + int diff_u = fenc[x] - fdec[x]; \ + int diff_v = fenc[x+FENC_STRIDE/2] - fdec[x+FDEC_STRIDE/2]; \ + sum_u += diff_u; \ + sum_v += diff_v; \ + sqr_u += diff_u * diff_u; \ + sqr_v += diff_v * diff_v; \ } \ - pix1 += i_stride1; \ - pix2 += i_stride2; \ + fenc += FENC_STRIDE; \ + fdec += FDEC_STRIDE; \ } \ - var = sqr - ((int64_t)sum * sum >> shift); \ - *ssd = sqr; \ - return var; \ + ssd[0] = sqr_u; \ + ssd[1] = sqr_v; \ + return sqr_u - ((int64_t)sum_u * sum_u >> shift) + \ + sqr_v - ((int64_t)sum_v * sum_v >> shift); \ } -PIXEL_VAR2_C( x264_pixel_var2_8x16, 8, 16, 7 ) -PIXEL_VAR2_C( x264_pixel_var2_8x8, 8, 8, 6 ) +PIXEL_VAR2_C( x264_pixel_var2_8x16, 16, 7 ) +PIXEL_VAR2_C( x264_pixel_var2_8x8, 8, 6 ) #if BIT_DEPTH > 8 typedef uint32_t sum_t; @@ -885,13 +889,6 @@ void x264_pixel_init( int cpu, x264_pixel_function_t *pixf ) INIT8( ssd, _mmx2 ); INIT_ADS( _mmx2 ); - pixf->var[PIXEL_16x16] = x264_pixel_var_16x16_mmx2; - pixf->var[PIXEL_8x8] = x264_pixel_var_8x8_mmx2; -#if ARCH_X86 - pixf->var2[PIXEL_8x8] = x264_pixel_var2_8x8_mmx2; - pixf->var2[PIXEL_8x16] = x264_pixel_var2_8x16_mmx2; -#endif - pixf->intra_sad_x3_4x4 = x264_intra_sad_x3_4x4_mmx2; pixf->intra_satd_x3_4x4 = x264_intra_satd_x3_4x4_mmx2; pixf->intra_sad_x3_8x8 = x264_intra_sad_x3_8x8_mmx2; @@ -962,7 +959,9 @@ void x264_pixel_init( int cpu, x264_pixel_function_t *pixf ) INIT7( sad, _ssse3 ); INIT7( sad_x3, _ssse3 ); INIT7( sad_x4, _ssse3 ); +#if ARCH_X86 || !defined( __MACH__ ) INIT_ADS( _ssse3 ); +#endif INIT6( satd, _ssse3 ); pixf->satd[PIXEL_4x16] = x264_pixel_satd_4x16_ssse3; @@ -1003,7 +1002,9 @@ void x264_pixel_init( int cpu, x264_pixel_function_t *pixf ) if( cpu&X264_CPU_AVX ) { INIT5_NAME( sad_aligned, sad, _ssse3 ); /* AVX-capable CPUs doesn't benefit from an aligned version */ +#if ARCH_X86 || !defined( __MACH__ ) INIT_ADS( _avx ); +#endif INIT6( satd, _avx ); pixf->satd[PIXEL_4x16] = x264_pixel_satd_4x16_avx; if( !(cpu&X264_CPU_STACK_MOD4) ) @@ -1028,8 +1029,6 @@ void x264_pixel_init( int cpu, x264_pixel_function_t *pixf ) INIT5( sad_x3, _xop ); INIT5( sad_x4, _xop ); pixf->ssd_nv12_core = x264_pixel_ssd_nv12_core_xop; - pixf->var[PIXEL_16x16] = x264_pixel_var_16x16_xop; - pixf->var[PIXEL_8x8] = x264_pixel_var_8x8_xop; pixf->vsad = x264_pixel_vsad_xop; pixf->asd8 = x264_pixel_asd8_xop; #if ARCH_X86_64 @@ -1044,10 +1043,19 @@ void x264_pixel_init( int cpu, x264_pixel_function_t *pixf ) INIT2( sad_x3, _avx2 ); INIT2( sad_x4, _avx2 ); pixf->var[PIXEL_16x16] = x264_pixel_var_16x16_avx2; + pixf->var2[PIXEL_8x8] = x264_pixel_var2_8x8_avx2; + pixf->var2[PIXEL_8x16] = x264_pixel_var2_8x16_avx2; pixf->vsad = x264_pixel_vsad_avx2; pixf->ssd_nv12_core = x264_pixel_ssd_nv12_core_avx2; pixf->intra_sad_x3_8x8 = x264_intra_sad_x3_8x8_avx2; } + if( cpu&X264_CPU_AVX512 ) + { + pixf->var[PIXEL_8x16] = x264_pixel_var_8x16_avx512; + pixf->var[PIXEL_16x16] = x264_pixel_var_16x16_avx512; + pixf->var2[PIXEL_8x8] = x264_pixel_var2_8x8_avx512; + pixf->var2[PIXEL_8x16] = x264_pixel_var2_8x16_avx512; + } #endif // HAVE_MMX #else // !HIGH_BIT_DEPTH #if HAVE_MMX @@ -1067,16 +1075,11 @@ void x264_pixel_init( int cpu, x264_pixel_function_t *pixf ) INIT7( satd_x4, _mmx2 ); INIT4( hadamard_ac, _mmx2 ); INIT_ADS( _mmx2 ); - pixf->var[PIXEL_16x16] = x264_pixel_var_16x16_mmx2; - pixf->var[PIXEL_8x16] = x264_pixel_var_8x16_mmx2; - pixf->var[PIXEL_8x8] = x264_pixel_var_8x8_mmx2; #if ARCH_X86 pixf->sa8d[PIXEL_16x16] = x264_pixel_sa8d_16x16_mmx2; pixf->sa8d[PIXEL_8x8] = x264_pixel_sa8d_8x8_mmx2; pixf->intra_sa8d_x3_8x8 = x264_intra_sa8d_x3_8x8_mmx2; pixf->ssim_4x4x2_core = x264_pixel_ssim_4x4x2_core_mmx2; - pixf->var2[PIXEL_8x8] = x264_pixel_var2_8x8_mmx2; - pixf->var2[PIXEL_8x16] = x264_pixel_var2_8x16_mmx2; pixf->vsad = x264_pixel_vsad_mmx2; if( cpu&X264_CPU_CACHELINE_32 ) @@ -1197,7 +1200,9 @@ void x264_pixel_init( int cpu, x264_pixel_function_t *pixf ) pixf->intra_sa8d_x9_8x8 = x264_intra_sa8d_x9_8x8_ssse3; #endif } +#if ARCH_X86 || !defined( __MACH__ ) INIT_ADS( _ssse3 ); +#endif if( cpu&X264_CPU_SLOW_ATOM ) { pixf->sa8d[PIXEL_16x16]= x264_pixel_sa8d_16x16_ssse3_atom; @@ -1280,7 +1285,9 @@ void x264_pixel_init( int cpu, x264_pixel_function_t *pixf ) INIT8( satd, _avx ); INIT7( satd_x3, _avx ); INIT7( satd_x4, _avx ); +#if ARCH_X86 || !defined( __MACH__ ) INIT_ADS( _avx ); +#endif INIT4( hadamard_ac, _avx ); if( !(cpu&X264_CPU_STACK_MOD4) ) { @@ -1321,11 +1328,6 @@ void x264_pixel_init( int cpu, x264_pixel_function_t *pixf ) pixf->sa8d[PIXEL_8x8] = x264_pixel_sa8d_8x8_xop; pixf->intra_satd_x3_8x16c = x264_intra_satd_x3_8x16c_xop; pixf->ssd_nv12_core = x264_pixel_ssd_nv12_core_xop; - pixf->var[PIXEL_16x16] = x264_pixel_var_16x16_xop; - pixf->var[PIXEL_8x16] = x264_pixel_var_8x16_xop; - pixf->var[PIXEL_8x8] = x264_pixel_var_8x8_xop; - pixf->var2[PIXEL_8x8] = x264_pixel_var2_8x8_xop; - pixf->var2[PIXEL_8x16] = x264_pixel_var2_8x16_xop; #if ARCH_X86_64 pixf->sa8d_satd[PIXEL_16x16] = x264_pixel_sa8d_satd_16x16_xop; #endif @@ -1338,7 +1340,9 @@ void x264_pixel_init( int cpu, x264_pixel_function_t *pixf ) INIT2( sad_x4, _avx2 ); INIT4( satd, _avx2 ); INIT2( hadamard_ac, _avx2 ); +#if ARCH_X86 || !defined( __MACH__ ) INIT_ADS( _avx2 ); +#endif pixf->sa8d[PIXEL_8x8] = x264_pixel_sa8d_8x8_avx2; pixf->var[PIXEL_16x16] = x264_pixel_var_16x16_avx2; pixf->var2[PIXEL_8x16] = x264_pixel_var2_8x16_avx2; @@ -1351,6 +1355,21 @@ void x264_pixel_init( int cpu, x264_pixel_function_t *pixf ) pixf->sa8d_satd[PIXEL_16x16] = x264_pixel_sa8d_satd_16x16_avx2; #endif } + + if( cpu&X264_CPU_AVX512 ) + { + INIT8( sad, _avx512 ); + INIT8_NAME( sad_aligned, sad, _avx512 ); + INIT7( sad_x3, _avx512 ); + INIT7( sad_x4, _avx512 ); + INIT8( satd, _avx512 ); + pixf->sa8d[PIXEL_8x8] = x264_pixel_sa8d_8x8_avx512; + pixf->var[PIXEL_8x8] = x264_pixel_var_8x8_avx512; + pixf->var[PIXEL_8x16] = x264_pixel_var_8x16_avx512; + pixf->var[PIXEL_16x16] = x264_pixel_var_16x16_avx512; + pixf->var2[PIXEL_8x8] = x264_pixel_var2_8x8_avx512; + pixf->var2[PIXEL_8x16] = x264_pixel_var2_8x16_avx512; + } #endif //HAVE_MMX #if HAVE_ARMV6 @@ -1480,8 +1499,8 @@ void x264_pixel_init( int cpu, x264_pixel_function_t *pixf ) pixf->var[PIXEL_16x16] = x264_pixel_var_16x16_msa; pixf->var[PIXEL_8x16] = x264_pixel_var_8x16_msa; pixf->var[PIXEL_8x8] = x264_pixel_var_8x8_msa; - pixf->var2[PIXEL_8x16] = x264_pixel_var2_8x16_msa; - pixf->var2[PIXEL_8x8] = x264_pixel_var2_8x8_msa; + //pixf->var2[PIXEL_8x16] = x264_pixel_var2_8x16_msa; + //pixf->var2[PIXEL_8x8] = x264_pixel_var2_8x8_msa; pixf->sa8d[PIXEL_16x16] = x264_pixel_sa8d_16x16; pixf->sa8d[PIXEL_8x8] = x264_pixel_sa8d_8x8; } diff --git a/library/src/main/cpp/libx264/common/pixel.h b/library/src/main/cpp/libx264/common/pixel.h index f634312..d4dbfaf 100644 --- a/library/src/main/cpp/libx264/common/pixel.h +++ b/library/src/main/cpp/libx264/common/pixel.h @@ -93,8 +93,7 @@ typedef struct uint64_t (*sa8d_satd[1])( pixel *pix1, intptr_t stride1, pixel *pix2, intptr_t stride2 ); uint64_t (*var[4])( pixel *pix, intptr_t stride ); - int (*var2[4])( pixel *pix1, intptr_t stride1, - pixel *pix2, intptr_t stride2, int *ssd ); + int (*var2[4])( pixel *fenc, pixel *fdec, int ssd[2] ); uint64_t (*hadamard_ac[4])( pixel *pix, intptr_t stride ); void (*ssd_nv12_core)( pixel *pixuv1, intptr_t stride1, diff --git a/library/src/main/cpp/libx264/common/ppc/dct.c b/library/src/main/cpp/libx264/common/ppc/dct.c index 768f390..2858bd0 100644 --- a/library/src/main/cpp/libx264/common/ppc/dct.c +++ b/library/src/main/cpp/libx264/common/ppc/dct.c @@ -293,12 +293,8 @@ void x264_sub16x16_dct8_altivec( int16_t dct[4][64], uint8_t *pix1, uint8_t *pix vec_vsx_st( dcvsum8, 0, dest ); \ } -static void idct8_dc_altivec( uint8_t *dst, int16_t dc1, int16_t dc2 ) +static void idct8_dc_altivec( uint8_t *dst, vec_s16_t dcv ) { - dc1 = (dc1 + 32) >> 6; - dc2 = (dc2 + 32) >> 6; - vec_s16_t dcv = { dc1, dc1, dc1, dc1, dc2, dc2, dc2, dc2 }; - LOAD_ZERO; ALTIVEC_STORE8_DC_SUM_CLIP( &dst[0*FDEC_STRIDE], dcv ); ALTIVEC_STORE8_DC_SUM_CLIP( &dst[1*FDEC_STRIDE], dcv ); @@ -308,8 +304,18 @@ static void idct8_dc_altivec( uint8_t *dst, int16_t dc1, int16_t dc2 ) void x264_add8x8_idct_dc_altivec( uint8_t *p_dst, int16_t dct[4] ) { - idct8_dc_altivec( &p_dst[0], dct[0], dct[1] ); - idct8_dc_altivec( &p_dst[4*FDEC_STRIDE+0], dct[2], dct[3] ); + vec_s16_t dcv; + vec_s16_t v32 = vec_sl( vec_splat_s16( 8 ), vec_splat_u16( 2 ) ); + vec_u16_t v6 = vec_splat_u16( 6 ); + vec_s16_t dctv = vec_vsx_ld( 0, dct ); + + dctv = vec_sra( vec_add( dctv, v32 ), v6 ); + dcv = (vec_s16_t)vec_mergeh( (vec_s32_t)vec_splat( dctv, 0 ), (vec_s32_t)vec_splat( dctv, 1 ) ); + dcv = (vec_s16_t)vec_mergeh( (vec_s32_t)dcv, (vec_s32_t)dcv ); + idct8_dc_altivec( &p_dst[0], dcv ); + dcv = (vec_s16_t)vec_mergeh( (vec_s32_t)vec_splat( dctv, 2 ), (vec_s32_t)vec_splat( dctv, 3 ) ); + dcv = (vec_s16_t)vec_mergeh( (vec_s32_t)dcv, (vec_s32_t)dcv ); + idct8_dc_altivec( &p_dst[4*FDEC_STRIDE+0], dcv ); } #define IDCT_1D_ALTIVEC(s0, s1, s2, s3, d0, d1, d2, d3) \ diff --git a/library/src/main/cpp/libx264/common/ppc/mc.c b/library/src/main/cpp/libx264/common/ppc/mc.c index 7fec750..6b24873 100644 --- a/library/src/main/cpp/libx264/common/ppc/mc.c +++ b/library/src/main/cpp/libx264/common/ppc/mc.c @@ -32,19 +32,6 @@ typedef void (*pf_mc_t)( uint8_t *src, intptr_t i_src, uint8_t *dst, intptr_t i_dst, int i_height ); -static inline int x264_tapfilter( uint8_t *pix, int i_pix_next ) -{ - return pix[-2*i_pix_next] - 5*pix[-1*i_pix_next] + 20*(pix[0] + - pix[1*i_pix_next]) - 5*pix[ 2*i_pix_next] + - pix[ 3*i_pix_next]; -} - -static inline int x264_tapfilter1( uint8_t *pix ) -{ - return pix[-2] - 5*pix[-1] + 20*(pix[0] + pix[1]) - 5*pix[ 2] + - pix[ 3]; -} - static inline void x264_pixel_avg2_w4_altivec( uint8_t *dst, intptr_t i_dst, uint8_t *src1, intptr_t i_src1, uint8_t *src2, int i_height ) diff --git a/library/src/main/cpp/libx264/common/quant.c b/library/src/main/cpp/libx264/common/quant.c index 7eef140..ae96222 100644 --- a/library/src/main/cpp/libx264/common/quant.c +++ b/library/src/main/cpp/libx264/common/quant.c @@ -460,9 +460,6 @@ void x264_quant_init( x264_t *h, int cpu, x264_quant_function_t *pf ) { #if ARCH_X86 pf->denoise_dct = x264_denoise_dct_mmx; - pf->decimate_score15 = x264_decimate_score15_mmx2; - pf->decimate_score16 = x264_decimate_score16_mmx2; - pf->decimate_score64 = x264_decimate_score64_mmx2; pf->coeff_last8 = x264_coeff_last8_mmx2; pf->coeff_last[ DCT_LUMA_AC] = x264_coeff_last15_mmx2; pf->coeff_last[ DCT_LUMA_4x4] = x264_coeff_last16_mmx2; @@ -473,8 +470,6 @@ void x264_quant_init( x264_t *h, int cpu, x264_quant_function_t *pf ) #endif pf->coeff_last4 = x264_coeff_last4_mmx2; pf->coeff_level_run4 = x264_coeff_level_run4_mmx2; - if( cpu&X264_CPU_LZCNT ) - pf->coeff_level_run4 = x264_coeff_level_run4_mmx2_lzcnt; } if( cpu&X264_CPU_SSE2 ) { @@ -499,17 +494,18 @@ void x264_quant_init( x264_t *h, int cpu, x264_quant_function_t *pf ) pf->coeff_level_run8 = x264_coeff_level_run8_sse2; pf->coeff_level_run[ DCT_LUMA_AC] = x264_coeff_level_run15_sse2; pf->coeff_level_run[DCT_LUMA_4x4] = x264_coeff_level_run16_sse2; - if( cpu&X264_CPU_LZCNT ) - { - pf->coeff_last4 = x264_coeff_last4_mmx2_lzcnt; - pf->coeff_last8 = x264_coeff_last8_sse2_lzcnt; - pf->coeff_last[ DCT_LUMA_AC] = x264_coeff_last15_sse2_lzcnt; - pf->coeff_last[DCT_LUMA_4x4] = x264_coeff_last16_sse2_lzcnt; - pf->coeff_last[DCT_LUMA_8x8] = x264_coeff_last64_sse2_lzcnt; - pf->coeff_level_run8 = x264_coeff_level_run8_sse2_lzcnt; - pf->coeff_level_run[ DCT_LUMA_AC] = x264_coeff_level_run15_sse2_lzcnt; - pf->coeff_level_run[DCT_LUMA_4x4] = x264_coeff_level_run16_sse2_lzcnt; - } + } + if( cpu&X264_CPU_LZCNT ) + { + pf->coeff_last4 = x264_coeff_last4_lzcnt; + pf->coeff_last8 = x264_coeff_last8_lzcnt; + pf->coeff_last[ DCT_LUMA_AC] = x264_coeff_last15_lzcnt; + pf->coeff_last[DCT_LUMA_4x4] = x264_coeff_last16_lzcnt; + pf->coeff_last[DCT_LUMA_8x8] = x264_coeff_last64_lzcnt; + pf->coeff_level_run4 = x264_coeff_level_run4_lzcnt; + pf->coeff_level_run8 = x264_coeff_level_run8_lzcnt; + pf->coeff_level_run[ DCT_LUMA_AC] = x264_coeff_level_run15_lzcnt; + pf->coeff_level_run[DCT_LUMA_4x4] = x264_coeff_level_run16_lzcnt; } if( cpu&X264_CPU_SSSE3 ) { @@ -557,8 +553,20 @@ void x264_quant_init( x264_t *h, int cpu, x264_quant_function_t *pf ) pf->dequant_8x8 = x264_dequant_8x8_avx2; pf->dequant_4x4_dc = x264_dequant_4x4dc_avx2; pf->denoise_dct = x264_denoise_dct_avx2; - if( cpu&X264_CPU_LZCNT ) - pf->coeff_last[DCT_LUMA_8x8] = x264_coeff_last64_avx2_lzcnt; + pf->coeff_last[DCT_LUMA_8x8] = x264_coeff_last64_avx2; + } + if( cpu&X264_CPU_AVX512 ) + { + pf->dequant_4x4 = x264_dequant_4x4_avx512; + pf->dequant_8x8 = x264_dequant_8x8_avx512; + pf->decimate_score15 = x264_decimate_score15_avx512; + pf->decimate_score16 = x264_decimate_score16_avx512; + pf->decimate_score64 = x264_decimate_score64_avx512; + pf->coeff_last4 = x264_coeff_last4_avx512; + pf->coeff_last8 = x264_coeff_last8_avx512; + pf->coeff_last[ DCT_LUMA_AC] = x264_coeff_last15_avx512; + pf->coeff_last[DCT_LUMA_4x4] = x264_coeff_last16_avx512; + pf->coeff_last[DCT_LUMA_8x8] = x264_coeff_last64_avx512; } #endif // HAVE_MMX #else // !HIGH_BIT_DEPTH @@ -586,9 +594,6 @@ void x264_quant_init( x264_t *h, int cpu, x264_quant_function_t *pf ) pf->quant_4x4 = x264_quant_4x4_mmx2; pf->quant_8x8 = x264_quant_8x8_mmx2; pf->quant_4x4_dc = x264_quant_4x4_dc_mmx2; - pf->decimate_score15 = x264_decimate_score15_mmx2; - pf->decimate_score16 = x264_decimate_score16_mmx2; - pf->decimate_score64 = x264_decimate_score64_mmx2; pf->coeff_last[ DCT_LUMA_AC] = x264_coeff_last15_mmx2; pf->coeff_last[ DCT_LUMA_4x4] = x264_coeff_last16_mmx2; pf->coeff_last[ DCT_LUMA_8x8] = x264_coeff_last64_mmx2; @@ -599,13 +604,6 @@ void x264_quant_init( x264_t *h, int cpu, x264_quant_function_t *pf ) pf->coeff_last8 = x264_coeff_last8_mmx2; pf->coeff_level_run4 = x264_coeff_level_run4_mmx2; pf->coeff_level_run8 = x264_coeff_level_run8_mmx2; - if( cpu&X264_CPU_LZCNT ) - { - pf->coeff_last4 = x264_coeff_last4_mmx2_lzcnt; - pf->coeff_last8 = x264_coeff_last8_mmx2_lzcnt; - pf->coeff_level_run4 = x264_coeff_level_run4_mmx2_lzcnt; - pf->coeff_level_run8 = x264_coeff_level_run8_mmx2_lzcnt; - } } if( cpu&X264_CPU_SSE2 ) @@ -634,14 +632,19 @@ void x264_quant_init( x264_t *h, int cpu, x264_quant_function_t *pf ) pf->coeff_last[DCT_LUMA_8x8] = x264_coeff_last64_sse2; pf->coeff_level_run[ DCT_LUMA_AC] = x264_coeff_level_run15_sse2; pf->coeff_level_run[DCT_LUMA_4x4] = x264_coeff_level_run16_sse2; - if( cpu&X264_CPU_LZCNT ) - { - pf->coeff_last[ DCT_LUMA_AC] = x264_coeff_last15_sse2_lzcnt; - pf->coeff_last[DCT_LUMA_4x4] = x264_coeff_last16_sse2_lzcnt; - pf->coeff_last[DCT_LUMA_8x8] = x264_coeff_last64_sse2_lzcnt; - pf->coeff_level_run[ DCT_LUMA_AC] = x264_coeff_level_run15_sse2_lzcnt; - pf->coeff_level_run[DCT_LUMA_4x4] = x264_coeff_level_run16_sse2_lzcnt; - } + } + + if( cpu&X264_CPU_LZCNT ) + { + pf->coeff_last4 = x264_coeff_last4_lzcnt; + pf->coeff_last8 = x264_coeff_last8_lzcnt; + pf->coeff_last[ DCT_LUMA_AC] = x264_coeff_last15_lzcnt; + pf->coeff_last[DCT_LUMA_4x4] = x264_coeff_last16_lzcnt; + pf->coeff_last[DCT_LUMA_8x8] = x264_coeff_last64_lzcnt; + pf->coeff_level_run4 = x264_coeff_level_run4_lzcnt; + pf->coeff_level_run8 = x264_coeff_level_run8_lzcnt; + pf->coeff_level_run[ DCT_LUMA_AC] = x264_coeff_level_run15_lzcnt; + pf->coeff_level_run[DCT_LUMA_4x4] = x264_coeff_level_run16_lzcnt; } if( cpu&X264_CPU_SSSE3 ) @@ -657,17 +660,19 @@ void x264_quant_init( x264_t *h, int cpu, x264_quant_function_t *pf ) pf->decimate_score16 = x264_decimate_score16_ssse3; pf->decimate_score64 = x264_decimate_score64_ssse3; INIT_TRELLIS( ssse3 ); +#if ARCH_X86 || !defined( __MACH__ ) pf->coeff_level_run4 = x264_coeff_level_run4_ssse3; pf->coeff_level_run8 = x264_coeff_level_run8_ssse3; pf->coeff_level_run[ DCT_LUMA_AC] = x264_coeff_level_run15_ssse3; pf->coeff_level_run[DCT_LUMA_4x4] = x264_coeff_level_run16_ssse3; if( cpu&X264_CPU_LZCNT ) { - pf->coeff_level_run4 = x264_coeff_level_run4_ssse3; - pf->coeff_level_run8 = x264_coeff_level_run8_ssse3; + pf->coeff_level_run4 = x264_coeff_level_run4_ssse3_lzcnt; + pf->coeff_level_run8 = x264_coeff_level_run8_ssse3_lzcnt; pf->coeff_level_run[ DCT_LUMA_AC] = x264_coeff_level_run15_ssse3_lzcnt; pf->coeff_level_run[DCT_LUMA_4x4] = x264_coeff_level_run16_ssse3_lzcnt; } +#endif } if( cpu&X264_CPU_SSE4 ) @@ -717,12 +722,28 @@ void x264_quant_init( x264_t *h, int cpu, x264_quant_function_t *pf ) } pf->decimate_score64 = x264_decimate_score64_avx2; pf->denoise_dct = x264_denoise_dct_avx2; - if( cpu&X264_CPU_LZCNT ) + pf->coeff_last[DCT_LUMA_8x8] = x264_coeff_last64_avx2; +#if ARCH_X86 || !defined( __MACH__ ) + pf->coeff_level_run[ DCT_LUMA_AC] = x264_coeff_level_run15_avx2; + pf->coeff_level_run[DCT_LUMA_4x4] = x264_coeff_level_run16_avx2; +#endif + } + if( cpu&X264_CPU_AVX512 ) + { + if( h->param.i_cqm_preset == X264_CQM_FLAT ) + pf->dequant_8x8 = x264_dequant_8x8_flat16_avx512; + else { - pf->coeff_last[DCT_LUMA_8x8] = x264_coeff_last64_avx2_lzcnt; - pf->coeff_level_run[ DCT_LUMA_AC] = x264_coeff_level_run15_avx2_lzcnt; - pf->coeff_level_run[DCT_LUMA_4x4] = x264_coeff_level_run16_avx2_lzcnt; + pf->dequant_4x4 = x264_dequant_4x4_avx512; + pf->dequant_8x8 = x264_dequant_8x8_avx512; } + pf->decimate_score15 = x264_decimate_score15_avx512; + pf->decimate_score16 = x264_decimate_score16_avx512; + pf->decimate_score64 = x264_decimate_score64_avx512; + pf->coeff_last8 = x264_coeff_last8_avx512; + pf->coeff_last[ DCT_LUMA_AC] = x264_coeff_last15_avx512; + pf->coeff_last[DCT_LUMA_4x4] = x264_coeff_last16_avx512; + pf->coeff_last[DCT_LUMA_8x8] = x264_coeff_last64_avx512; } #endif // HAVE_MMX diff --git a/library/src/main/cpp/libx264/common/x86/cabac-a.asm b/library/src/main/cpp/libx264/common/x86/cabac-a.asm index d7870a3..49bca50 100644 --- a/library/src/main/cpp/libx264/common/x86/cabac-a.asm +++ b/library/src/main/cpp/libx264/common/x86/cabac-a.asm @@ -53,21 +53,32 @@ coeff_abs_level_transition: db 1, 2, 3, 3, 4, 5, 6, 7 %endmacro cextern coeff_last4_mmx2 -cextern coeff_last4_mmx2_lzcnt +cextern coeff_last4_lzcnt +%if HIGH_BIT_DEPTH +cextern coeff_last4_avx512 +%endif cextern coeff_last15_sse2 -cextern coeff_last15_sse2_lzcnt +cextern coeff_last15_lzcnt +cextern coeff_last15_avx512 cextern coeff_last16_sse2 -cextern coeff_last16_sse2_lzcnt +cextern coeff_last16_lzcnt +cextern coeff_last16_avx512 cextern coeff_last64_sse2 -cextern coeff_last64_sse2_lzcnt -cextern coeff_last64_avx2_lzcnt +cextern coeff_last64_lzcnt +cextern coeff_last64_avx2 +cextern coeff_last64_avx512 %ifdef PIC SECTION .data %endif -coeff_last_sse2: COEFF_LAST_TABLE mmx2, sse2, sse2, 16, 15, 16, 4, 15, 64, 16, 15, 16, 64, 16, 15, 16, 64 -coeff_last_sse2_lzcnt: COEFF_LAST_TABLE mmx2_lzcnt, sse2_lzcnt, sse2_lzcnt, 16, 15, 16, 4, 15, 64, 16, 15, 16, 64, 16, 15, 16, 64 -coeff_last_avx2_lzcnt: COEFF_LAST_TABLE mmx2_lzcnt, avx2_lzcnt, sse2_lzcnt, 16, 15, 16, 4, 15, 64, 16, 15, 16, 64, 16, 15, 16, 64 +coeff_last_sse2: COEFF_LAST_TABLE mmx2, sse2, sse2, 16, 15, 16, 4, 15, 64, 16, 15, 16, 64, 16, 15, 16, 64 +coeff_last_lzcnt: COEFF_LAST_TABLE lzcnt, lzcnt, lzcnt, 16, 15, 16, 4, 15, 64, 16, 15, 16, 64, 16, 15, 16, 64 +coeff_last_avx2: COEFF_LAST_TABLE lzcnt, avx2, lzcnt, 16, 15, 16, 4, 15, 64, 16, 15, 16, 64, 16, 15, 16, 64 +%if HIGH_BIT_DEPTH +coeff_last_avx512: COEFF_LAST_TABLE avx512, avx512, avx512, 16, 15, 16, 4, 15, 64, 16, 15, 16, 64, 16, 15, 16, 64 +%else +coeff_last_avx512: COEFF_LAST_TABLE lzcnt, avx512, avx512, 16, 15, 16, 4, 15, 64, 16, 15, 16, 64, 16, 15, 16, 64 +%endif %endif SECTION .text @@ -100,7 +111,7 @@ struc cb .start: pointer 1 .p: pointer 1 .end: pointer 1 - align 16, resb 1 + align 64, resb 1 .bits_encoded: resd 1 .state: resb 1024 endstruc @@ -352,25 +363,33 @@ CABAC bmi2 %endmacro %macro ABS_DCTCOEFS 2 -%assign i 0 -%rep %2/16 %if HIGH_BIT_DEPTH - ABSD m0, [%1+ 0+i*64], m4 - ABSD m1, [%1+16+i*64], m5 - ABSD m2, [%1+32+i*64], m4 - ABSD m3, [%1+48+i*64], m5 - mova [rsp+ 0+i*64], m0 - mova [rsp+16+i*64], m1 - mova [rsp+32+i*64], m2 - mova [rsp+48+i*64], m3 + %define %%abs ABSD %else - ABSW m0, [%1+ 0+i*32], m2 - ABSW m1, [%1+16+i*32], m3 - mova [rsp+ 0+i*32], m0 - mova [rsp+16+i*32], m1 -%endif + %define %%abs ABSW +%endif +%if mmsize == %2*SIZEOF_DCTCOEF + %%abs m0, [%1], m1 + mova [rsp], m0 +%elif mmsize == %2*SIZEOF_DCTCOEF/2 + %%abs m0, [%1+0*mmsize], m2 + %%abs m1, [%1+1*mmsize], m3 + mova [rsp+0*mmsize], m0 + mova [rsp+1*mmsize], m1 +%else +%assign i 0 +%rep %2*SIZEOF_DCTCOEF/(4*mmsize) + %%abs m0, [%1+(4*i+0)*mmsize], m4 + %%abs m1, [%1+(4*i+1)*mmsize], m5 + %%abs m2, [%1+(4*i+2)*mmsize], m4 + %%abs m3, [%1+(4*i+3)*mmsize], m5 + mova [rsp+(4*i+0)*mmsize], m0 + mova [rsp+(4*i+1)*mmsize], m1 + mova [rsp+(4*i+2)*mmsize], m2 + mova [rsp+(4*i+3)*mmsize], m3 %assign i i+1 %endrep +%endif %endmacro %macro SIG_OFFSET 1 @@ -403,16 +422,14 @@ CABAC bmi2 %endif %ifdef PIC - cglobal func, 4,13 + cglobal func, 4,13,6,-maxcoeffs*SIZEOF_DCTCOEF lea r12, [$$] %define GLOBAL +r12-$$ %else - cglobal func, 4,12 + cglobal func, 4,12,6,-maxcoeffs*SIZEOF_DCTCOEF %define GLOBAL %endif -%assign pad gprsize+SIZEOF_DCTCOEF*maxcoeffs-(stack_offset&15) - SUB rsp, pad shl r1d, 4 ; MB_INTERLACED*16 %if %1 lea r4, [significant_coeff_flag_offset_8x8+r1*4 GLOBAL] ; r12 = sig offset 8x8 @@ -429,15 +446,13 @@ CABAC bmi2 ABS_DCTCOEFS r0, 64 %else mov r4, r0 ; r4 = dct - mov r6, ~SIZEOF_DCTCOEF - and r6, r4 ; handle AC coefficient case - ABS_DCTCOEFS r6, 16 - sub r4, r6 ; calculate our new dct pointer + and r4, ~SIZEOF_DCTCOEF ; handle AC coefficient case + ABS_DCTCOEFS r4, 16 + xor r4, r0 ; calculate our new dct pointer add r4, rsp ; restore AC coefficient offset %endif - mov r1, [%2+gprsize*r2 GLOBAL] ; for improved OOE performance, run coeff_last on the original coefficients. - call r1 ; coeff_last[ctx_block_cat]( dct ) + call [%2+gprsize*r2 GLOBAL] ; coeff_last[ctx_block_cat]( dct ) ; we know on 64-bit that the SSE2 versions of this function only ; overwrite r0, r1, and rax (r6). last64 overwrites r2 too, but we ; don't need r2 in 8x8 mode. @@ -521,7 +536,6 @@ CABAC bmi2 jge .coeff_loop .end: mov [r3+cb.bits_encoded-cb.state], r0d - ADD rsp, pad RET %endmacro @@ -529,15 +543,23 @@ CABAC bmi2 INIT_XMM sse2 CABAC_RESIDUAL_RD 0, coeff_last_sse2 CABAC_RESIDUAL_RD 1, coeff_last_sse2 -INIT_XMM sse2,lzcnt -CABAC_RESIDUAL_RD 0, coeff_last_sse2_lzcnt -CABAC_RESIDUAL_RD 1, coeff_last_sse2_lzcnt +INIT_XMM lzcnt +CABAC_RESIDUAL_RD 0, coeff_last_lzcnt +CABAC_RESIDUAL_RD 1, coeff_last_lzcnt INIT_XMM ssse3 CABAC_RESIDUAL_RD 0, coeff_last_sse2 CABAC_RESIDUAL_RD 1, coeff_last_sse2 INIT_XMM ssse3,lzcnt -CABAC_RESIDUAL_RD 0, coeff_last_sse2_lzcnt -CABAC_RESIDUAL_RD 1, coeff_last_sse2_lzcnt +CABAC_RESIDUAL_RD 0, coeff_last_lzcnt +CABAC_RESIDUAL_RD 1, coeff_last_lzcnt +%if HIGH_BIT_DEPTH +INIT_ZMM avx512 +%else +INIT_YMM avx512 +%endif +CABAC_RESIDUAL_RD 0, coeff_last_avx512 +INIT_ZMM avx512 +CABAC_RESIDUAL_RD 1, coeff_last_avx512 %endif ;----------------------------------------------------------------------------- @@ -615,7 +637,7 @@ CABAC_RESIDUAL_RD 1, coeff_last_sse2_lzcnt %endmacro %macro CABAC_RESIDUAL 1 -cglobal cabac_block_residual_internal, 4,15 +cglobal cabac_block_residual_internal, 4,15,0,-4*64 %ifdef PIC ; if we use the same r7 as in cabac_encode_decision, we can cheat and save a register. lea r7, [$$] @@ -625,8 +647,6 @@ cglobal cabac_block_residual_internal, 4,15 %define lastm r7d %define GLOBAL %endif -%assign pad gprsize+4*2+4*64-(stack_offset&15) - SUB rsp, pad shl r1d, 4 %define sigoffq r8 @@ -653,8 +673,7 @@ cglobal cabac_block_residual_internal, 4,15 mov dct, r0 mov leveloffm, leveloffd - mov r1, [%1+gprsize*r2 GLOBAL] - call r1 + call [%1+gprsize*r2 GLOBAL] mov lastm, eax ; put cabac in r0; needed for cabac_encode_decision mov r0, r3 @@ -742,15 +761,16 @@ cglobal cabac_block_residual_internal, 4,15 %endif dec coeffidxd jge .level_loop - ADD rsp, pad RET %endmacro %if ARCH_X86_64 INIT_XMM sse2 CABAC_RESIDUAL coeff_last_sse2 -INIT_XMM sse2,lzcnt -CABAC_RESIDUAL coeff_last_sse2_lzcnt -INIT_XMM avx2,bmi2 -CABAC_RESIDUAL coeff_last_avx2_lzcnt +INIT_XMM lzcnt +CABAC_RESIDUAL coeff_last_lzcnt +INIT_XMM avx2 +CABAC_RESIDUAL coeff_last_avx2 +INIT_XMM avx512 +CABAC_RESIDUAL coeff_last_avx512 %endif diff --git a/library/src/main/cpp/libx264/common/x86/cpu-a.asm b/library/src/main/cpp/libx264/common/x86/cpu-a.asm index c961903..4692f65 100644 --- a/library/src/main/cpp/libx264/common/x86/cpu-a.asm +++ b/library/src/main/cpp/libx264/common/x86/cpu-a.asm @@ -53,18 +53,16 @@ cglobal cpu_cpuid, 5,7 RET ;----------------------------------------------------------------------------- -; void cpu_xgetbv( int op, int *eax, int *edx ) +; uint64_t cpu_xgetbv( int xcr ) ;----------------------------------------------------------------------------- -cglobal cpu_xgetbv, 3,7 - push r2 - push r1 - mov ecx, r0d +cglobal cpu_xgetbv + movifnidn ecx, r0m xgetbv - pop r4 - mov [r4], eax - pop r4 - mov [r4], edx - RET +%if ARCH_X86_64 + shl rdx, 32 + or rax, rdx +%endif + ret %if ARCH_X86_64 @@ -77,7 +75,7 @@ cglobal stack_align %if WIN64 sub rsp, 32 ; shadow space %endif - and rsp, ~31 + and rsp, ~(STACK_ALIGNMENT-1) mov rax, r0 mov r0, r1 mov r1, r2 @@ -118,7 +116,7 @@ cglobal stack_align push ebp mov ebp, esp sub esp, 12 - and esp, ~31 + and esp, ~(STACK_ALIGNMENT-1) mov ecx, [ebp+8] mov edx, [ebp+12] mov [esp], edx diff --git a/library/src/main/cpp/libx264/common/x86/dct-a.asm b/library/src/main/cpp/libx264/common/x86/dct-a.asm index c2f8973..33ed061 100644 --- a/library/src/main/cpp/libx264/common/x86/dct-a.asm +++ b/library/src/main/cpp/libx264/common/x86/dct-a.asm @@ -30,7 +30,41 @@ %include "x86inc.asm" %include "x86util.asm" -SECTION_RODATA 32 +SECTION_RODATA 64 +; AVX-512 permutation indices are bit-packed to save cache +%if HIGH_BIT_DEPTH +scan_frame_avx512: dd 0x00bf0200, 0x00fd7484, 0x0033a611, 0x0069d822 ; bits 0-3: 4x4_frame + dd 0x00a3ca95, 0x00dd8d08, 0x00e75b8c, 0x00a92919 ; bits 4-8: 8x8_frame1 + dd 0x0072f6a6, 0x003c8433, 0x007e5247, 0x00b6a0ba ; bits 9-13: 8x8_frame2 + dd 0x00ecf12d, 0x00f3239e, 0x00b9540b, 0x00ff868f ; bits 14-18: 8x8_frame3 + ; bits 19-23: 8x8_frame4 +scan_field_avx512: dd 0x0006b240, 0x000735a1, 0x0007b9c2, 0x0009bde8 ; bits 0-4: 8x8_field1 + dd 0x000c4e69, 0x000ce723, 0x000a0004, 0x000aeb4a ; bits 5-9: 8x8_field2 + dd 0x000b5290, 0x000bd6ab, 0x000d5ac5, 0x000ddee6 ; bits 10-14: 8x8_field3 + dd 0x000e6f67, 0x000e842c, 0x000f0911, 0x000ff058 ; bits 15-19: 8x8_field4 +cavlc_shuf_avx512: dd 0x00018820, 0x000398a4, 0x0005a928, 0x0007b9ac ; bits 0-4: interleave1 + dd 0x0009ca30, 0x000bdab4, 0x000deb38, 0x000ffbbc ; bits 5-9: interleave2 + dd 0x00010c01, 0x00031c85, 0x00052d09, 0x00073d8d ; bits 10-14: interleave3 + dd 0x00094e11, 0x000b5e95, 0x000d6f19, 0x000f7f9d ; bits 15-19: interleave4 +%else +dct_avx512: dd 0x10000000, 0x00021104, 0x3206314c, 0x60042048 ; bits 0-4: dct8x8_fenc bits 5-9: dct8x8_fdec + dd 0x98008a10, 0x20029b14, 0xba06bb5c, 0x4004aa58 ; bits 10-13: dct16x16_fenc bits 14-18: dct16x16_fdec + dd 0x54004421, 0x80025525, 0x7606756d, 0xe0046469 ; bits(e) 24-27: idct8x8_idct1 bits(e) 28-31: idct8x8_idct2 + dd 0xdc00ce31, 0xa002df35, 0xfe06ff7d, 0xc004ee79 ; bits(o) 24-31: idct8x8_gather +scan_frame_avx512: dw 0x7000, 0x5484, 0x3811, 0x1c22, 0x3c95, 0x5908, 0x758c, 0x9119 ; bits 0-3: 4x4_frame + dw 0xaca6, 0xc833, 0xe447, 0xe8ba, 0xcd2d, 0xb19e, 0x960b, 0x7a8f ; bits 4-9: 8x8_frame1 + dw 0x5e10, 0x7da0, 0x9930, 0xb4c0, 0xd050, 0xec60, 0xf0d0, 0xd540 ; bits 10-15: 8x8_frame2 + dw 0xb9b0, 0x9e20, 0xbe90, 0xdb00, 0xf780, 0xfb10, 0xdea0, 0xfe30 +scan_field_avx512: dw 0x0700, 0x0741, 0x0782, 0x07c8, 0x08c9, 0x0a43, 0x0c04, 0x0a8a ; bits 0-5: 8x8_field1 + dw 0x0910, 0x094b, 0x0985, 0x09c6, 0x0ac7, 0x0c4c, 0x0c91, 0x0b18 ; bits 6-11: 8x8_field2 + dw 0x0b52, 0x0b8d, 0x0bce, 0x0ccf, 0x0e13, 0x0e59, 0x0d20, 0x0d5a + dw 0x0d94, 0x0dd5, 0x0e96, 0x0ed7, 0x0f1b, 0x0f61, 0x0fa8, 0x0fe2 +cavlc_shuf_avx512: dw 0x0080, 0x0184, 0x0288, 0x038c, 0x0490, 0x0594, 0x0698, 0x079c ; bits 0-5: interleave1 + dw 0x08a0, 0x09a4, 0x0aa8, 0x0bac, 0x0cb0, 0x0db4, 0x0eb8, 0x0fbc ; bits 6-11: interleave2 + dw 0x00c1, 0x01c5, 0x02c9, 0x03cd, 0x04d1, 0x05d5, 0x06d9, 0x07dd + dw 0x08e1, 0x09e5, 0x0ae9, 0x0bed, 0x0cf1, 0x0df5, 0x0ef9, 0x0ffd +%endif + pw_ppmmmmpp: dw 1,1,-1,-1,-1,-1,1,1 pb_sub4frame: db 0,1,4,8,5,2,3,6,9,12,13,10,7,11,14,15 pb_sub4field: db 0,4,1,8,12,5,9,13,2,6,10,14,3,7,11,15 @@ -580,6 +614,217 @@ cglobal sub16x16_dct, 3,3,6 DCT4_1D 0, 1, 2, 3, 4 STORE16_DCT_AVX2 0, 1, 2, 3, 4 ret + +%macro DCT4x4_AVX512 0 + psubw m0, m2 ; 0 1 + psubw m1, m3 ; 3 2 + SUMSUB_BA w, 1, 0, 2 + SBUTTERFLY wd, 1, 0, 2 + paddw m2, m1, m0 + psubw m3, m1, m0 + paddw m2 {k1}, m1 ; 0+1+2+3 0<<1+1-2-3<<1 + psubw m3 {k1}, m0 ; 0-1-2+3 0-1<<1+2<<1-3 + shufps m1, m2, m3, q2323 ; a3 b3 a2 b2 c3 d3 c2 d2 + punpcklqdq m2, m3 ; a0 b0 a1 b1 c0 d0 c1 d1 + SUMSUB_BA w, 1, 2, 3 + shufps m3, m1, m2, q3131 ; a1+a2 b1+b2 c1+c2 d1+d2 a1-a2 b1-b2 b1-b2 d1-d2 + shufps m1, m2, q2020 ; a0+a3 b0+b3 c0+c3 d0+d3 a0-a3 b0-b3 c0-c3 d0-d3 + paddw m2, m1, m3 + psubw m0, m1, m3 + paddw m2 {k2}, m1 ; 0'+1'+2'+3' 0'<<1+1'-2'-3'<<1 + psubw m0 {k2}, m3 ; 0'-1'-2'+3' 0'-1'<<1+2'<<1-3' +%endmacro + +INIT_XMM avx512 +cglobal sub4x4_dct + mov eax, 0xf0aa + kmovw k1, eax + PROLOGUE 3,3 + movd m0, [r1+0*FENC_STRIDE] + movd m2, [r2+0*FDEC_STRIDE] + vpbroadcastd m0 {k1}, [r1+1*FENC_STRIDE] + vpbroadcastd m2 {k1}, [r2+1*FDEC_STRIDE] + movd m1, [r1+3*FENC_STRIDE] + movd m3, [r2+3*FDEC_STRIDE] + vpbroadcastd m1 {k1}, [r1+2*FENC_STRIDE] + vpbroadcastd m3 {k1}, [r2+2*FDEC_STRIDE] + kshiftrw k2, k1, 8 + pxor m4, m4 + punpcklbw m0, m4 + punpcklbw m2, m4 + punpcklbw m1, m4 + punpcklbw m3, m4 + DCT4x4_AVX512 + mova [r0], m2 + mova [r0+16], m0 + RET + +INIT_ZMM avx512 +cglobal dct4x4x4_internal + punpcklbw m0, m1, m4 + punpcklbw m2, m3, m4 + punpckhbw m1, m4 + punpckhbw m3, m4 + DCT4x4_AVX512 + mova m1, m2 + vshufi32x4 m2 {k2}, m0, m0, q2200 ; m0 + vshufi32x4 m0 {k3}, m1, m1, q3311 ; m1 + ret + +%macro DCT8x8_LOAD_FENC_AVX512 4 ; dst, perm, row1, row2 + movu %1, [r1+%3*FENC_STRIDE] + vpermt2d %1, %2, [r1+%4*FENC_STRIDE] +%endmacro + +%macro DCT8x8_LOAD_FDEC_AVX512 5 ; dst, perm, tmp, row1, row2 + movu %1, [r2+(%4 )*FDEC_STRIDE] + vmovddup %1 {k1}, [r2+(%4+2)*FDEC_STRIDE] + movu %3, [r2+(%5 )*FDEC_STRIDE] + vmovddup %3 {k1}, [r2+(%5+2)*FDEC_STRIDE] + vpermt2d %1, %2, %3 +%endmacro + +cglobal sub8x8_dct, 3,3 + mova m0, [dct_avx512] + DCT8x8_LOAD_FENC_AVX512 m1, m0, 0, 4 ; 0 2 1 3 + mov r1d, 0xaaaaaaaa + kmovd k1, r1d + psrld m0, 5 + DCT8x8_LOAD_FDEC_AVX512 m3, m0, m2, 0, 4 + mov r1d, 0xf0f0f0f0 + kmovd k2, r1d + pxor xm4, xm4 + knotw k3, k2 + call dct4x4x4_internal_avx512 + mova [r0], m0 + mova [r0+64], m1 + RET + +%macro SUB4x16_DCT_AVX512 2 ; dst, src + vpermd m1, m5, [r1+1*%2*64] + mova m3, [r2+2*%2*64] + vpermt2d m3, m6, [r2+2*%2*64+64] + call dct4x4x4_internal_avx512 + mova [r0+%1*64 ], m0 + mova [r0+%1*64+128], m1 +%endmacro + +cglobal sub16x16_dct + psrld m5, [dct_avx512], 10 + mov eax, 0xaaaaaaaa + kmovd k1, eax + mov eax, 0xf0f0f0f0 + kmovd k2, eax + PROLOGUE 3,3 + pxor xm4, xm4 + knotw k3, k2 + psrld m6, m5, 4 + SUB4x16_DCT_AVX512 0, 0 + SUB4x16_DCT_AVX512 1, 1 + SUB4x16_DCT_AVX512 4, 2 + SUB4x16_DCT_AVX512 5, 3 + RET + +cglobal sub8x8_dct_dc, 3,3 + mova m3, [dct_avx512] + DCT8x8_LOAD_FENC_AVX512 m0, m3, 0, 4 ; 0 2 1 3 + mov r1d, 0xaa + kmovb k1, r1d + psrld m3, 5 + DCT8x8_LOAD_FDEC_AVX512 m1, m3, m2, 0, 4 + pxor xm3, xm3 + psadbw m0, m3 + psadbw m1, m3 + psubw m0, m1 + vpmovqw xmm0, m0 + vprold xmm1, xmm0, 16 + paddw xmm0, xmm1 ; 0 0 2 2 1 1 3 3 + punpckhqdq xmm2, xmm0, xmm0 + psubw xmm1, xmm0, xmm2 ; 0-1 0-1 2-3 2-3 + paddw xmm0, xmm2 ; 0+1 0+1 2+3 2+3 + punpckldq xmm0, xmm1 ; 0+1 0+1 0-1 0-1 2+3 2+3 2-3 2-3 + punpcklqdq xmm1, xmm0, xmm0 + psubw xmm0 {k1}, xm3, xmm0 + paddw xmm0, xmm1 ; 0+1+2+3 0+1-2-3 0-1+2-3 0-1-2+3 + movhps [r0], xmm0 + RET + +cglobal sub8x16_dct_dc, 3,3 + mova m5, [dct_avx512] + DCT8x8_LOAD_FENC_AVX512 m0, m5, 0, 8 ; 0 4 1 5 + DCT8x8_LOAD_FENC_AVX512 m1, m5, 4, 12 ; 2 6 3 7 + mov r1d, 0xaa + kmovb k1, r1d + psrld m5, 5 + DCT8x8_LOAD_FDEC_AVX512 m2, m5, m4, 0, 8 + DCT8x8_LOAD_FDEC_AVX512 m3, m5, m4, 4, 12 + pxor xm4, xm4 + psadbw m0, m4 + psadbw m1, m4 + psadbw m2, m4 + psadbw m3, m4 + psubw m0, m2 + psubw m1, m3 + SBUTTERFLY qdq, 0, 1, 2 + paddw m0, m1 + vpmovqw xmm0, m0 ; 0 2 4 6 1 3 5 7 + psrlq xmm2, xmm0, 32 + psubw xmm1, xmm0, xmm2 ; 0-4 2-6 1-5 3-7 + paddw xmm0, xmm2 ; 0+4 2+6 1+5 3+7 + punpckhdq xmm2, xmm0, xmm1 + punpckldq xmm0, xmm1 + psubw xmm1, xmm0, xmm2 ; 0-1+4-5 2-3+6-7 0-1-4+5 2-3-6+7 + paddw xmm0, xmm2 ; 0+1+4+5 2+3+6+7 0+1-4-5 2+3-6-7 + punpcklwd xmm0, xmm1 + psrlq xmm2, xmm0, 32 + psubw xmm1, xmm0, xmm2 ; 0+1-2-3+4+5-6-7 0-1-2+3+4-5-6+7 0+1-2-3-4-5+6+7 0-1-2+3-4+5+6-7 + paddw xmm0, xmm2 ; 0+1+2+3+4+5+6+7 0-1+2-3+4-5+6-7 0+1+2+3-4-5-6-7 0-1+2-3-4+5-6+7 + shufps xmm0, xmm1, q0220 + mova [r0], xmm0 + RET + +%macro SARSUMSUB 3 ; a, b, tmp + mova m%3, m%1 + vpsraw m%1 {k1}, 1 + psubw m%1, m%2 ; 0-2 1>>1-3 + vpsraw m%2 {k1}, 1 + paddw m%2, m%3 ; 0+2 1+3>>1 +%endmacro + +cglobal add8x8_idct, 2,2 + mova m1, [r1] + mova m2, [r1+64] + mova m3, [dct_avx512] + vbroadcasti32x4 m4, [pw_32] + mov r1d, 0xf0f0f0f0 + kxnorb k2, k2, k2 + kmovd k1, r1d + kmovb k3, k2 + vshufi32x4 m0, m1, m2, q2020 ; 0 1 4 5 8 9 c d + vshufi32x4 m1, m2, q3131 ; 2 3 6 7 a b e f + psrlq m5, m3, 56 ; {0, 3, 1, 2, 4, 7, 5, 6} * FDEC_STRIDE + vpgatherqq m6 {k2}, [r0+m5] + SARSUMSUB 0, 1, 2 + SBUTTERFLY wd, 1, 0, 2 + psrlq m7, m3, 28 + SUMSUB_BA w, 0, 1, 2 ; 0+1+2+3>>1 0+1>>1-2-3 + vprold m1, 16 ; 0-1>>1-2+3 0-1+2-3>>1 + SBUTTERFLY dq, 0, 1, 2 + psrlq m3, 24 + SARSUMSUB 0, 1, 2 + vpermi2q m3, m1, m0 + vpermt2q m1, m7, m0 + paddw m3, m4 ; += 32 + SUMSUB_BA w, 1, 3, 0 + psraw m1, 6 ; 0'+1'+2'+3'>>1 0'+1'>>1-2'-3' + psraw m3, 6 ; 0'-1'+2'-3'>>1 0'-1'>>1-2'+3' + pxor xm0, xm0 + SBUTTERFLY bw, 6, 0, 2 + paddsw m1, m6 + paddsw m3, m0 + packuswb m1, m3 + vpscatterqq [r0+m5] {k3}, m1 + RET %endif ; HIGH_BIT_DEPTH INIT_MMX @@ -1883,3 +2128,161 @@ cglobal zigzag_interleave_8x8_cavlc, 3,3,6 mov [r2+8], r0w RET %endif ; !HIGH_BIT_DEPTH + +%if HIGH_BIT_DEPTH +INIT_ZMM avx512 +cglobal zigzag_scan_4x4_frame, 2,2 + mova m0, [scan_frame_avx512] + vpermd m0, m0, [r1] + mova [r0], m0 + RET + +cglobal zigzag_scan_4x4_field, 2,2 + mova m0, [r1] + pshufd xmm1, [r1+8], q3102 + mova [r0], m0 + movu [r0+8], xmm1 + RET + +cglobal zigzag_scan_8x8_frame, 2,2 + psrld m0, [scan_frame_avx512], 4 + mova m1, [r1+0*64] + mova m2, [r1+1*64] + mova m3, [r1+2*64] + mova m4, [r1+3*64] + mov r1d, 0x01fe7f80 + kmovd k1, r1d + kshiftrd k2, k1, 16 + vpermd m5, m0, m3 ; __ __ __ __ __ __ __ __ __ __ __ __ __ __ 32 40 + psrld m6, m0, 5 + vpermi2d m0, m1, m2 ; 0 8 1 2 9 16 24 17 10 3 4 11 18 25 __ __ + vmovdqa64 m0 {k1}, m5 + mova [r0+0*64], m0 + mova m5, m1 + vpermt2d m1, m6, m2 ; __ 26 19 12 5 6 13 20 27 __ __ __ __ __ __ __ + psrld m0, m6, 5 + vpermi2d m6, m3, m4 ; 33 __ __ __ __ __ __ __ __ 34 41 48 56 49 42 35 + vmovdqa32 m6 {k2}, m1 + mova [r0+1*64], m6 + vpermt2d m5, m0, m2 ; 28 21 14 7 15 22 29 __ __ __ __ __ __ __ __ 30 + psrld m1, m0, 5 + vpermi2d m0, m3, m4 ; __ __ __ __ __ __ __ 36 43 50 57 58 51 44 37 __ + vmovdqa32 m5 {k1}, m0 + mova [r0+2*64], m5 + vpermt2d m3, m1, m4 ; __ __ 38 45 52 59 60 53 46 39 47 54 61 62 55 63 + vpermd m2, m1, m2 ; 23 31 __ __ __ __ __ __ __ __ __ __ __ __ __ __ + vmovdqa64 m2 {k2}, m3 + mova [r0+3*64], m2 + RET + +cglobal zigzag_scan_8x8_field, 2,2 + mova m0, [scan_field_avx512] + mova m1, [r1+0*64] + mova m2, [r1+1*64] + mova m3, [r1+2*64] + mova m4, [r1+3*64] + mov r1d, 0x3f + kmovb k1, r1d + psrld m5, m0, 5 + vpermi2d m0, m1, m2 + vmovdqa64 m1 {k1}, m3 ; 32 33 34 35 36 37 38 39 40 41 42 43 12 13 14 15 + vpermt2d m1, m5, m2 + psrld m5, 5 + vmovdqa64 m2 {k1}, m4 ; 48 49 50 51 52 53 54 55 56 57 58 59 28 29 30 31 + vpermt2d m2, m5, m3 + psrld m5, 5 + vpermt2d m3, m5, m4 + mova [r0+0*64], m0 + mova [r0+1*64], m1 + mova [r0+2*64], m2 + mova [r0+3*64], m3 + RET + +cglobal zigzag_interleave_8x8_cavlc, 3,3 + mova m0, [cavlc_shuf_avx512] + mova m1, [r1+0*64] + mova m2, [r1+1*64] + mova m3, [r1+2*64] + mova m4, [r1+3*64] + kxnorb k1, k1, k1 + por m7, m1, m2 + psrld m5, m0, 5 + vpermi2d m0, m1, m2 ; a0 a1 b0 b1 + vpternlogd m7, m3, m4, 0xfe ; m1|m2|m3|m4 + psrld m6, m5, 5 + vpermi2d m5, m3, m4 ; b2 b3 a2 a3 + vptestmd k0, m7, m7 + vpermt2d m1, m6, m2 ; c0 c1 d0 d1 + psrld m6, 5 + vpermt2d m3, m6, m4 ; d2 d3 c2 c3 + vshufi32x4 m2, m0, m5, q1032 ; b0 b1 b2 b3 + vmovdqa32 m5 {k1}, m0 ; a0 a1 a2 a3 + vshufi32x4 m4, m1, m3, q1032 ; d0 d1 d2 d3 + vmovdqa32 m3 {k1}, m1 ; c0 c1 c2 c3 + mova [r0+0*64], m5 + mova [r0+1*64], m2 + mova [r0+2*64], m3 + mova [r0+3*64], m4 + kmovw r1d, k0 + test r1d, 0x1111 + setnz [r2] + test r1d, 0x2222 + setnz [r2+1] + test r1d, 0x4444 + setnz [r2+8] + test r1d, 0x8888 + setnz [r2+9] + RET + +%else ; !HIGH_BIT_DEPTH +INIT_YMM avx512 +cglobal zigzag_scan_4x4_frame, 2,2 + mova m0, [scan_frame_avx512] + vpermw m0, m0, [r1] + mova [r0], m0 + RET + +cglobal zigzag_scan_4x4_field, 2,2 + mova m0, [r1] + pshuflw xmm1, [r1+4], q3102 + mova [r0], m0 + movq [r0+4], xmm1 + RET + +INIT_ZMM avx512 +cglobal zigzag_scan_8x8_frame, 2,2 + psrlw m0, [scan_frame_avx512], 4 +scan8_avx512: + mova m1, [r1] + mova m2, [r1+64] + psrlw m3, m0, 6 + vpermi2w m0, m1, m2 + vpermt2w m1, m3, m2 + mova [r0], m0 + mova [r0+64], m1 + RET + +cglobal zigzag_scan_8x8_field, 2,2 + mova m0, [scan_field_avx512] + jmp scan8_avx512 + +cglobal zigzag_interleave_8x8_cavlc, 3,3 + mova m0, [cavlc_shuf_avx512] + mova m1, [r1] + mova m2, [r1+64] + psrlw m3, m0, 6 + vpermi2w m0, m1, m2 + vpermt2w m1, m3, m2 + kxnorb k2, k2, k2 + vptestmd k0, m0, m0 + vptestmd k1, m1, m1 + mova [r0], m0 + mova [r0+64], m1 + ktestw k2, k0 + setnz [r2] + setnc [r2+1] + ktestw k2, k1 + setnz [r2+8] + setnc [r2+9] + RET +%endif ; !HIGH_BIT_DEPTH diff --git a/library/src/main/cpp/libx264/common/x86/dct.h b/library/src/main/cpp/libx264/common/x86/dct.h index 67221c3..20a65c5 100644 --- a/library/src/main/cpp/libx264/common/x86/dct.h +++ b/library/src/main/cpp/libx264/common/x86/dct.h @@ -34,6 +34,7 @@ void x264_sub16x16_dct_mmx ( dctcoef dct[16][16], pixel *pix1, pixel *pix2 void x264_sub8x8_dct_sse2 ( int16_t dct[ 4][16], uint8_t *pix1, uint8_t *pix2 ); void x264_sub16x16_dct_sse2 ( int16_t dct[16][16], uint8_t *pix1, uint8_t *pix2 ); void x264_sub4x4_dct_ssse3 ( int16_t dct [16], uint8_t *pix1, uint8_t *pix2 ); +void x264_sub4x4_dct_avx512 ( int16_t dct [16], uint8_t *pix1, uint8_t *pix2 ); void x264_sub8x8_dct_ssse3 ( int16_t dct[ 4][16], uint8_t *pix1, uint8_t *pix2 ); void x264_sub16x16_dct_ssse3( int16_t dct[16][16], uint8_t *pix1, uint8_t *pix2 ); void x264_sub8x8_dct_avx ( int16_t dct[ 4][16], uint8_t *pix1, uint8_t *pix2 ); @@ -41,12 +42,16 @@ void x264_sub16x16_dct_avx ( int16_t dct[16][16], uint8_t *pix1, uint8_t *pix2 void x264_sub8x8_dct_xop ( int16_t dct[ 4][16], uint8_t *pix1, uint8_t *pix2 ); void x264_sub16x16_dct_xop ( int16_t dct[16][16], uint8_t *pix1, uint8_t *pix2 ); void x264_sub8x8_dct_avx2 ( int16_t dct[ 4][16], uint8_t *pix1, uint8_t *pix2 ); +void x264_sub8x8_dct_avx512 ( int16_t dct[ 4][16], uint8_t *pix1, uint8_t *pix2 ); void x264_sub16x16_dct_avx2 ( int16_t dct[16][16], uint8_t *pix1, uint8_t *pix2 ); -void x264_sub8x8_dct_dc_mmx2( int16_t dct [ 4], uint8_t *pix1, uint8_t *pix2 ); -void x264_sub8x8_dct_dc_sse2( dctcoef dct [ 4], pixel *pix1, pixel *pix2 ); -void x264_sub8x16_dct_dc_sse2 ( dctcoef dct [ 4], pixel *pix1, pixel *pix2 ); -void x264_sub8x16_dct_dc_ssse3( int16_t dct [ 4], uint8_t *pix1, uint8_t *pix2 ); -void x264_sub8x16_dct_dc_avx ( dctcoef dct [ 4], pixel *pix1, pixel *pix2 ); +void x264_sub16x16_dct_avx512( int16_t dct[16][16], uint8_t *pix1, uint8_t *pix2 ); +void x264_sub8x8_dct_dc_mmx2 ( int16_t dct [ 4], uint8_t *pix1, uint8_t *pix2 ); +void x264_sub8x8_dct_dc_sse2 ( dctcoef dct [ 4], pixel *pix1, pixel *pix2 ); +void x264_sub8x8_dct_dc_avx512 ( int16_t dct [ 4], uint8_t *pix1, uint8_t *pix2 ); +void x264_sub8x16_dct_dc_sse2 ( dctcoef dct [ 8], pixel *pix1, pixel *pix2 ); +void x264_sub8x16_dct_dc_ssse3 ( int16_t dct [ 8], uint8_t *pix1, uint8_t *pix2 ); +void x264_sub8x16_dct_dc_avx ( dctcoef dct [ 8], pixel *pix1, pixel *pix2 ); +void x264_sub8x16_dct_dc_avx512( int16_t dct [ 8], uint8_t *pix1, uint8_t *pix2 ); void x264_add4x4_idct_mmx ( uint8_t *p_dst, int16_t dct [16] ); void x264_add4x4_idct_sse2 ( uint16_t *p_dst, int32_t dct [16] ); @@ -59,6 +64,7 @@ void x264_add16x16_idct_dc_mmx2 ( uint8_t *p_dst, int16_t dct [16] ); void x264_add8x8_idct_sse2 ( pixel *p_dst, dctcoef dct[ 4][16] ); void x264_add8x8_idct_avx ( pixel *p_dst, dctcoef dct[ 4][16] ); void x264_add8x8_idct_avx2 ( pixel *p_dst, dctcoef dct[ 4][16] ); +void x264_add8x8_idct_avx512 ( uint8_t *p_dst, int16_t dct[ 4][16] ); void x264_add16x16_idct_sse2 ( pixel *p_dst, dctcoef dct[16][16] ); void x264_add16x16_idct_avx ( pixel *p_dst, dctcoef dct[16][16] ); void x264_add16x16_idct_avx2 ( pixel *p_dst, dctcoef dct[16][16] ); @@ -101,22 +107,26 @@ void x264_add16x16_idct8_sse2( pixel *dst, dctcoef dct[4][64] ); void x264_add8x8_idct8_avx ( pixel *dst, dctcoef dct [64] ); void x264_add16x16_idct8_avx ( pixel *dst, dctcoef dct[4][64] ); -void x264_zigzag_scan_8x8_frame_xop ( int16_t level[64], int16_t dct[64] ); -void x264_zigzag_scan_8x8_frame_avx ( dctcoef level[64], dctcoef dct[64] ); -void x264_zigzag_scan_8x8_frame_ssse3( int16_t level[64], int16_t dct[64] ); -void x264_zigzag_scan_8x8_frame_sse2 ( dctcoef level[64], dctcoef dct[64] ); -void x264_zigzag_scan_8x8_frame_mmx2 ( int16_t level[64], int16_t dct[64] ); -void x264_zigzag_scan_4x4_frame_xop ( dctcoef level[16], dctcoef dct[16] ); -void x264_zigzag_scan_4x4_frame_avx ( dctcoef level[16], dctcoef dct[16] ); -void x264_zigzag_scan_4x4_frame_ssse3( int16_t level[16], int16_t dct[16] ); -void x264_zigzag_scan_4x4_frame_sse2 ( int32_t level[16], int32_t dct[16] ); -void x264_zigzag_scan_4x4_frame_mmx ( int16_t level[16], int16_t dct[16] ); -void x264_zigzag_scan_4x4_field_sse2 ( int32_t level[16], int32_t dct[16] ); -void x264_zigzag_scan_4x4_field_sse ( int16_t level[16], int16_t dct[16] ); -void x264_zigzag_scan_8x8_field_xop ( int16_t level[64], int16_t dct[64] ); -void x264_zigzag_scan_8x8_field_avx ( int32_t level[64], int32_t dct[64] ); -void x264_zigzag_scan_8x8_field_sse4 ( int32_t level[64], int32_t dct[64] ); -void x264_zigzag_scan_8x8_field_mmx2 ( int16_t level[64], int16_t dct[64] ); +void x264_zigzag_scan_8x8_frame_mmx2 ( int16_t level[64], int16_t dct[64] ); +void x264_zigzag_scan_8x8_frame_sse2 ( dctcoef level[64], dctcoef dct[64] ); +void x264_zigzag_scan_8x8_frame_ssse3 ( int16_t level[64], int16_t dct[64] ); +void x264_zigzag_scan_8x8_frame_avx ( dctcoef level[64], dctcoef dct[64] ); +void x264_zigzag_scan_8x8_frame_xop ( int16_t level[64], int16_t dct[64] ); +void x264_zigzag_scan_8x8_frame_avx512( dctcoef level[64], dctcoef dct[64] ); +void x264_zigzag_scan_4x4_frame_mmx ( int16_t level[16], int16_t dct[16] ); +void x264_zigzag_scan_4x4_frame_sse2 ( int32_t level[16], int32_t dct[16] ); +void x264_zigzag_scan_4x4_frame_ssse3 ( int16_t level[16], int16_t dct[16] ); +void x264_zigzag_scan_4x4_frame_avx ( dctcoef level[16], dctcoef dct[16] ); +void x264_zigzag_scan_4x4_frame_xop ( dctcoef level[16], dctcoef dct[16] ); +void x264_zigzag_scan_4x4_frame_avx512( dctcoef level[16], dctcoef dct[16] ); +void x264_zigzag_scan_4x4_field_sse ( int16_t level[16], int16_t dct[16] ); +void x264_zigzag_scan_4x4_field_sse2 ( int32_t level[16], int32_t dct[16] ); +void x264_zigzag_scan_4x4_field_avx512( dctcoef level[16], dctcoef dct[16] ); +void x264_zigzag_scan_8x8_field_mmx2 ( int16_t level[64], int16_t dct[64] ); +void x264_zigzag_scan_8x8_field_sse4 ( int32_t level[64], int32_t dct[64] ); +void x264_zigzag_scan_8x8_field_avx ( int32_t level[64], int32_t dct[64] ); +void x264_zigzag_scan_8x8_field_xop ( int16_t level[64], int16_t dct[64] ); +void x264_zigzag_scan_8x8_field_avx512( dctcoef level[64], dctcoef dct[64] ); int x264_zigzag_sub_4x4_frame_avx ( int16_t level[16], const uint8_t *src, uint8_t *dst ); int x264_zigzag_sub_4x4_frame_ssse3 ( int16_t level[16], const uint8_t *src, uint8_t *dst ); int x264_zigzag_sub_4x4ac_frame_avx ( int16_t level[16], const uint8_t *src, uint8_t *dst, int16_t *dc ); @@ -125,9 +135,10 @@ int x264_zigzag_sub_4x4_field_avx ( int16_t level[16], const uint8_t *src, u int x264_zigzag_sub_4x4_field_ssse3 ( int16_t level[16], const uint8_t *src, uint8_t *dst ); int x264_zigzag_sub_4x4ac_field_avx ( int16_t level[16], const uint8_t *src, uint8_t *dst, int16_t *dc ); int x264_zigzag_sub_4x4ac_field_ssse3( int16_t level[16], const uint8_t *src, uint8_t *dst, int16_t *dc ); -void x264_zigzag_interleave_8x8_cavlc_mmx ( int16_t *dst, int16_t *src, uint8_t *nnz ); -void x264_zigzag_interleave_8x8_cavlc_sse2( dctcoef *dst, dctcoef *src, uint8_t *nnz ); -void x264_zigzag_interleave_8x8_cavlc_avx ( dctcoef *dst, dctcoef *src, uint8_t *nnz ); -void x264_zigzag_interleave_8x8_cavlc_avx2( int16_t *dst, int16_t *src, uint8_t *nnz ); +void x264_zigzag_interleave_8x8_cavlc_mmx ( int16_t *dst, int16_t *src, uint8_t *nnz ); +void x264_zigzag_interleave_8x8_cavlc_sse2 ( dctcoef *dst, dctcoef *src, uint8_t *nnz ); +void x264_zigzag_interleave_8x8_cavlc_avx ( dctcoef *dst, dctcoef *src, uint8_t *nnz ); +void x264_zigzag_interleave_8x8_cavlc_avx2 ( int16_t *dst, int16_t *src, uint8_t *nnz ); +void x264_zigzag_interleave_8x8_cavlc_avx512( dctcoef *dst, dctcoef *src, uint8_t *nnz ); #endif diff --git a/library/src/main/cpp/libx264/common/x86/deblock-a.asm b/library/src/main/cpp/libx264/common/x86/deblock-a.asm index 9790fd2..917119b 100644 --- a/library/src/main/cpp/libx264/common/x86/deblock-a.asm +++ b/library/src/main/cpp/libx264/common/x86/deblock-a.asm @@ -28,10 +28,14 @@ %include "x86inc.asm" %include "x86util.asm" -SECTION_RODATA 32 - -load_bytes_shuf: times 2 db 3,4,5,6,11,12,13,14,4,5,6,7,12,13,14,15 -insert_top_shuf: dd 0,1,4,5,7,2,3,6 +SECTION_RODATA 64 + +load_bytes_zmm_shuf: dd 0x50404032, 0x70606053, 0xd0c0c0b4, 0xf0e0e0d5 + dd 0x50404036, 0x70606057, 0xd0c0c0b8, 0xf0e0e0d9 + dd 0x50104001, 0x70306023, 0xd090c083, 0xf0b0e0a5 + dd 0x50104005, 0x70306027, 0xd090c087, 0xf0b0e0a9 +load_bytes_ymm_shuf: dd 0x06050403, 0x0e0d0c1b, 0x07060544, 0x0f0e0d5c + dd 0x06050473, 0x0e0d0c2b, 0x07060534, 0x0f0e0d6c transpose_shuf: db 0,4,8,12,1,5,9,13,2,6,10,14,3,7,11,15 SECTION .text @@ -906,9 +910,8 @@ DEBLOCK_LUMA_INTRA movq m3, %4 punpcklwd m0, m2 punpcklwd m1, m3 - mova m2, m0 + punpckhdq m2, m0, m1 punpckldq m0, m1 - punpckhdq m2, m1 movq m4, %5 movq m6, %6 @@ -916,9 +919,8 @@ DEBLOCK_LUMA_INTRA movq m7, %8 punpcklwd m4, m6 punpcklwd m5, m7 - mova m6, m4 + punpckhdq m6, m4, m5 punpckldq m4, m5 - punpckhdq m6, m5 punpckhqdq m1, m0, m4 punpckhqdq m3, m2, m6 @@ -2278,13 +2280,10 @@ cglobal deblock_h_chroma_intra_mbaff, 4,6,8 RET %endif ; !HIGH_BIT_DEPTH - - ;----------------------------------------------------------------------------- ; static void deblock_strength( uint8_t nnz[48], int8_t ref[2][40], int16_t mv[2][40][2], ; uint8_t bs[2][4][4], int mvy_limit, int bframe ) ;----------------------------------------------------------------------------- - %define scan8start (4+1*8) %define nnz r0+scan8start %define ref r1+scan8start @@ -2292,145 +2291,54 @@ cglobal deblock_h_chroma_intra_mbaff, 4,6,8 %define bs0 r3 %define bs1 r3+32 -%macro LOAD_BYTES_MMX 1 - movd m2, [%1+8*0-1] - movd m0, [%1+8*0] - movd m3, [%1+8*2-1] - movd m1, [%1+8*2] - punpckldq m2, [%1+8*1-1] - punpckldq m0, [%1+8*1] - punpckldq m3, [%1+8*3-1] - punpckldq m1, [%1+8*3] -%endmacro - -%macro DEBLOCK_STRENGTH_REFS_MMX 0 - LOAD_BYTES_MMX ref - pxor m2, m0 - pxor m3, m1 - por m2, [bs0+0] - por m3, [bs0+8] - movq [bs0+0], m2 - movq [bs0+8], m3 - - movd m2, [ref-8*1] - movd m3, [ref+8*1] - punpckldq m2, m0 ; row -1, row 0 - punpckldq m3, m1 ; row 1, row 2 - pxor m0, m2 - pxor m1, m3 - por m0, [bs1+0] - por m1, [bs1+8] - movq [bs1+0], m0 - movq [bs1+8], m1 -%endmacro - -%macro DEBLOCK_STRENGTH_MVS_MMX 2 - mova m0, [mv-%2] - mova m1, [mv-%2+8] - psubw m0, [mv] - psubw m1, [mv+8] - packsswb m0, m1 - ABSB m0, m1 - psubusb m0, m7 - packsswb m0, m0 - por m0, [%1] - movd [%1], m0 -%endmacro - -%macro DEBLOCK_STRENGTH_NNZ_MMX 1 - por m2, m0 - por m3, m1 - mova m4, [%1] - mova m5, [%1+8] - pminub m2, m6 - pminub m3, m6 - pminub m4, m6 ; mv ? 1 : 0 - pminub m5, m6 - paddb m2, m2 ; nnz ? 2 : 0 - paddb m3, m3 - pmaxub m2, m4 - pmaxub m3, m5 -%endmacro - -%macro LOAD_BYTES_XMM 1 - movu m2, [%1-4] ; FIXME could be aligned if we changed nnz's allocation +%macro LOAD_BYTES_XMM 2 ; src, aligned +%if %2 + mova m2, [%1-4] + mova m1, [%1+12] +%else + movu m2, [%1-4] movu m1, [%1+12] - pslldq m0, m2, 1 +%endif + psllq m0, m2, 8 shufps m2, m1, q3131 ; cur nnz, all rows - pslldq m1, 1 + psllq m1, 8 shufps m0, m1, q3131 ; left neighbors +%if cpuflag(avx) || (%2 && cpuflag(ssse3)) + palignr m1, m2, [%1-20], 12 +%else pslldq m1, m2, 4 - movd m3, [%1-8] ; could be palignr if nnz was aligned + movd m3, [%1-8] por m1, m3 ; top neighbors +%endif %endmacro -INIT_MMX mmx2 -cglobal deblock_strength, 6,6 - ; Prepare mv comparison register - shl r4d, 8 - add r4d, 3 - (1<<8) - movd m7, r4d - SPLATW m7, m7 - mova m6, [pb_1] - pxor m0, m0 - mova [bs0+0], m0 - mova [bs0+8], m0 - mova [bs1+0], m0 - mova [bs1+8], m0 - -.lists: - DEBLOCK_STRENGTH_REFS_MMX - mov r4d, 4 -.mvs: - DEBLOCK_STRENGTH_MVS_MMX bs0, 4 - DEBLOCK_STRENGTH_MVS_MMX bs1, 4*8 - add r2, 4*8 - add r3, 4 - dec r4d - jg .mvs - add r1, 40 - add r2, 4*8 - sub r3, 16 - dec r5d - jge .lists - - ; Check nnz - LOAD_BYTES_MMX nnz - DEBLOCK_STRENGTH_NNZ_MMX bs0 - ; Transpose column output - SBUTTERFLY bw, 2, 3, 4 - SBUTTERFLY bw, 2, 3, 4 - mova [bs0+0], m2 - mova [bs0+8], m3 - movd m2, [nnz-8*1] - movd m3, [nnz+8*1] - punpckldq m2, m0 ; row -1, row 0 - punpckldq m3, m1 ; row 1, row 2 - DEBLOCK_STRENGTH_NNZ_MMX bs1 - mova [bs1+0], m2 - mova [bs1+8], m3 - RET +%if UNIX64 + DECLARE_REG_TMP 5 +%else + DECLARE_REG_TMP 4 +%endif %macro DEBLOCK_STRENGTH_XMM 0 -cglobal deblock_strength, 6,6,7 +cglobal deblock_strength, 5,5,7 ; Prepare mv comparison register shl r4d, 8 add r4d, 3 - (1<<8) movd m6, r4d + movifnidn t0d, r5m SPLATW m6, m6 pxor m4, m4 ; bs0 pxor m5, m5 ; bs1 .lists: ; Check refs - LOAD_BYTES_XMM ref + LOAD_BYTES_XMM ref, 0 pxor m0, m2 pxor m1, m2 por m4, m0 por m5, m1 ; Check mvs -%if cpuflag(ssse3) +%if cpuflag(ssse3) && notcpuflag(avx) mova m0, [mv+4*8*0] mova m1, [mv+4*8*1] palignr m3, m0, [mv+4*8*0-16], 12 @@ -2483,11 +2391,11 @@ cglobal deblock_strength, 6,6,7 por m5, m0 add r1, 40 add r2, 4*8*5 - dec r5d + dec t0d jge .lists ; Check nnz - LOAD_BYTES_XMM nnz + LOAD_BYTES_XMM nnz, 1 por m0, m2 por m1, m2 mova m6, [pb_1] @@ -2520,68 +2428,121 @@ INIT_XMM avx DEBLOCK_STRENGTH_XMM %macro LOAD_BYTES_YMM 1 - movu m0, [%1-4] ; ___E FGHI ___J KLMN ___O PQRS ___T UVWX - pshufb m0, [load_bytes_shuf] ; EFGH JKLM FGHI KLMN OPQR TUVW PQRS UVWX - mova m2, [insert_top_shuf] - vpermq m1, m0, q3131 ; FGHI KLMN PQRS UVWX x2 - vpermd m0, m2, m0 ; EFGH JKLM OPQR TUVW ____ FGHI KLMN PQRS - vpbroadcastd m2, [%1-8] ; ABCD .... - vpblendd m0, m0, m2, 00010000b ; EFGH JKLM OPQR TUVW ABCD FGHI KLMN PQRS + movu m0, [%1-4] ; ___E FGHI ___J KLMN ___O PQRS ___T UVWX + pshufb m0, m6 ; EFGH JKLM FGHI KLMN OPQR TUVW PQRS UVWX + vpermq m1, m0, q3131 ; FGHI KLMN PQRS UVWX x2 + vpbroadcastd m2, [%1-8] ; ABCD .... + vpblendd m0, m0, m2, 0x80 + vpermd m0, m7, m0 ; EFGH JKLM OPQR TUVW ABCD FGHI KLMN PQRS %endmacro INIT_YMM avx2 -cglobal deblock_strength, 6,6,7 +cglobal deblock_strength, 5,5,8 + mova m6, [load_bytes_ymm_shuf] ; Prepare mv comparison register - shl r4d, 8 - add r4d, 3 - (1<<8) - movd xm6, r4d - vpbroadcastw m6, xm6 - pxor m5, m5 ; bs0,bs1 + shl r4d, 8 + add r4d, 3 - (1<<8) + movd xm5, r4d + movifnidn t0d, r5m + vpbroadcastw m5, xm5 + psrld m7, m6, 4 + pxor m4, m4 ; bs0,bs1 .lists: ; Check refs LOAD_BYTES_YMM ref - pxor m0, m1 - por m5, m0 + pxor m0, m1 + por m4, m0 ; Check mvs - movu xm0, [mv-4+4*8*0] - vinserti128 m0, m0, [mv+4*8*-1], 1 - vbroadcasti128 m2, [mv+4*8* 0] - vinserti128 m1, m2, [mv-4+4*8*1], 0 - vbroadcasti128 m3, [mv+4*8* 1] - psubw m0, m2 - psubw m1, m3 - - vinserti128 m2, m3, [mv-4+4*8*2], 0 - vbroadcasti128 m4, [mv+4*8* 2] - vinserti128 m3, m4, [mv-4+4*8*3], 0 - psubw m2, m4 - vbroadcasti128 m4, [mv+4*8* 3] - psubw m3, m4 - packsswb m0, m1 - packsswb m2, m3 - pabsb m0, m0 - pabsb m2, m2 - psubusb m0, m6 - psubusb m2, m6 - packsswb m0, m2 - por m5, m0 - - add r1, 40 - add r2, 4*8*5 - dec r5d + movu xm0, [mv+0*4*8-4] + vinserti128 m0, m0, [mv-1*4*8 ], 1 + vbroadcasti128 m2, [mv+0*4*8 ] + vinserti128 m1, m2, [mv+1*4*8-4], 0 + psubw m0, m2 + vbroadcasti128 m2, [mv+1*4*8 ] + psubw m1, m2 + packsswb m0, m1 + vinserti128 m1, m2, [mv+2*4*8-4], 0 + vbroadcasti128 m3, [mv+2*4*8 ] + vinserti128 m2, m3, [mv+3*4*8-4], 0 + psubw m1, m3 + vbroadcasti128 m3, [mv+3*4*8 ] + psubw m2, m3 + packsswb m1, m2 + pabsb m0, m0 + pabsb m1, m1 + psubusb m0, m5 + psubusb m1, m5 + packsswb m0, m1 + por m4, m0 + add r1, 40 + add r2, 4*8*5 + dec t0d jge .lists ; Check nnz LOAD_BYTES_YMM nnz - por m0, m1 - mova m6, [pb_1] - pminub m0, m6 - pminub m5, m6 ; mv ? 1 : 0 - paddb m0, m0 ; nnz ? 2 : 0 - pmaxub m5, m0 - vextracti128 [bs1], m5, 1 - pshufb xm5, [transpose_shuf] - mova [bs0], xm5 + mova m2, [pb_1] + por m0, m1 + pminub m0, m2 + pminub m4, m2 ; mv ? 1 : 0 + paddb m0, m0 ; nnz ? 2 : 0 + pmaxub m0, m4 + vextracti128 [bs1], m0, 1 + pshufb xm0, [transpose_shuf] + mova [bs0], xm0 + RET + +%macro LOAD_BYTES_ZMM 1 + vpermd m1, m6, [%1-12] + pshufb m1, m7 ; EF FG GH HI JK KL LM MN OP PQ QR RS TU UV VW WX +%endmacro ; AF BG CH DI FK GL HM IN KP LQ MR NS PU QV RW SX + +INIT_ZMM avx512 +cglobal deblock_strength, 5,5 + mova m6, [load_bytes_zmm_shuf] + shl r4d, 8 + add r4d, 3 - (1<<8) + vpbroadcastw m5, r4d + mov r4d, 0x34cc34cc ; {1,-1} * 11001100b + kmovb k1, r4d + vpbroadcastd m4, r4d + movifnidn t0d, r5m + psrld m7, m6, 4 + pxor xm3, xm3 + +.lists: + vbroadcasti64x2 m2, [mv+32] + vinserti64x2 m0, m2, [mv-32], 2 + vbroadcasti64x2 m1, [mv+ 0] + vinserti64x2 m0, m0, [mv- 4], 0 + vbroadcasti64x2 m1 {k1}, [mv+64] + vinserti64x2 m0, m0, [mv+60], 1 + psubw m0, m1 + vinserti64x2 m1, m1, [mv+28], 0 + vbroadcasti64x2 m2 {k1}, [mv+96] + vinserti64x2 m1, m1, [mv+92], 1 + psubw m1, m2 + packsswb m0, m1 + pabsb m0, m0 + psubusb m0, m5 + + LOAD_BYTES_ZMM ref + pmaddubsw m1, m4 ; E-F F-G G-H H-I ... + vpternlogd m3, m0, m1, 0xfe ; m3 | m0 | m1 + add r1, 40 + add r2, 4*8*5 + dec t0d + jge .lists + + LOAD_BYTES_ZMM nnz + mova ym2, [pb_1] + vptestmw k1, m1, m1 + vptestmw k2, m3, m3 + vpaddb ym0 {k1}{z}, ym2, ym2 ; nnz ? 2 : 0 + vpmaxub ym0 {k2}, ym2 ; mv ? 1 : 0 + vextracti128 [bs1], ym0, 1 + pshufb xm0, [transpose_shuf] + mova [bs0], xm0 RET diff --git a/library/src/main/cpp/libx264/common/x86/mc-a.asm b/library/src/main/cpp/libx264/common/x86/mc-a.asm index f16f958..3c1d214 100644 --- a/library/src/main/cpp/libx264/common/x86/mc-a.asm +++ b/library/src/main/cpp/libx264/common/x86/mc-a.asm @@ -83,11 +83,11 @@ cextern deinterleave_shufd %endmacro %endif -%macro AVG_END 0 - lea t4, [t4+t5*2*SIZEOF_PIXEL] +%macro AVG_END 0-1 2 ; rows lea t2, [t2+t3*2*SIZEOF_PIXEL] + lea t4, [t4+t5*2*SIZEOF_PIXEL] lea t0, [t0+t1*2*SIZEOF_PIXEL] - sub eax, 2 + sub eax, %1 jg .height_loop RET %endmacro @@ -147,17 +147,24 @@ cextern deinterleave_shufd %endmacro %macro BIWEIGHT_START_SSSE3 0 - movzx t6d, byte r6m ; FIXME x86_64 - mov t7d, 64 - sub t7d, t6d - shl t7d, 8 - add t6d, t7d - mova m4, [pw_512] - movd xm3, t6d + movzx t6d, byte r6m ; FIXME x86_64 +%if mmsize > 16 + vbroadcasti128 m4, [pw_512] +%else + mova m4, [pw_512] +%endif + lea t7d, [t6+(64<<8)] + shl t6d, 8 + sub t7d, t6d +%if cpuflag(avx512) + vpbroadcastw m3, t7d +%else + movd xm3, t7d %if cpuflag(avx2) - vpbroadcastw m3, xm3 + vpbroadcastw m3, xm3 %else - SPLATW m3, m3 ; weight_dst,src + SPLATW m3, m3 ; weight_dst,src +%endif %endif %endmacro @@ -268,6 +275,66 @@ cglobal pixel_avg_weight_w16 mova [t0], xm0 vextracti128 [t0+t1], m0, 1 AVG_END + +INIT_YMM avx512 +cglobal pixel_avg_weight_w8 + BIWEIGHT_START + kxnorb k1, k1, k1 + kaddb k1, k1, k1 + AVG_START 5 +.height_loop: + movq xm0, [t2] + movq xm2, [t4] + movq xm1, [t2+t3] + movq xm5, [t4+t5] + lea t2, [t2+t3*2] + lea t4, [t4+t5*2] + vpbroadcastq m0 {k1}, [t2] + vpbroadcastq m2 {k1}, [t4] + vpbroadcastq m1 {k1}, [t2+t3] + vpbroadcastq m5 {k1}, [t4+t5] + punpcklbw m0, m2 + punpcklbw m1, m5 + pmaddubsw m0, m3 + pmaddubsw m1, m3 + pmulhrsw m0, m4 + pmulhrsw m1, m4 + packuswb m0, m1 + vextracti128 xmm1, m0, 1 + movq [t0], xm0 + movhps [t0+t1], xm0 + lea t0, [t0+t1*2] + movq [t0], xmm1 + movhps [t0+t1], xmm1 + AVG_END 4 + +INIT_ZMM avx512 +cglobal pixel_avg_weight_w16 + BIWEIGHT_START + AVG_START 5 +.height_loop: + movu xm0, [t2] + movu xm1, [t4] + vinserti128 ym0, [t2+t3], 1 + vinserti128 ym1, [t4+t5], 1 + lea t2, [t2+t3*2] + lea t4, [t4+t5*2] + vinserti32x4 m0, [t2], 2 + vinserti32x4 m1, [t4], 2 + vinserti32x4 m0, [t2+t3], 3 + vinserti32x4 m1, [t4+t5], 3 + SBUTTERFLY bw, 0, 1, 2 + pmaddubsw m0, m3 + pmaddubsw m1, m3 + pmulhrsw m0, m4 + pmulhrsw m1, m4 + packuswb m0, m1 + mova [t0], xm0 + vextracti128 [t0+t1], ym0, 1 + lea t0, [t0+t1*2] + vextracti32x4 [t0], m0, 2 + vextracti32x4 [t0+t1], m0, 3 + AVG_END 4 %endif ;HIGH_BIT_DEPTH ;============================================================================= @@ -738,6 +805,12 @@ INIT_XMM avx2 AVG_FUNC 16, movdqu, movdqa AVGH 16, 16 AVGH 16, 8 +INIT_XMM avx512 +AVGH 16, 16 +AVGH 16, 8 +AVGH 8, 16 +AVGH 8, 8 +AVGH 8, 4 %endif ;HIGH_BIT_DEPTH @@ -2125,7 +2198,7 @@ INIT_XMM sse2 MC_CHROMA INIT_XMM ssse3 MC_CHROMA_SSSE3 -INIT_XMM ssse3, cache64 +INIT_XMM cache64, ssse3 MC_CHROMA_SSSE3 INIT_XMM avx MC_CHROMA_SSSE3 ; No known AVX CPU will trigger CPU_CACHELINE_64 diff --git a/library/src/main/cpp/libx264/common/x86/mc-a2.asm b/library/src/main/cpp/libx264/common/x86/mc-a2.asm index 2e72b61..e93cfcc 100644 --- a/library/src/main/cpp/libx264/common/x86/mc-a2.asm +++ b/library/src/main/cpp/libx264/common/x86/mc-a2.asm @@ -30,18 +30,15 @@ %include "x86inc.asm" %include "x86util.asm" -SECTION_RODATA 32 - -pw_1024: times 16 dw 1024 -filt_mul20: times 32 db 20 -filt_mul15: times 16 db 1, -5 -filt_mul51: times 16 db -5, 1 -hpel_shuf: times 2 db 0,8,1,9,2,10,3,11,4,12,5,13,6,14,7,15 +SECTION_RODATA 64 %if HIGH_BIT_DEPTH -v210_mask: times 4 dq 0xc00ffc003ff003ff -v210_luma_shuf: times 2 db 1,2,4,5,6,7,9,10,12,13,14,15,12,13,14,15 -v210_chroma_shuf: times 2 db 0,1,2,3,5,6,8,9,10,11,13,14,10,11,13,14 +v210_shuf_avx512: db 0, 0,34, 1,35,34, 4, 4,38, 5,39,38, 8, 8,42, 9, ; luma, chroma + db 43,42,12,12,46,13,47,46,16,16,50,17,51,50,20,20, + db 54,21,55,54,24,24,58,25,59,58,28,28,62,29,63,62 +v210_mask: dd 0x3ff003ff, 0xc00ffc00, 0x3ff003ff, 0xc00ffc00 +v210_luma_shuf: db 1, 2, 4, 5, 6, 7, 9,10,12,13,14,15,12,13,14,15 +v210_chroma_shuf: db 0, 1, 2, 3, 5, 6, 8, 9,10,11,13,14,10,11,13,14 ; vpermd indices {0,1,2,4,5,7,_,_} merged in the 3 lsb of each dword to save a register v210_mult: dw 0x2000,0x7fff,0x0801,0x2000,0x7ffa,0x0800,0x7ffc,0x0800 dw 0x1ffd,0x7fff,0x07ff,0x2000,0x7fff,0x0800,0x7fff,0x0800 @@ -58,6 +55,13 @@ deinterleave_shuf32a: db 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30 deinterleave_shuf32b: db 1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31 %endif ; !HIGH_BIT_DEPTH +pw_1024: times 16 dw 1024 +filt_mul20: times 32 db 20 +filt_mul15: times 16 db 1, -5 +filt_mul51: times 16 db -5, 1 +hpel_shuf: times 2 db 0,8,1,9,2,10,3,11,4,12,5,13,6,14,7,15 + +mbtree_prop_list_avx512_shuf: dw 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7 mbtree_fix8_unpack_shuf: db -1,-1, 1, 0,-1,-1, 3, 2,-1,-1, 5, 4,-1,-1, 7, 6 db -1,-1, 9, 8,-1,-1,11,10,-1,-1,13,12,-1,-1,15,14 mbtree_fix8_pack_shuf: db 1, 0, 3, 2, 5, 4, 7, 6, 9, 8,11,10,13,12,15,14 @@ -1044,8 +1048,8 @@ PLANE_COPY_CORE 1 %endif ; HIGH_BIT_DEPTH %endmacro -%macro DEINTERLEAVE 6 ; dstu, dstv, src, dstv==dstu+8, shuffle constant, is aligned - mova m0, [%3] +%macro DEINTERLEAVE 6 ; dsta, dstb, src, dsta==dstb+8, shuffle constant, is aligned + mov%6 m0, [%3] %if mmsize == 32 pshufb m0, %5 vpermq m0, m0, q3120 @@ -1056,7 +1060,7 @@ PLANE_COPY_CORE 1 vextracti128 [%2], m0, 1 %endif %elif HIGH_BIT_DEPTH - mova m1, [%3+mmsize] + mov%6 m1, [%3+mmsize] psrld m2, m0, 16 psrld m3, m1, 16 pand m0, %5 @@ -1181,8 +1185,8 @@ cglobal store_interleave_chroma, 5,5 %macro PLANE_DEINTERLEAVE 0 ;----------------------------------------------------------------------------- -; void plane_copy_deinterleave( pixel *dstu, intptr_t i_dstu, -; pixel *dstv, intptr_t i_dstv, +; void plane_copy_deinterleave( pixel *dsta, intptr_t i_dsta, +; pixel *dstb, intptr_t i_dstb, ; pixel *src, intptr_t i_src, int w, int h ) ;----------------------------------------------------------------------------- %if ARCH_X86_64 @@ -1400,43 +1404,64 @@ cglobal plane_copy_deinterleave_v210, 7,7,7 %define org_w r6m %define h dword r7m %endif - FIX_STRIDES r1, r3, r6d - shl r5, 2 - add r0, r6 - add r2, r6 - neg r6 - mov src, r4 - mov org_w, r6 - mova m2, [v210_mask] - mova m3, [v210_luma_shuf] - mova m4, [v210_chroma_shuf] - mova m5, [v210_mult] ; also functions as vpermd index for avx2 - pshufd m6, m5, q1102 - + FIX_STRIDES r1, r3, r6d + shl r5, 2 + add r0, r6 + add r2, r6 + neg r6 + mov src, r4 + mov org_w, r6 +%if cpuflag(avx512) + vpbroadcastd m2, [v210_mask] + vpbroadcastd m3, [v210_shuf_avx512] + psrlw m3, 6 ; dw 0, 4 + mova m4, [v210_shuf_avx512] ; luma + psrlw m5, m4, 8 ; chroma +%else +%if mmsize == 32 + vbroadcasti128 m2, [v210_mask] + vbroadcasti128 m3, [v210_luma_shuf] + vbroadcasti128 m4, [v210_chroma_shuf] +%else + mova m2, [v210_mask] + mova m3, [v210_luma_shuf] + mova m4, [v210_chroma_shuf] +%endif + mova m5, [v210_mult] ; also functions as vpermd index for avx2 + pshufd m6, m5, q1102 +%endif ALIGN 16 .loop: - movu m1, [r4] - pandn m0, m2, m1 - pand m1, m2 - pshufb m0, m3 - pshufb m1, m4 - pmulhrsw m0, m5 ; y0 y1 y2 y3 y4 y5 __ __ - pmulhrsw m1, m6 ; u0 v0 u1 v1 u2 v2 __ __ + movu m1, [r4] + pandn m0, m2, m1 + pand m1, m2 +%if cpuflag(avx512) + psrld m0, 10 + vpsrlvw m1, m3 + mova m6, m0 + vpermt2w m0, m4, m1 + vpermt2w m1, m5, m6 +%else + pshufb m0, m3 + pshufb m1, m4 + pmulhrsw m0, m5 ; y0 y1 y2 y3 y4 y5 __ __ + pmulhrsw m1, m6 ; u0 v0 u1 v1 u2 v2 __ __ %if mmsize == 32 - vpermd m0, m5, m0 - vpermd m1, m5, m1 + vpermd m0, m5, m0 + vpermd m1, m5, m1 +%endif %endif - movu [r0+r6], m0 - movu [r2+r6], m1 - add r4, mmsize - add r6, 3*mmsize/4 + movu [r0+r6], m0 + movu [r2+r6], m1 + add r4, mmsize + add r6, mmsize*3/4 jl .loop - add r0, r1 - add r2, r3 - add src, r5 - mov r4, src - mov r6, org_w - dec h + add r0, r1 + add r2, r3 + add src, r5 + mov r4, src + mov r6, org_w + dec h jg .loop RET %endmacro ; PLANE_DEINTERLEAVE_V210 @@ -1461,6 +1486,8 @@ PLANE_DEINTERLEAVE_V210 INIT_YMM avx2 LOAD_DEINTERLEAVE_CHROMA PLANE_DEINTERLEAVE_V210 +INIT_ZMM avx512 +PLANE_DEINTERLEAVE_V210 %else INIT_XMM sse2 PLANE_DEINTERLEAVE_RGB @@ -1473,82 +1500,85 @@ LOAD_DEINTERLEAVE_CHROMA_FENC_AVX2 PLANE_DEINTERLEAVE_RGB %endif -; These functions are not general-use; not only do the SSE ones require aligned input, -; but they also will fail if given a non-mod16 size. -; memzero SSE will fail for non-mod128. +; These functions are not general-use; not only do they require aligned input, but memcpy +; requires size to be a multiple of 16 and memzero requires size to be a multiple of 128. ;----------------------------------------------------------------------------- ; void *memcpy_aligned( void *dst, const void *src, size_t n ); ;----------------------------------------------------------------------------- %macro MEMCPY 0 cglobal memcpy_aligned, 3,3 -%if mmsize == 16 +%if mmsize == 32 test r2d, 16 - jz .copy2 - mova m0, [r1+r2-16] - mova [r0+r2-16], m0 + jz .copy32 + mova xm0, [r1+r2-16] + mova [r0+r2-16], xm0 sub r2d, 16 -.copy2: -%endif - test r2d, 2*mmsize - jz .copy4start + jle .ret +.copy32: +%endif + test r2d, mmsize + jz .loop + mova m0, [r1+r2-mmsize] + mova [r0+r2-mmsize], m0 + sub r2d, mmsize + jle .ret +.loop: mova m0, [r1+r2-1*mmsize] mova m1, [r1+r2-2*mmsize] mova [r0+r2-1*mmsize], m0 mova [r0+r2-2*mmsize], m1 sub r2d, 2*mmsize -.copy4start: - test r2d, r2d - jz .ret -.copy4: - mova m0, [r1+r2-1*mmsize] - mova m1, [r1+r2-2*mmsize] - mova m2, [r1+r2-3*mmsize] - mova m3, [r1+r2-4*mmsize] - mova [r0+r2-1*mmsize], m0 - mova [r0+r2-2*mmsize], m1 - mova [r0+r2-3*mmsize], m2 - mova [r0+r2-4*mmsize], m3 - sub r2d, 4*mmsize - jg .copy4 + jg .loop .ret: - REP_RET + RET %endmacro -INIT_MMX mmx -MEMCPY -INIT_XMM sse -MEMCPY - ;----------------------------------------------------------------------------- ; void *memzero_aligned( void *dst, size_t n ); ;----------------------------------------------------------------------------- -%macro MEMZERO 1 +%macro MEMZERO 0 cglobal memzero_aligned, 2,2 - add r0, r1 - neg r1 -%if mmsize == 8 - pxor m0, m0 -%else xorps m0, m0 -%endif .loop: -%assign i 0 -%rep %1 - mova [r0 + r1 + i], m0 -%assign i i+mmsize +%assign %%i mmsize +%rep 128 / mmsize + movaps [r0 + r1 - %%i], m0 +%assign %%i %%i+mmsize %endrep - add r1, mmsize*%1 - jl .loop + sub r1d, 128 + jg .loop RET %endmacro -INIT_MMX mmx -MEMZERO 8 INIT_XMM sse -MEMZERO 8 +MEMCPY +MEMZERO INIT_YMM avx -MEMZERO 4 +MEMCPY +MEMZERO +INIT_ZMM avx512 +MEMZERO + +cglobal memcpy_aligned, 3,4 + dec r2d ; offset of the last byte + rorx r3d, r2d, 2 + and r2d, ~63 + and r3d, 15 ; n = number of dwords minus one to copy in the tail + mova m0, [r1+r2] + not r3d ; bits 0-4: (n^15)+16, bits 16-31: 0xffff + shrx r3d, r3d, r3d ; 0xffff >> (n^15) + kmovw k1, r3d ; (1 << (n+1)) - 1 + vmovdqa32 [r0+r2] {k1}, m0 + sub r2d, 64 + jl .ret +.loop: + mova m0, [r1+r2] + mova [r0+r2], m0 + sub r2d, 64 + jge .loop +.ret: + RET %if HIGH_BIT_DEPTH == 0 ;----------------------------------------------------------------------------- @@ -2147,13 +2177,13 @@ MBTREE cglobal mbtree_propagate_cost, 6,6,8-2*cpuflag(avx2) vbroadcastss m5, [r5] mov r5d, r6m - lea r0, [r0+r5*2] + lea r2, [r2+r5*2] add r5d, r5d - add r1, r5 - add r2, r5 - add r3, r5 add r4, r5 neg r5 + sub r1, r5 + sub r3, r5 + sub r0, r5 mova xm4, [pw_3fff] %if notcpuflag(avx2) pxor xm7, xm7 @@ -2165,9 +2195,8 @@ cglobal mbtree_propagate_cost, 6,6,8-2*cpuflag(avx2) pmovzxwd m2, [r1+r5] ; prop pand xm3, xm4, [r3+r5] ; inter pmovzxwd m3, xm3 - pminsd m3, m0 pmaddwd m1, m0 - psubd m3, m0, m3 + psubusw m3, m0, m3 cvtdq2ps m0, m0 cvtdq2ps m1, m1 cvtdq2ps m2, m2 @@ -2184,7 +2213,7 @@ cglobal mbtree_propagate_cost, 6,6,8-2*cpuflag(avx2) movu xm1, [r4+r5] movu xm2, [r1+r5] pand xm3, xm4, [r3+r5] - pminsw xm3, xm0 + psubusw xm3, xm0, xm3 INT16_UNPACK 0 INT16_UNPACK 1 INT16_UNPACK 2 @@ -2194,7 +2223,6 @@ cglobal mbtree_propagate_cost, 6,6,8-2*cpuflag(avx2) cvtdq2ps m2, m2 cvtdq2ps m3, m3 mulps m1, m0 - subps m3, m0, m3 mulps m1, m5 ; intra*invq*fps_factor>>8 addps m1, m2 ; prop + (intra*invq*fps_factor>>8) rcpps m2, m0 ; 1 / intra 1st approximation @@ -2205,7 +2233,7 @@ cglobal mbtree_propagate_cost, 6,6,8-2*cpuflag(avx2) subps m2, m0 ; 2nd approximation for 1/intra mulps m1, m2 ; / intra %endif - vcvtps2dq m1, m1 + cvtps2dq m1, m1 vextractf128 xm2, m1, 1 packssdw xm1, xm2 mova [r0+r5], xm1 @@ -2219,6 +2247,39 @@ MBTREE_AVX INIT_YMM avx2 MBTREE_AVX +INIT_ZMM avx512 +cglobal mbtree_propagate_cost, 6,6 + vbroadcastss m5, [r5] + mov r5d, 0x3fff3fff + vpbroadcastd ym4, r5d + mov r5d, r6m + lea r2, [r2+r5*2] + add r5d, r5d + add r1, r5 + neg r5 + sub r4, r5 + sub r3, r5 + sub r0, r5 +.loop: + pmovzxwd m0, [r2+r5] ; intra + pmovzxwd m1, [r1+r5] ; prop + pmovzxwd m2, [r4+r5] ; invq + pand ym3, ym4, [r3+r5] ; inter + pmovzxwd m3, ym3 + psubusw m3, m0, m3 + cvtdq2ps m0, m0 + cvtdq2ps m1, m1 + cvtdq2ps m2, m2 + cvtdq2ps m3, m3 + vdivps m1, m0, {rn-sae} + fmaddps m1, m2, m5, m1 + mulps m1, m3 + cvtps2dq m1, m1 + vpmovsdw [r0+r5], m1 + add r5, 32 + jl .loop + RET + %macro MBTREE_PROPAGATE_LIST 0 ;----------------------------------------------------------------------------- ; void mbtree_propagate_list_internal( int16_t (*mvs)[2], int16_t *propagate_amount, uint16_t *lowres_costs, @@ -2372,6 +2433,112 @@ cglobal mbtree_propagate_list_internal, 4+2*UNIX64,5+UNIX64,8 jl .loop RET +%if ARCH_X86_64 +;----------------------------------------------------------------------------- +; void x264_mbtree_propagate_list_internal_avx512( size_t len, uint16_t *ref_costs, int16_t (*mvs)[2], int16_t *propagate_amount, +; uint16_t *lowres_costs, int bipred_weight, int mb_y, +; int width, int height, int stride, int list_mask ); +;----------------------------------------------------------------------------- +INIT_ZMM avx512 +cglobal mbtree_propagate_list_internal, 5,7,21 + mova xm16, [pw_0xc000] + vpbroadcastw xm17, r5m ; bipred_weight << 9 + vpbroadcastw ym18, r10m ; 1 << (list+LOWRES_COST_SHIFT) + vbroadcasti32x8 m5, [mbtree_prop_list_avx512_shuf] + vbroadcasti32x8 m6, [pd_0123] + vpord m6, r6m {1to16} ; 0 y 1 y 2 y 3 y 4 y 5 y 6 y 7 y + vbroadcasti128 m7, [pd_8] + vbroadcasti128 m8, [pw_31] + vbroadcasti128 m9, [pw_32] + psllw m10, m9, 4 + pcmpeqw ym19, ym19 ; pw_m1 + vpbroadcastw ym20, r7m ; width + psrld m11, m7, 3 ; pd_1 + psrld m12, m8, 16 ; pd_31 + vpbroadcastd m13, r8m ; height + vpbroadcastd m14, r9m ; stride + pslld m15, m14, 16 + por m15, m11 ; {1, stride, 1, stride} ... + lea r4, [r4+2*r0] ; lowres_costs + lea r3, [r3+2*r0] ; propagate_amount + lea r2, [r2+4*r0] ; mvs + neg r0 + mov r6d, 0x5555ffff + kmovd k4, r6d + kshiftrd k5, k4, 16 ; 0x5555 + kshiftlw k6, k4, 8 ; 0xff00 +.loop: + vbroadcasti128 ym1, [r4+2*r0] + mova xm4, [r3+2*r0] + vpcmpuw k1, xm1, xm16, 5 ; if (lists_used == 3) + vpmulhrsw xm4 {k1}, xm17 ; propagate_amount = (propagate_amount * bipred_weight + 32) >> 6 + vptestmw k1, ym1, ym18 + vpermw m4, m5, m4 + + vbroadcasti32x8 m3, [r2+4*r0] ; {mvx, mvy} + psraw m0, m3, 5 + paddw m0, m6 ; {mbx, mby} = ({x, y} >> 5) + {h->mb.i_mb_x, h->mb.i_mb_y} + paddd m6, m7 ; i_mb_x += 8 + pand m3, m8 ; {x, y} + vprold m1, m3, 20 ; {y, x} << 4 + psubw m3 {k4}, m9, m3 ; {32-x, 32-y}, {32-x, y} + psubw m1 {k5}, m10, m1 ; ({32-y, x}, {y, x}) << 4 + pmullw m3, m1 + paddsw m3, m3 ; prevent signed overflow in idx0 (32*32<<5 == 0x8000) + pmulhrsw m2, m3, m4 ; idx01weight idx23weightp + + pslld ym1, ym0, 16 + psubw ym1, ym19 + vmovdqu16 ym1 {k5}, ym0 + vpcmpuw k2, ym1, ym20, 1 ; {mbx, mbx+1} < width + kunpckwd k2, k2, k2 + psrad m1, m0, 16 + paddd m1 {k6}, m11 + vpcmpud k1 {k1}, m1, m13, 1 ; mby < height | mby+1 < height + + pmaddwd m0, m15 + paddd m0 {k6}, m14 ; idx0 | idx2 + vmovdqu16 m2 {k2}{z}, m2 ; idx01weight | idx23weight + vptestmd k1 {k1}, m2, m2 ; mask out offsets with no changes + + ; We're handling dwords, but the offsets are in words so there may be partial overlaps. + ; We can work around this by handling dword-aligned and -unaligned offsets separately. + vptestmd k0, m0, m11 + kandnw k2, k0, k1 ; dword-aligned offsets + kmovw k3, k2 + vpgatherdd m3 {k2}, [r1+2*m0] + + ; If there are conflicts in the offsets we have to handle them before storing the results. + ; By creating a permutation index using vplzcntd we can resolve all conflicts in parallel + ; in ceil(log2(n)) iterations where n is the largest number of duplicate offsets. + vpconflictd m4, m0 + vpbroadcastmw2d m1, k1 + vptestmd k2, m1, m4 + ktestw k2, k2 + jz .no_conflicts + pand m1, m4 ; mask away unused offsets to avoid false positives + vplzcntd m1, m1 + pxor m1, m12 ; lzcnt gives us the distance from the msb, we want it from the lsb +.conflict_loop: + vpermd m4 {k2}{z}, m1, m2 + vpermd m1 {k2}, m1, m1 ; shift the index one step forward + paddsw m2, m4 ; add the weights of conflicting offsets + vpcmpd k2, m1, m12, 2 + ktestw k2, k2 + jnz .conflict_loop +.no_conflicts: + paddsw m3, m2 + vpscatterdd [r1+2*m0] {k3}, m3 + kandw k1, k0, k1 ; dword-unaligned offsets + kmovw k2, k1 + vpgatherdd m1 {k1}, [r1+2*m0] + paddsw m1, m2 ; all conflicts have already been resolved + vpscatterdd [r1+2*m0] {k2}, m1 + add r0, 8 + jl .loop + RET +%endif + %macro MBTREE_FIX8 0 ;----------------------------------------------------------------------------- ; void mbtree_fix8_pack( uint16_t *dst, float *src, int count ) diff --git a/library/src/main/cpp/libx264/common/x86/mc-c.c b/library/src/main/cpp/libx264/common/x86/mc-c.c index 3258381..c06691c 100644 --- a/library/src/main/cpp/libx264/common/x86/mc-c.c +++ b/library/src/main/cpp/libx264/common/x86/mc-c.c @@ -32,7 +32,8 @@ void func##_mmx2 args;\ void func##_sse2 args;\ void func##_ssse3 args;\ - void func##_avx2 args; + void func##_avx2 args;\ + void func##_avx512 args; DECL_SUF( x264_pixel_avg_16x16, ( pixel *, intptr_t, pixel *, intptr_t, pixel *, intptr_t, int )) DECL_SUF( x264_pixel_avg_16x8, ( pixel *, intptr_t, pixel *, intptr_t, pixel *, intptr_t, int )) @@ -99,17 +100,17 @@ void x264_plane_copy_interleave_core_sse2( pixel *dst, intptr_t i_dst, void x264_plane_copy_interleave_core_avx( pixel *dst, intptr_t i_dst, pixel *srcu, intptr_t i_srcu, pixel *srcv, intptr_t i_srcv, int w, int h ); -void x264_plane_copy_deinterleave_sse2( pixel *dstu, intptr_t i_dstu, - pixel *dstv, intptr_t i_dstv, +void x264_plane_copy_deinterleave_sse2( pixel *dsta, intptr_t i_dsta, + pixel *dstb, intptr_t i_dstb, pixel *src, intptr_t i_src, int w, int h ); -void x264_plane_copy_deinterleave_ssse3( uint8_t *dstu, intptr_t i_dstu, - uint8_t *dstv, intptr_t i_dstv, +void x264_plane_copy_deinterleave_ssse3( uint8_t *dsta, intptr_t i_dsta, + uint8_t *dstb, intptr_t i_dstb, uint8_t *src, intptr_t i_src, int w, int h ); -void x264_plane_copy_deinterleave_avx( uint16_t *dstu, intptr_t i_dstu, - uint16_t *dstv, intptr_t i_dstv, +void x264_plane_copy_deinterleave_avx( uint16_t *dsta, intptr_t i_dsta, + uint16_t *dstb, intptr_t i_dstb, uint16_t *src, intptr_t i_src, int w, int h ); -void x264_plane_copy_deinterleave_avx2( pixel *dstu, intptr_t i_dstu, - pixel *dstv, intptr_t i_dstv, +void x264_plane_copy_deinterleave_avx2( pixel *dsta, intptr_t i_dsta, + pixel *dstb, intptr_t i_dstb, pixel *src, intptr_t i_src, int w, int h ); void x264_plane_copy_deinterleave_rgb_sse2 ( pixel *dsta, intptr_t i_dsta, pixel *dstb, intptr_t i_dstb, @@ -123,15 +124,18 @@ void x264_plane_copy_deinterleave_rgb_avx2 ( pixel *dsta, intptr_t i_dsta, pixel *dstb, intptr_t i_dstb, pixel *dstc, intptr_t i_dstc, pixel *src, intptr_t i_src, int pw, int w, int h ); -void x264_plane_copy_deinterleave_v210_ssse3( uint16_t *dstu, intptr_t i_dstu, - uint16_t *dstv, intptr_t i_dstv, - uint32_t *src, intptr_t i_src, int w, int h ); -void x264_plane_copy_deinterleave_v210_avx ( uint16_t *dstu, intptr_t i_dstu, - uint16_t *dstv, intptr_t i_dstv, - uint32_t *src, intptr_t i_src, int w, int h ); -void x264_plane_copy_deinterleave_v210_avx2 ( uint16_t *dstu, intptr_t i_dstu, - uint16_t *dstv, intptr_t i_dstv, - uint32_t *src, intptr_t i_src, int w, int h ); +void x264_plane_copy_deinterleave_v210_ssse3 ( uint16_t *dstu, intptr_t i_dstu, + uint16_t *dstv, intptr_t i_dstv, + uint32_t *src, intptr_t i_src, int w, int h ); +void x264_plane_copy_deinterleave_v210_avx ( uint16_t *dstu, intptr_t i_dstu, + uint16_t *dstv, intptr_t i_dstv, + uint32_t *src, intptr_t i_src, int w, int h ); +void x264_plane_copy_deinterleave_v210_avx2 ( uint16_t *dstu, intptr_t i_dstu, + uint16_t *dstv, intptr_t i_dstv, + uint32_t *src, intptr_t i_src, int w, int h ); +void x264_plane_copy_deinterleave_v210_avx512( uint16_t *dstu, intptr_t i_dstu, + uint16_t *dstv, intptr_t i_dstv, + uint32_t *src, intptr_t i_src, int w, int h ); void x264_store_interleave_chroma_mmx2( pixel *dst, intptr_t i_dst, pixel *srcu, pixel *srcv, int height ); void x264_store_interleave_chroma_sse2( pixel *dst, intptr_t i_dst, pixel *srcu, pixel *srcv, int height ); void x264_store_interleave_chroma_avx ( pixel *dst, intptr_t i_dst, pixel *srcu, pixel *srcv, int height ); @@ -143,11 +147,12 @@ void x264_load_deinterleave_chroma_fdec_sse2( pixel *dst, pixel *src, intptr_t i void x264_load_deinterleave_chroma_fdec_ssse3( uint8_t *dst, uint8_t *src, intptr_t i_src, int height ); void x264_load_deinterleave_chroma_fdec_avx( uint16_t *dst, uint16_t *src, intptr_t i_src, int height ); void x264_load_deinterleave_chroma_fdec_avx2( uint16_t *dst, uint16_t *src, intptr_t i_src, int height ); -void *x264_memcpy_aligned_mmx( void *dst, const void *src, size_t n ); -void *x264_memcpy_aligned_sse( void *dst, const void *src, size_t n ); -void x264_memzero_aligned_mmx( void *dst, size_t n ); -void x264_memzero_aligned_sse( void *dst, size_t n ); -void x264_memzero_aligned_avx( void *dst, size_t n ); +void *x264_memcpy_aligned_sse ( void *dst, const void *src, size_t n ); +void *x264_memcpy_aligned_avx ( void *dst, const void *src, size_t n ); +void *x264_memcpy_aligned_avx512( void *dst, const void *src, size_t n ); +void x264_memzero_aligned_sse ( void *dst, size_t n ); +void x264_memzero_aligned_avx ( void *dst, size_t n ); +void x264_memzero_aligned_avx512( void *dst, size_t n ); void x264_integral_init4h_sse4( uint16_t *sum, uint8_t *pix, intptr_t stride ); void x264_integral_init4h_avx2( uint16_t *sum, uint8_t *pix, intptr_t stride ); void x264_integral_init8h_sse4( uint16_t *sum, uint8_t *pix, intptr_t stride ); @@ -160,14 +165,16 @@ void x264_integral_init4v_avx2( uint16_t *sum8, uint16_t *sum4, intptr_t stride void x264_integral_init8v_mmx ( uint16_t *sum8, intptr_t stride ); void x264_integral_init8v_sse2( uint16_t *sum8, intptr_t stride ); void x264_integral_init8v_avx2( uint16_t *sum8, intptr_t stride ); -void x264_mbtree_propagate_cost_sse2( int16_t *dst, uint16_t *propagate_in, uint16_t *intra_costs, - uint16_t *inter_costs, uint16_t *inv_qscales, float *fps_factor, int len ); -void x264_mbtree_propagate_cost_avx ( int16_t *dst, uint16_t *propagate_in, uint16_t *intra_costs, - uint16_t *inter_costs, uint16_t *inv_qscales, float *fps_factor, int len ); -void x264_mbtree_propagate_cost_fma4( int16_t *dst, uint16_t *propagate_in, uint16_t *intra_costs, - uint16_t *inter_costs, uint16_t *inv_qscales, float *fps_factor, int len ); -void x264_mbtree_propagate_cost_avx2( int16_t *dst, uint16_t *propagate_in, uint16_t *intra_costs, - uint16_t *inter_costs, uint16_t *inv_qscales, float *fps_factor, int len ); +void x264_mbtree_propagate_cost_sse2 ( int16_t *dst, uint16_t *propagate_in, uint16_t *intra_costs, + uint16_t *inter_costs, uint16_t *inv_qscales, float *fps_factor, int len ); +void x264_mbtree_propagate_cost_avx ( int16_t *dst, uint16_t *propagate_in, uint16_t *intra_costs, + uint16_t *inter_costs, uint16_t *inv_qscales, float *fps_factor, int len ); +void x264_mbtree_propagate_cost_fma4 ( int16_t *dst, uint16_t *propagate_in, uint16_t *intra_costs, + uint16_t *inter_costs, uint16_t *inv_qscales, float *fps_factor, int len ); +void x264_mbtree_propagate_cost_avx2 ( int16_t *dst, uint16_t *propagate_in, uint16_t *intra_costs, + uint16_t *inter_costs, uint16_t *inv_qscales, float *fps_factor, int len ); +void x264_mbtree_propagate_cost_avx512( int16_t *dst, uint16_t *propagate_in, uint16_t *intra_costs, + uint16_t *inter_costs, uint16_t *inv_qscales, float *fps_factor, int len ); void x264_mbtree_fix8_pack_ssse3( uint16_t *dst, float *src, int count ); void x264_mbtree_fix8_pack_avx2 ( uint16_t *dst, float *src, int count ); void x264_mbtree_fix8_unpack_ssse3( float *dst, uint16_t *src, int count ); @@ -179,7 +186,7 @@ void x264_mc_chroma_##cpu( pixel *dstu, pixel *dstv, intptr_t i_dst, pixel *src, MC_CHROMA(mmx2) MC_CHROMA(sse2) MC_CHROMA(ssse3) -MC_CHROMA(ssse3_cache64) +MC_CHROMA(cache64_ssse3) MC_CHROMA(avx) MC_CHROMA(avx2) @@ -498,6 +505,15 @@ PLANE_COPY(32, avx) PLANE_COPY_SWAP(16, ssse3) PLANE_COPY_SWAP(32, avx2) +#if HIGH_BIT_DEPTH +PLANE_COPY_YUYV(64, sse2) +PLANE_COPY_YUYV(64, avx) +#else +PLANE_COPY_YUYV(32, sse2) +PLANE_COPY_YUYV(32, ssse3) +#endif +PLANE_COPY_YUYV(64, avx2) + PLANE_INTERLEAVE(mmx2) PLANE_INTERLEAVE(sse2) #if HIGH_BIT_DEPTH @@ -538,6 +554,21 @@ PROPAGATE_LIST(ssse3) PROPAGATE_LIST(avx) PROPAGATE_LIST(avx2) +#if ARCH_X86_64 +void x264_mbtree_propagate_list_internal_avx512( size_t len, uint16_t *ref_costs, int16_t (*mvs)[2], int16_t *propagate_amount, + uint16_t *lowres_costs, int bipred_weight, int mb_y, + int width, int height, int stride, int list_mask ); + +static void x264_mbtree_propagate_list_avx512( x264_t *h, uint16_t *ref_costs, int16_t (*mvs)[2], + int16_t *propagate_amount, uint16_t *lowres_costs, + int bipred_weight, int mb_y, int len, int list ) +{ + x264_mbtree_propagate_list_internal_avx512( len, ref_costs, mvs, propagate_amount, lowres_costs, bipred_weight << 9, + mb_y << 16, h->mb.i_mb_width, h->mb.i_mb_height, h->mb.i_mb_stride, + (1 << LOWRES_COST_SHIFT) << list ); +} +#endif + void x264_mc_init_mmx( int cpu, x264_mc_functions_t *pf ) { if( !(cpu&X264_CPU_MMX) ) @@ -547,8 +578,6 @@ void x264_mc_init_mmx( int cpu, x264_mc_functions_t *pf ) pf->copy[PIXEL_16x16] = x264_mc_copy_w16_mmx; pf->copy[PIXEL_8x8] = x264_mc_copy_w8_mmx; pf->copy[PIXEL_4x4] = x264_mc_copy_w4_mmx; - pf->memcpy_aligned = x264_memcpy_aligned_mmx; - pf->memzero_aligned = x264_memzero_aligned_mmx; pf->integral_init4v = x264_integral_init4v_mmx; pf->integral_init8v = x264_integral_init8v_mmx; @@ -606,6 +635,7 @@ void x264_mc_init_mmx( int cpu, x264_mc_functions_t *pf ) pf->plane_copy_interleave = x264_plane_copy_interleave_sse2; pf->plane_copy_deinterleave = x264_plane_copy_deinterleave_sse2; + pf->plane_copy_deinterleave_yuyv = x264_plane_copy_deinterleave_yuyv_sse2; if( cpu&X264_CPU_SSE2_IS_FAST ) { @@ -661,6 +691,7 @@ void x264_mc_init_mmx( int cpu, x264_mc_functions_t *pf ) pf->load_deinterleave_chroma_fdec = x264_load_deinterleave_chroma_fdec_avx; pf->plane_copy_interleave = x264_plane_copy_interleave_avx; pf->plane_copy_deinterleave = x264_plane_copy_deinterleave_avx; + pf->plane_copy_deinterleave_yuyv = x264_plane_copy_deinterleave_yuyv_avx; pf->plane_copy_deinterleave_v210 = x264_plane_copy_deinterleave_v210_avx; pf->store_interleave_chroma = x264_store_interleave_chroma_avx; pf->copy[PIXEL_16x16] = x264_mc_copy_w16_aligned_avx; @@ -677,6 +708,11 @@ void x264_mc_init_mmx( int cpu, x264_mc_functions_t *pf ) pf->load_deinterleave_chroma_fdec = x264_load_deinterleave_chroma_fdec_avx2; pf->plane_copy_deinterleave_v210 = x264_plane_copy_deinterleave_v210_avx2; } + + if( cpu&X264_CPU_AVX512 ) + { + pf->plane_copy_deinterleave_v210 = x264_plane_copy_deinterleave_v210_avx512; + } #else // !HIGH_BIT_DEPTH #if ARCH_X86 // all x86_64 cpus with cacheline split issues use sse2 instead @@ -702,6 +738,7 @@ void x264_mc_init_mmx( int cpu, x264_mc_functions_t *pf ) pf->hpel_filter = x264_hpel_filter_sse2_amd; pf->mbtree_propagate_cost = x264_mbtree_propagate_cost_sse2; pf->plane_copy_deinterleave = x264_plane_copy_deinterleave_sse2; + pf->plane_copy_deinterleave_yuyv = x264_plane_copy_deinterleave_yuyv_sse2; pf->load_deinterleave_chroma_fenc = x264_load_deinterleave_chroma_fenc_sse2; pf->load_deinterleave_chroma_fdec = x264_load_deinterleave_chroma_fdec_sse2; pf->plane_copy_deinterleave_rgb = x264_plane_copy_deinterleave_rgb_sse2; @@ -763,6 +800,7 @@ void x264_mc_init_mmx( int cpu, x264_mc_functions_t *pf ) pf->load_deinterleave_chroma_fenc = x264_load_deinterleave_chroma_fenc_ssse3; pf->load_deinterleave_chroma_fdec = x264_load_deinterleave_chroma_fdec_ssse3; pf->plane_copy_deinterleave = x264_plane_copy_deinterleave_ssse3; + pf->plane_copy_deinterleave_yuyv = x264_plane_copy_deinterleave_yuyv_ssse3; } if( !(cpu&X264_CPU_SLOW_PALIGNR) ) @@ -779,7 +817,7 @@ void x264_mc_init_mmx( int cpu, x264_mc_functions_t *pf ) if( cpu&X264_CPU_CACHELINE_64 ) { if( !(cpu&X264_CPU_STACK_MOD4) ) - pf->mc_chroma = x264_mc_chroma_ssse3_cache64; + pf->mc_chroma = x264_mc_chroma_cache64_ssse3; pf->mc_luma = mc_luma_cache64_ssse3; pf->get_ref = get_ref_cache64_ssse3; if( cpu&X264_CPU_SLOW_ATOM ) @@ -828,10 +866,20 @@ void x264_mc_init_mmx( int cpu, x264_mc_functions_t *pf ) pf->frame_init_lowres_core = x264_frame_init_lowres_core_avx2; pf->plane_copy_deinterleave_rgb = x264_plane_copy_deinterleave_rgb_avx2; } + + if( cpu&X264_CPU_AVX512 ) + { + pf->avg[PIXEL_16x16] = x264_pixel_avg_16x16_avx512; + pf->avg[PIXEL_16x8] = x264_pixel_avg_16x8_avx512; + pf->avg[PIXEL_8x16] = x264_pixel_avg_8x16_avx512; + pf->avg[PIXEL_8x8] = x264_pixel_avg_8x8_avx512; + pf->avg[PIXEL_8x4] = x264_pixel_avg_8x4_avx512; + } #endif // HIGH_BIT_DEPTH if( !(cpu&X264_CPU_AVX) ) return; + pf->memcpy_aligned = x264_memcpy_aligned_avx; pf->memzero_aligned = x264_memzero_aligned_avx; pf->plane_copy = x264_plane_copy_avx; pf->mbtree_propagate_cost = x264_mbtree_propagate_cost_avx; @@ -844,10 +892,20 @@ void x264_mc_init_mmx( int cpu, x264_mc_functions_t *pf ) return; pf->plane_copy_swap = x264_plane_copy_swap_avx2; pf->plane_copy_deinterleave = x264_plane_copy_deinterleave_avx2; + pf->plane_copy_deinterleave_yuyv = x264_plane_copy_deinterleave_yuyv_avx2; pf->load_deinterleave_chroma_fenc = x264_load_deinterleave_chroma_fenc_avx2; pf->get_ref = get_ref_avx2; pf->mbtree_propagate_cost = x264_mbtree_propagate_cost_avx2; pf->mbtree_propagate_list = x264_mbtree_propagate_list_avx2; pf->mbtree_fix8_pack = x264_mbtree_fix8_pack_avx2; pf->mbtree_fix8_unpack = x264_mbtree_fix8_unpack_avx2; + + if( !(cpu&X264_CPU_AVX512) ) + return; + pf->memcpy_aligned = x264_memcpy_aligned_avx512; + pf->memzero_aligned = x264_memzero_aligned_avx512; + pf->mbtree_propagate_cost = x264_mbtree_propagate_cost_avx512; +#if ARCH_X86_64 + pf->mbtree_propagate_list = x264_mbtree_propagate_list_avx512; +#endif } diff --git a/library/src/main/cpp/libx264/common/x86/pixel-a.asm b/library/src/main/cpp/libx264/common/x86/pixel-a.asm index 0dfe61d..1ce26b9 100644 --- a/library/src/main/cpp/libx264/common/x86/pixel-a.asm +++ b/library/src/main/cpp/libx264/common/x86/pixel-a.asm @@ -32,6 +32,8 @@ %include "x86util.asm" SECTION_RODATA 32 +var_shuf_avx512: db 0,-1, 1,-1, 2,-1, 3,-1, 4,-1, 5,-1, 6,-1, 7,-1 + db 8,-1, 9,-1,10,-1,11,-1,12,-1,13,-1,14,-1,15,-1 hmul_16p: times 16 db 1 times 8 db 1, -1 hmul_8p: times 8 db 1 @@ -701,25 +703,32 @@ SSD_NV12 %if HIGH_BIT_DEPTH == 0 %if %1 mova m7, [pw_00ff] -%elif mmsize < 32 +%elif mmsize == 16 pxor m7, m7 ; zero %endif %endif ; !HIGH_BIT_DEPTH %endmacro -%macro VAR_END 2 -%if HIGH_BIT_DEPTH && mmsize == 8 && %1*%2 == 256 - HADDUW m5, m2 -%else - HADDW m5, m2 +%macro VAR_END 0 + pmaddwd m5, [pw_1] + SBUTTERFLY dq, 5, 6, 0 + paddd m5, m6 +%if mmsize == 32 + vextracti128 xm6, m5, 1 + paddd xm5, xm6 %endif - HADDD m6, m1 + MOVHL xm6, xm5 + paddd xm5, xm6 %if ARCH_X86_64 - punpckldq m5, m6 - movq rax, m5 + movq rax, xm5 +%else + movd eax, xm5 +%if cpuflag(avx) + pextrd edx, xm5, 1 %else - movd eax, m5 - movd edx, m6 + pshuflw xm5, xm5, q1032 + movd edx, xm5 +%endif %endif RET %endmacro @@ -739,61 +748,25 @@ SSD_NV12 paddd m6, m4 %endmacro -%macro VAR_2ROW 2 - mov r2d, %2 -.loop: -%if HIGH_BIT_DEPTH - mova m0, [r0] - mova m1, [r0+mmsize] - mova m3, [r0+%1] - mova m4, [r0+%1+mmsize] -%else ; !HIGH_BIT_DEPTH - mova m0, [r0] - mova m3, [r0+%1] - punpckhbw m1, m0, m7 - punpcklbw m0, m7 - punpckhbw m4, m3, m7 - punpcklbw m3, m7 -%endif ; HIGH_BIT_DEPTH -%ifidn %1, r1 - lea r0, [r0+%1*2] -%else - add r0, r1 -%endif - VAR_CORE - dec r2d - jg .loop -%endmacro - ;----------------------------------------------------------------------------- ; int pixel_var_wxh( uint8_t *, intptr_t ) ;----------------------------------------------------------------------------- -INIT_MMX mmx2 -cglobal pixel_var_16x16, 2,3 - FIX_STRIDES r1 - VAR_START 0 - VAR_2ROW 8*SIZEOF_PIXEL, 16 - VAR_END 16, 16 - -cglobal pixel_var_8x16, 2,3 - FIX_STRIDES r1 - VAR_START 0 - VAR_2ROW r1, 8 - VAR_END 8, 16 - -cglobal pixel_var_8x8, 2,3 - FIX_STRIDES r1 - VAR_START 0 - VAR_2ROW r1, 4 - VAR_END 8, 8 - %if HIGH_BIT_DEPTH %macro VAR 0 cglobal pixel_var_16x16, 2,3,8 FIX_STRIDES r1 VAR_START 0 - VAR_2ROW r1, 8 - VAR_END 16, 16 + mov r2d, 8 +.loop: + mova m0, [r0] + mova m1, [r0+mmsize] + mova m3, [r0+r1] + mova m4, [r0+r1+mmsize] + lea r0, [r0+r1*2] + VAR_CORE + dec r2d + jg .loop + VAR_END cglobal pixel_var_8x8, 2,3,8 lea r2, [r1*3] @@ -809,18 +782,16 @@ cglobal pixel_var_8x8, 2,3,8 mova m3, [r0+r1*4] mova m4, [r0+r2*2] VAR_CORE - VAR_END 8, 8 + VAR_END %endmacro ; VAR INIT_XMM sse2 VAR INIT_XMM avx VAR -INIT_XMM xop -VAR -%endif ; HIGH_BIT_DEPTH -%if HIGH_BIT_DEPTH == 0 +%else ; HIGH_BIT_DEPTH == 0 + %macro VAR 0 cglobal pixel_var_16x16, 2,3,8 VAR_START 1 @@ -833,7 +804,7 @@ cglobal pixel_var_16x16, 2,3,8 VAR_CORE dec r2d jg .loop - VAR_END 16, 16 + VAR_END cglobal pixel_var_8x8, 2,4,8 VAR_START 1 @@ -849,7 +820,7 @@ cglobal pixel_var_8x8, 2,4,8 VAR_CORE dec r2d jg .loop - VAR_END 8, 8 + VAR_END cglobal pixel_var_8x16, 2,4,8 VAR_START 1 @@ -865,15 +836,13 @@ cglobal pixel_var_8x16, 2,4,8 VAR_CORE dec r2d jg .loop - VAR_END 8, 16 + VAR_END %endmacro ; VAR INIT_XMM sse2 VAR INIT_XMM avx VAR -INIT_XMM xop -VAR %endif ; !HIGH_BIT_DEPTH INIT_YMM avx2 @@ -898,209 +867,357 @@ cglobal pixel_var_16x16, 2,4,7 VAR_CORE dec r2d jg .loop - vextracti128 xm0, m5, 1 - vextracti128 xm1, m6, 1 - paddw xm5, xm0 - paddd xm6, xm1 - HADDW xm5, xm2 - HADDD xm6, xm1 -%if ARCH_X86_64 - punpckldq xm5, xm6 - movq rax, xm5 + VAR_END + +%macro VAR_AVX512_CORE 1 ; accum +%if %1 + paddw m0, m2 + pmaddwd m2, m2 + paddw m0, m3 + pmaddwd m3, m3 + paddd m1, m2 + paddd m1, m3 %else - movd eax, xm5 - movd edx, xm6 + paddw m0, m2, m3 + pmaddwd m2, m2 + pmaddwd m3, m3 + paddd m1, m2, m3 %endif - RET +%endmacro -%macro VAR2_END 3 - HADDW %2, xm1 - movd r1d, %2 - imul r1d, r1d - HADDD %3, xm1 - shr r1d, %1 - movd eax, %3 - movd [r4], %3 - sub eax, r1d ; sqr - (sum * sum >> shift) - RET +%macro VAR_AVX512_CORE_16x16 1 ; accum +%if HIGH_BIT_DEPTH + mova ym2, [r0] + vinserti64x4 m2, [r0+r1], 1 + mova ym3, [r0+2*r1] + vinserti64x4 m3, [r0+r3], 1 +%else + vbroadcasti64x2 ym2, [r0] + vbroadcasti64x2 m2 {k1}, [r0+r1] + vbroadcasti64x2 ym3, [r0+2*r1] + vbroadcasti64x2 m3 {k1}, [r0+r3] + pshufb m2, m4 + pshufb m3, m4 +%endif + VAR_AVX512_CORE %1 %endmacro -;----------------------------------------------------------------------------- -; int pixel_var2_8x8( pixel *, intptr_t, pixel *, intptr_t, int * ) -;----------------------------------------------------------------------------- -%macro VAR2_8x8_MMX 2 -cglobal pixel_var2_8x%1, 5,6 - FIX_STRIDES r1, r3 - VAR_START 0 - mov r5d, %1 -.loop: +%macro VAR_AVX512_CORE_8x8 1 ; accum %if HIGH_BIT_DEPTH - mova m0, [r0] - mova m1, [r0+mmsize] - psubw m0, [r2] - psubw m1, [r2+mmsize] -%else ; !HIGH_BIT_DEPTH - movq m0, [r0] - movq m1, m0 - movq m2, [r2] - movq m3, m2 - punpcklbw m0, m7 - punpckhbw m1, m7 - punpcklbw m2, m7 - punpckhbw m3, m7 - psubw m0, m2 - psubw m1, m3 -%endif ; HIGH_BIT_DEPTH - paddw m5, m0 - paddw m5, m1 - pmaddwd m0, m0 - pmaddwd m1, m1 - paddd m6, m0 - paddd m6, m1 - add r0, r1 - add r2, r3 - dec r5d - jg .loop - VAR2_END %2, m5, m6 + mova xm2, [r0] + mova xm3, [r0+r1] +%else + movq xm2, [r0] + movq xm3, [r0+r1] +%endif + vinserti128 ym2, [r0+2*r1], 1 + vinserti128 ym3, [r0+r2], 1 + lea r0, [r0+4*r1] + vinserti32x4 m2, [r0], 2 + vinserti32x4 m3, [r0+r1], 2 + vinserti32x4 m2, [r0+2*r1], 3 + vinserti32x4 m3, [r0+r2], 3 +%if HIGH_BIT_DEPTH == 0 + punpcklbw m2, m4 + punpcklbw m3, m4 +%endif + VAR_AVX512_CORE %1 %endmacro +INIT_ZMM avx512 +cglobal pixel_var_16x16, 2,4 + FIX_STRIDES r1 + mov r2d, 0xf0 + lea r3, [3*r1] +%if HIGH_BIT_DEPTH == 0 + vbroadcasti64x4 m4, [var_shuf_avx512] + kmovb k1, r2d +%endif + VAR_AVX512_CORE_16x16 0 +.loop: + lea r0, [r0+4*r1] + VAR_AVX512_CORE_16x16 1 + sub r2d, 0x50 + jg .loop %if ARCH_X86_64 == 0 -INIT_MMX mmx2 -VAR2_8x8_MMX 8, 6 -VAR2_8x8_MMX 16, 7 + pop r3d + %assign regs_used 3 +%endif +var_avx512_end: + vbroadcasti32x4 m2, [pw_1] + pmaddwd m0, m2 + SBUTTERFLY dq, 0, 1, 2 + paddd m0, m1 + vextracti32x8 ym1, m0, 1 + paddd ym0, ym1 + vextracti128 xm1, ym0, 1 + paddd xmm0, xm0, xm1 + punpckhqdq xmm1, xmm0, xmm0 + paddd xmm0, xmm1 +%if ARCH_X86_64 + movq rax, xmm0 +%else + movd eax, xmm0 + pextrd edx, xmm0, 1 %endif + RET + +%if HIGH_BIT_DEPTH == 0 ; 8x8 doesn't benefit from AVX-512 in high bit-depth +cglobal pixel_var_8x8, 2,3 + lea r2, [3*r1] + pxor xm4, xm4 + VAR_AVX512_CORE_8x8 0 + jmp var_avx512_end +%endif + +cglobal pixel_var_8x16, 2,3 + FIX_STRIDES r1 + lea r2, [3*r1] +%if HIGH_BIT_DEPTH == 0 + pxor xm4, xm4 +%endif + VAR_AVX512_CORE_8x8 0 + lea r0, [r0+4*r1] + VAR_AVX512_CORE_8x8 1 + jmp var_avx512_end + +;----------------------------------------------------------------------------- +; int pixel_var2_8x8( pixel *fenc, pixel *fdec, int ssd[2] ) +;----------------------------------------------------------------------------- + +%if ARCH_X86_64 + DECLARE_REG_TMP 6 +%else + DECLARE_REG_TMP 2 +%endif + +%macro VAR2_END 3 ; src, tmp, shift + movifnidn r2, r2mp + pshufd %2, %1, q3331 + pmuludq %1, %1 + movq [r2], %2 ; sqr_u sqr_v + psrld %1, %3 + psubd %2, %1 ; sqr - (sum * sum >> shift) + MOVHL %1, %2 + paddd %1, %2 + movd eax, %1 + RET +%endmacro %macro VAR2_8x8_SSE2 2 -cglobal pixel_var2_8x%1, 5,6,8 - VAR_START 1 - mov r5d, %1/2 +%if HIGH_BIT_DEPTH +cglobal pixel_var2_8x%1, 2,3,6 + pxor m4, m4 + pxor m5, m5 +%define %%sum2 m4 +%define %%sqr2 m5 +%else +cglobal pixel_var2_8x%1, 2,3,7 + mova m6, [pw_00ff] +%define %%sum2 m0 +%define %%sqr2 m1 +%endif + pxor m0, m0 ; sum + pxor m1, m1 ; sqr + mov t0d, (%1-1)*FENC_STRIDEB .loop: %if HIGH_BIT_DEPTH - mova m0, [r0] - mova m1, [r0+r1*2] - mova m2, [r2] - mova m3, [r2+r3*2] -%else ; !HIGH_BIT_DEPTH - movq m1, [r0] - movhps m1, [r0+r1] - movq m3, [r2] - movhps m3, [r2+r3] - DEINTB 0, 1, 2, 3, 7 -%endif ; HIGH_BIT_DEPTH - psubw m0, m2 - psubw m1, m3 - paddw m5, m0 - paddw m5, m1 - pmaddwd m0, m0 - pmaddwd m1, m1 - paddd m6, m0 - paddd m6, m1 - lea r0, [r0+r1*2*SIZEOF_PIXEL] - lea r2, [r2+r3*2*SIZEOF_PIXEL] - dec r5d - jg .loop - VAR2_END %2, m5, m6 + mova m2, [r0+1*t0] + psubw m2, [r1+2*t0] + mova m3, [r0+1*t0+16] + psubw m3, [r1+2*t0+32] +%else + mova m3, [r0+1*t0] + movq m5, [r1+2*t0] + punpcklqdq m5, [r1+2*t0+16] + DEINTB 2, 3, 4, 5, 6 + psubw m2, m4 + psubw m3, m5 +%endif + paddw m0, m2 + pmaddwd m2, m2 + paddw %%sum2, m3 + pmaddwd m3, m3 + paddd m1, m2 + paddd %%sqr2, m3 + sub t0d, FENC_STRIDEB + jge .loop +%if HIGH_BIT_DEPTH + SBUTTERFLY dq, 0, 4, 2 + paddw m0, m4 ; sum_u sum_v + pmaddwd m0, [pw_1] + SBUTTERFLY dq, 1, 5, 2 + paddd m1, m5 ; sqr_u sqr_v + SBUTTERFLY dq, 0, 1, 2 + paddd m0, m1 +%else + pmaddwd m0, [pw_1] + shufps m2, m0, m1, q2020 + shufps m0, m1, q3131 + paddd m0, m2 + pshufd m0, m0, q3120 ; sum_u sqr_u sum_v sqr_v +%endif + VAR2_END m0, m1, %2 %endmacro INIT_XMM sse2 VAR2_8x8_SSE2 8, 6 VAR2_8x8_SSE2 16, 7 +%macro VAR2_CORE 3 ; src1, src2, accum +%if %3 + paddw m0, %1 + pmaddwd %1, %1 + paddw m0, %2 + pmaddwd %2, %2 + paddd m1, %1 + paddd m1, %2 +%else + paddw m0, %1, %2 + pmaddwd %1, %1 + pmaddwd %2, %2 + paddd m1, %1, %2 +%endif +%endmacro + %if HIGH_BIT_DEPTH == 0 -%macro VAR2_8x8_SSSE3 2 -cglobal pixel_var2_8x%1, 5,6,8 - pxor m5, m5 ; sum - pxor m6, m6 ; sum squared - mova m7, [hsub_mul] - mov r5d, %1/4 +INIT_XMM ssse3 +cglobal pixel_var2_internal + pxor m0, m0 ; sum + pxor m1, m1 ; sqr .loop: - movq m0, [r0] - movq m2, [r2] - movq m1, [r0+r1] - movq m3, [r2+r3] - lea r0, [r0+r1*2] - lea r2, [r2+r3*2] - punpcklbw m0, m2 - punpcklbw m1, m3 - movq m2, [r0] - movq m3, [r2] - punpcklbw m2, m3 - movq m3, [r0+r1] - movq m4, [r2+r3] - punpcklbw m3, m4 - pmaddubsw m0, m7 - pmaddubsw m1, m7 - pmaddubsw m2, m7 - pmaddubsw m3, m7 - paddw m5, m0 - paddw m5, m1 - paddw m5, m2 - paddw m5, m3 - pmaddwd m0, m0 - pmaddwd m1, m1 - pmaddwd m2, m2 - pmaddwd m3, m3 - paddd m6, m0 - paddd m6, m1 - paddd m6, m2 - paddd m6, m3 - lea r0, [r0+r1*2] - lea r2, [r2+r3*2] - dec r5d + movq m2, [r0+1*t0] + punpcklbw m2, [r1+2*t0] + movq m3, [r0+1*t0-1*FENC_STRIDE] + punpcklbw m3, [r1+2*t0-1*FDEC_STRIDE] + movq m4, [r0+1*t0-2*FENC_STRIDE] + punpcklbw m4, [r1+2*t0-2*FDEC_STRIDE] + movq m5, [r0+1*t0-3*FENC_STRIDE] + punpcklbw m5, [r1+2*t0-3*FDEC_STRIDE] + pmaddubsw m2, m7 + pmaddubsw m3, m7 + pmaddubsw m4, m7 + pmaddubsw m5, m7 + VAR2_CORE m2, m3, 1 + VAR2_CORE m4, m5, 1 + sub t0d, 4*FENC_STRIDE jg .loop - VAR2_END %2, m5, m6 + pmaddwd m0, [pw_1] + ret + +%macro VAR2_8x8_SSSE3 2 +cglobal pixel_var2_8x%1, 2,3,8 + mova m7, [hsub_mul] + mov t0d, (%1-1)*FENC_STRIDE + call pixel_var2_internal_ssse3 ; u + add r0, 8 + add r1, 16 + SBUTTERFLY qdq, 0, 1, 6 + paddd m1, m0 + mov t0d, (%1-1)*FENC_STRIDE + call pixel_var2_internal_ssse3 ; v + SBUTTERFLY qdq, 0, 6, 2 + paddd m0, m6 + phaddd m1, m0 ; sum_u sqr_u sum_v sqr_v + VAR2_END m1, m0, %2 %endmacro -INIT_XMM ssse3 -VAR2_8x8_SSSE3 8, 6 -VAR2_8x8_SSSE3 16, 7 -INIT_XMM xop VAR2_8x8_SSSE3 8, 6 VAR2_8x8_SSSE3 16, 7 +%endif ; !HIGH_BIT_DEPTH + +%macro VAR2_AVX2_LOAD 3 ; offset_reg, row1_offset, row2_offset +%if HIGH_BIT_DEPTH +%if mmsize == 64 + mova m2, [r1+2*%1+%2*FDEC_STRIDEB] + vshufi32x4 m2, [r1+2*%1+%2*FDEC_STRIDEB+64], q2020 + mova m3, [r1+2*%1+%3*FDEC_STRIDEB] + vshufi32x4 m3, [r1+2*%1+%3*FDEC_STRIDEB+64], q2020 +%else + mova xm2, [r1+2*%1+%2*FDEC_STRIDEB] + vinserti128 m2, [r1+2*%1+%2*FDEC_STRIDEB+32], 1 + mova xm3, [r1+2*%1+%3*FDEC_STRIDEB] + vinserti128 m3, [r1+2*%1+%3*FDEC_STRIDEB+32], 1 +%endif + psubw m2, [r0+1*%1+%2*FENC_STRIDEB] + psubw m3, [r0+1*%1+%3*FENC_STRIDEB] +%else + pmovzxbw m2, [r0+1*%1+%2*FENC_STRIDE] + mova m4, [r1+2*%1+%2*FDEC_STRIDE] + pmovzxbw m3, [r0+1*%1+%3*FENC_STRIDE] + mova m5, [r1+2*%1+%3*FDEC_STRIDE] + punpcklbw m4, m6 + punpcklbw m5, m6 + psubw m2, m4 + psubw m3, m5 +%endif +%endmacro %macro VAR2_8x8_AVX2 2 -cglobal pixel_var2_8x%1, 5,6,6 - pxor m3, m3 ; sum - pxor m4, m4 ; sum squared - mova m5, [hsub_mul] - mov r5d, %1/4 +%if HIGH_BIT_DEPTH +cglobal pixel_var2_8x%1, 2,3,4 +%else +cglobal pixel_var2_8x%1, 2,3,7 + pxor m6, m6 +%endif + mov t0d, (%1-3)*FENC_STRIDEB + VAR2_AVX2_LOAD t0, 2, 1 + VAR2_CORE m2, m3, 0 .loop: - movq xm0, [r0] - movq xm1, [r2] - vinserti128 m0, m0, [r0+r1], 1 - vinserti128 m1, m1, [r2+r3], 1 - lea r0, [r0+r1*2] - lea r2, [r2+r3*2] - punpcklbw m0, m1 - movq xm1, [r0] - movq xm2, [r2] - vinserti128 m1, m1, [r0+r1], 1 - vinserti128 m2, m2, [r2+r3], 1 - lea r0, [r0+r1*2] - lea r2, [r2+r3*2] - punpcklbw m1, m2 - pmaddubsw m0, m5 - pmaddubsw m1, m5 - paddw m3, m0 - paddw m3, m1 - pmaddwd m0, m0 - pmaddwd m1, m1 - paddd m4, m0 - paddd m4, m1 - dec r5d + VAR2_AVX2_LOAD t0, 0, -1 + VAR2_CORE m2, m3, 1 + sub t0d, 2*FENC_STRIDEB jg .loop - vextracti128 xm0, m3, 1 - vextracti128 xm1, m4, 1 - paddw xm3, xm0 - paddd xm4, xm1 - VAR2_END %2, xm3, xm4 + + pmaddwd m0, [pw_1] + SBUTTERFLY qdq, 0, 1, 2 + paddd m0, m1 + vextracti128 xm1, m0, 1 + phaddd xm0, xm1 + VAR2_END xm0, xm1, %2 %endmacro INIT_YMM avx2 VAR2_8x8_AVX2 8, 6 VAR2_8x8_AVX2 16, 7 -%endif ; !HIGH_BIT_DEPTH +%macro VAR2_AVX512_END 1 ; shift + vbroadcasti32x4 m2, [pw_1] + pmaddwd m0, m2 + SBUTTERFLY qdq, 0, 1, 2 + paddd m0, m1 + vextracti32x8 ym1, m0, 1 + paddd ym0, ym1 + psrlq ym1, ym0, 32 + paddd ym0, ym1 + vpmovqd xmm0, ym0 ; sum_u, sqr_u, sum_v, sqr_v + VAR2_END xmm0, xmm1, %1 +%endmacro + +INIT_ZMM avx512 +cglobal pixel_var2_8x8, 2,3 +%if HIGH_BIT_DEPTH == 0 + pxor xm6, xm6 +%endif + VAR2_AVX2_LOAD 0, 0, 2 + VAR2_CORE m2, m3, 0 + VAR2_AVX2_LOAD 0, 4, 6 + VAR2_CORE m2, m3, 1 + VAR2_AVX512_END 6 + +cglobal pixel_var2_8x16, 2,3 +%if HIGH_BIT_DEPTH == 0 + pxor xm6, xm6 +%endif + mov t0d, 10*FENC_STRIDEB + VAR2_AVX2_LOAD 0, 14, 12 + VAR2_CORE m2, m3, 0 +.loop: + VAR2_AVX2_LOAD t0, 0, -2 + VAR2_CORE m2, m3, 1 + sub t0d, 4*FENC_STRIDEB + jg .loop + VAR2_AVX512_END 7 ;============================================================================= ; SATD @@ -4583,6 +4700,244 @@ cglobal intra_sad_x9_8x8, 5,7,8 mov rsp, r6 mov eax, r2d RET + +%macro SATD_AVX512_LOAD4 2 ; size, opmask + vpbroadcast%1 m0, [r0] + vpbroadcast%1 m0 {%2}, [r0+2*r1] + vpbroadcast%1 m2, [r2] + vpbroadcast%1 m2 {%2}, [r2+2*r3] + add r0, r1 + add r2, r3 + vpbroadcast%1 m1, [r0] + vpbroadcast%1 m1 {%2}, [r0+2*r1] + vpbroadcast%1 m3, [r2] + vpbroadcast%1 m3 {%2}, [r2+2*r3] +%endmacro + +%macro SATD_AVX512_LOAD8 5 ; size, halfreg, opmask1, opmask2, opmask3 + vpbroadcast%1 %{2}0, [r0] + vpbroadcast%1 %{2}0 {%3}, [r0+2*r1] + vpbroadcast%1 %{2}2, [r2] + vpbroadcast%1 %{2}2 {%3}, [r2+2*r3] + vpbroadcast%1 m0 {%4}, [r0+4*r1] + vpbroadcast%1 m2 {%4}, [r2+4*r3] + vpbroadcast%1 m0 {%5}, [r0+2*r4] + vpbroadcast%1 m2 {%5}, [r2+2*r5] + vpbroadcast%1 %{2}1, [r0+r1] + vpbroadcast%1 %{2}1 {%3}, [r0+r4] + vpbroadcast%1 %{2}3, [r2+r3] + vpbroadcast%1 %{2}3 {%3}, [r2+r5] + lea r0, [r0+4*r1] + lea r2, [r2+4*r3] + vpbroadcast%1 m1 {%4}, [r0+r1] + vpbroadcast%1 m3 {%4}, [r2+r3] + vpbroadcast%1 m1 {%5}, [r0+r4] + vpbroadcast%1 m3 {%5}, [r2+r5] +%endmacro + +%macro SATD_AVX512_PACKED 0 + DIFF_SUMSUB_SSSE3 0, 2, 1, 3, 4 + SUMSUB_BA w, 0, 1, 2 + SBUTTERFLY qdq, 0, 1, 2 + SUMSUB_BA w, 0, 1, 2 + HMAXABSW2 0, 1, 2, 3 +%endmacro + +%macro SATD_AVX512_END 0-1 0 ; sa8d + paddw m0 {k1}{z}, m1 ; zero-extend to dwords +%if ARCH_X86_64 +%if mmsize == 64 + vextracti32x8 ym1, m0, 1 + paddd ym0, ym1 +%endif +%if mmsize >= 32 + vextracti128 xm1, ym0, 1 + paddd xmm0, xm0, xm1 +%endif + punpckhqdq xmm1, xmm0, xmm0 + paddd xmm0, xmm1 + movq rax, xmm0 + rorx rdx, rax, 32 +%if %1 + lea eax, [rax+rdx+1] + shr eax, 1 +%else + add eax, edx +%endif +%else + HADDD m0, m1 + movd eax, xm0 +%if %1 + inc eax + shr eax, 1 +%endif +%endif + RET +%endmacro + +%macro HMAXABSW2 4 ; a, b, tmp1, tmp2 + pabsw m%1, m%1 + pabsw m%2, m%2 + psrldq m%3, m%1, 2 + psrld m%4, m%2, 16 + pmaxsw m%1, m%3 + pmaxsw m%2, m%4 +%endmacro + +INIT_ZMM avx512 +cglobal pixel_satd_16x8_internal + vbroadcasti64x4 m6, [hmul_16p] + kxnorb k2, k2, k2 + mov r4d, 0x55555555 + knotw k2, k2 + kmovd k1, r4d + lea r4, [3*r1] + lea r5, [3*r3] +satd_16x8_avx512: + vbroadcasti128 ym0, [r0] + vbroadcasti32x4 m0 {k2}, [r0+4*r1] ; 0 0 4 4 + vbroadcasti128 ym4, [r2] + vbroadcasti32x4 m4 {k2}, [r2+4*r3] + vbroadcasti128 ym2, [r0+2*r1] + vbroadcasti32x4 m2 {k2}, [r0+2*r4] ; 2 2 6 6 + vbroadcasti128 ym5, [r2+2*r3] + vbroadcasti32x4 m5 {k2}, [r2+2*r5] + DIFF_SUMSUB_SSSE3 0, 4, 2, 5, 6 + vbroadcasti128 ym1, [r0+r1] + vbroadcasti128 ym4, [r2+r3] + vbroadcasti128 ym3, [r0+r4] + vbroadcasti128 ym5, [r2+r5] + lea r0, [r0+4*r1] + lea r2, [r2+4*r3] + vbroadcasti32x4 m1 {k2}, [r0+r1] ; 1 1 5 5 + vbroadcasti32x4 m4 {k2}, [r2+r3] + vbroadcasti32x4 m3 {k2}, [r0+r4] ; 3 3 7 7 + vbroadcasti32x4 m5 {k2}, [r2+r5] + DIFF_SUMSUB_SSSE3 1, 4, 3, 5, 6 + HADAMARD4_V 0, 1, 2, 3, 4 + HMAXABSW2 0, 2, 4, 5 + HMAXABSW2 1, 3, 4, 5 + paddw m4, m0, m2 ; m1 + paddw m2, m1, m3 ; m0 + ret + +cglobal pixel_satd_8x8_internal + vbroadcasti64x4 m4, [hmul_16p] + mov r4d, 0x55555555 + kmovd k1, r4d ; 01010101 + kshiftlb k2, k1, 5 ; 10100000 + kshiftlb k3, k1, 4 ; 01010000 + lea r4, [3*r1] + lea r5, [3*r3] +satd_8x8_avx512: + SATD_AVX512_LOAD8 q, ym, k1, k2, k3 ; 2 0 2 0 6 4 6 4 + SATD_AVX512_PACKED ; 3 1 3 1 7 5 7 5 + ret + +cglobal pixel_satd_16x8, 4,6 + call pixel_satd_16x8_internal_avx512 + jmp satd_zmm_avx512_end + +cglobal pixel_satd_16x16, 4,6 + call pixel_satd_16x8_internal_avx512 + lea r0, [r0+4*r1] + lea r2, [r2+4*r3] + paddw m7, m0, m1 + call satd_16x8_avx512 + paddw m1, m7 + jmp satd_zmm_avx512_end + +cglobal pixel_satd_8x8, 4,6 + call pixel_satd_8x8_internal_avx512 +satd_zmm_avx512_end: + SATD_AVX512_END + +cglobal pixel_satd_8x16, 4,6 + call pixel_satd_8x8_internal_avx512 + lea r0, [r0+4*r1] + lea r2, [r2+4*r3] + paddw m5, m0, m1 + call satd_8x8_avx512 + paddw m1, m5 + jmp satd_zmm_avx512_end + +INIT_YMM avx512 +cglobal pixel_satd_4x8_internal + vbroadcasti128 m4, [hmul_4p] + mov r4d, 0x55550c + kmovd k2, r4d ; 00001100 + kshiftlb k3, k2, 2 ; 00110000 + kshiftlb k4, k2, 4 ; 11000000 + kshiftrd k1, k2, 8 ; 01010101 + lea r4, [3*r1] + lea r5, [3*r3] +satd_4x8_avx512: + SATD_AVX512_LOAD8 d, xm, k2, k3, k4 ; 0 0 2 2 4 4 6 6 +satd_ymm_avx512: ; 1 1 3 3 5 5 7 7 + SATD_AVX512_PACKED + ret + +cglobal pixel_satd_8x4, 4,5 + mova m4, [hmul_16p] + mov r4d, 0x5555 + kmovw k1, r4d + SATD_AVX512_LOAD4 q, k1 ; 2 0 2 0 + call satd_ymm_avx512 ; 3 1 3 1 + jmp satd_ymm_avx512_end2 + +cglobal pixel_satd_4x8, 4,6 + call pixel_satd_4x8_internal_avx512 +satd_ymm_avx512_end: +%if ARCH_X86_64 == 0 + pop r5d + %assign regs_used 5 +%endif +satd_ymm_avx512_end2: + SATD_AVX512_END + +cglobal pixel_satd_4x16, 4,6 + call pixel_satd_4x8_internal_avx512 + lea r0, [r0+4*r1] + lea r2, [r2+4*r3] + paddw m5, m0, m1 + call satd_4x8_avx512 + paddw m1, m5 + jmp satd_ymm_avx512_end + +INIT_XMM avx512 +cglobal pixel_satd_4x4, 4,5 + mova m4, [hmul_4p] + mov r4d, 0x550c + kmovw k2, r4d + kshiftrw k1, k2, 8 + SATD_AVX512_LOAD4 d, k2 ; 0 0 2 2 + SATD_AVX512_PACKED ; 1 1 3 3 + SWAP 0, 1 + SATD_AVX512_END + +INIT_ZMM avx512 +cglobal pixel_sa8d_8x8, 4,6 + vbroadcasti64x4 m4, [hmul_16p] + mov r4d, 0x55555555 + kmovd k1, r4d ; 01010101 + kshiftlb k2, k1, 5 ; 10100000 + kshiftlb k3, k1, 4 ; 01010000 + lea r4, [3*r1] + lea r5, [3*r3] + SATD_AVX512_LOAD8 q, ym, k1, k2, k3 ; 2 0 2 0 6 4 6 4 + DIFF_SUMSUB_SSSE3 0, 2, 1, 3, 4 ; 3 1 3 1 7 5 7 5 + SUMSUB_BA w, 0, 1, 2 + SBUTTERFLY qdq, 0, 1, 2 + SUMSUB_BA w, 0, 1, 2 + shufps m2, m0, m1, q2020 + shufps m1, m0, m1, q3131 + SUMSUB_BA w, 2, 1, 0 + vshufi32x4 m0, m2, m1, q1010 + vshufi32x4 m1, m2, m1, q3232 + SUMSUB_BA w, 0, 1, 2 + HMAXABSW2 0, 1, 2, 3 + SATD_AVX512_END 1 + %endif ; HIGH_BIT_DEPTH ;============================================================================= @@ -4867,7 +5222,7 @@ ASD8 add r6, 4*%1 sub r0d, 4*%1 jg .loop - WIN64_RESTORE_XMM rsp + WIN64_RESTORE_XMM %if mmsize==32 vzeroupper %endif diff --git a/library/src/main/cpp/libx264/common/x86/pixel.h b/library/src/main/cpp/libx264/common/x86/pixel.h index 2b0baa3..56cfc5c 100644 --- a/library/src/main/cpp/libx264/common/x86/pixel.h +++ b/library/src/main/cpp/libx264/common/x86/pixel.h @@ -52,6 +52,7 @@ DECL_X1( sad, sse2_aligned ) DECL_X1( sad, ssse3 ) DECL_X1( sad, ssse3_aligned ) DECL_X1( sad, avx2 ) +DECL_X1( sad, avx512 ) DECL_X4( sad, mmx2 ) DECL_X4( sad, sse2 ) DECL_X4( sad, sse3 ) @@ -59,6 +60,7 @@ DECL_X4( sad, ssse3 ) DECL_X4( sad, xop ) DECL_X4( sad, avx ) DECL_X4( sad, avx2 ) +DECL_X4( sad, avx512 ) DECL_X1( ssd, mmx ) DECL_X1( ssd, mmx2 ) DECL_X1( ssd, sse2slow ) @@ -75,6 +77,7 @@ DECL_X1( satd, sse4 ) DECL_X1( satd, avx ) DECL_X1( satd, xop ) DECL_X1( satd, avx2 ) +DECL_X1( satd, avx512 ) DECL_X1( sa8d, mmx2 ) DECL_X1( sa8d, sse2 ) DECL_X1( sa8d, ssse3 ) @@ -83,6 +86,7 @@ DECL_X1( sa8d, sse4 ) DECL_X1( sa8d, avx ) DECL_X1( sa8d, xop ) DECL_X1( sa8d, avx2 ) +DECL_X1( sa8d, avx512 ) DECL_X1( sad, cache32_mmx2 ); DECL_X1( sad, cache64_mmx2 ); DECL_X1( sad, cache64_sse2 ); @@ -92,11 +96,10 @@ DECL_X4( sad, cache64_mmx2 ); DECL_X4( sad, cache64_sse2 ); DECL_X4( sad, cache64_ssse3 ); -DECL_PIXELS( uint64_t, var, mmx2, ( pixel *pix, intptr_t i_stride )) -DECL_PIXELS( uint64_t, var, sse2, ( pixel *pix, intptr_t i_stride )) -DECL_PIXELS( uint64_t, var, avx, ( pixel *pix, intptr_t i_stride )) -DECL_PIXELS( uint64_t, var, xop, ( pixel *pix, intptr_t i_stride )) -DECL_PIXELS( uint64_t, var, avx2, ( pixel *pix, intptr_t i_stride )) +DECL_PIXELS( uint64_t, var, sse2, ( pixel *pix, intptr_t i_stride )) +DECL_PIXELS( uint64_t, var, avx, ( pixel *pix, intptr_t i_stride )) +DECL_PIXELS( uint64_t, var, avx2, ( pixel *pix, intptr_t i_stride )) +DECL_PIXELS( uint64_t, var, avx512, ( pixel *pix, intptr_t i_stride )) DECL_PIXELS( uint64_t, hadamard_ac, mmx2, ( pixel *pix, intptr_t i_stride )) DECL_PIXELS( uint64_t, hadamard_ac, sse2, ( pixel *pix, intptr_t i_stride )) DECL_PIXELS( uint64_t, hadamard_ac, ssse3, ( pixel *pix, intptr_t i_stride )) @@ -165,16 +168,14 @@ void x264_pixel_ssim_4x4x2_core_avx ( const pixel *pix1, intptr_t stride1, const pixel *pix2, intptr_t stride2, int sums[2][4] ); float x264_pixel_ssim_end4_sse2( int sum0[5][4], int sum1[5][4], int width ); float x264_pixel_ssim_end4_avx ( int sum0[5][4], int sum1[5][4], int width ); -int x264_pixel_var2_8x8_mmx2 ( pixel *, intptr_t, pixel *, intptr_t, int * ); -int x264_pixel_var2_8x8_sse2 ( pixel *, intptr_t, pixel *, intptr_t, int * ); -int x264_pixel_var2_8x8_ssse3 ( uint8_t *, intptr_t, uint8_t *, intptr_t, int * ); -int x264_pixel_var2_8x8_xop ( uint8_t *, intptr_t, uint8_t *, intptr_t, int * ); -int x264_pixel_var2_8x8_avx2 ( uint8_t *, intptr_t, uint8_t *, intptr_t, int * ); -int x264_pixel_var2_8x16_mmx2 ( pixel *, intptr_t, pixel *, intptr_t, int * ); -int x264_pixel_var2_8x16_sse2 ( pixel *, intptr_t, pixel *, intptr_t, int * ); -int x264_pixel_var2_8x16_ssse3( uint8_t *, intptr_t, uint8_t *, intptr_t, int * ); -int x264_pixel_var2_8x16_xop ( uint8_t *, intptr_t, uint8_t *, intptr_t, int * ); -int x264_pixel_var2_8x16_avx2 ( uint8_t *, intptr_t, uint8_t *, intptr_t, int * ); +int x264_pixel_var2_8x8_sse2 ( pixel *fenc, pixel *fdec, int ssd[2] ); +int x264_pixel_var2_8x8_ssse3 ( uint8_t *fenc, uint8_t *fdec, int ssd[2] ); +int x264_pixel_var2_8x8_avx2 ( pixel *fenc, pixel *fdec, int ssd[2] ); +int x264_pixel_var2_8x8_avx512 ( pixel *fenc, pixel *fdec, int ssd[2] ); +int x264_pixel_var2_8x16_sse2 ( pixel *fenc, pixel *fdec, int ssd[2] ); +int x264_pixel_var2_8x16_ssse3 ( uint8_t *fenc, uint8_t *fdec, int ssd[2] ); +int x264_pixel_var2_8x16_avx2 ( pixel *fenc, pixel *fdec, int ssd[2] ); +int x264_pixel_var2_8x16_avx512( pixel *fenc, pixel *fdec, int ssd[2] ); int x264_pixel_vsad_mmx2 ( pixel *src, intptr_t stride, int height ); int x264_pixel_vsad_sse2 ( pixel *src, intptr_t stride, int height ); int x264_pixel_vsad_ssse3( pixel *src, intptr_t stride, int height ); diff --git a/library/src/main/cpp/libx264/common/x86/predict-a.asm b/library/src/main/cpp/libx264/common/x86/predict-a.asm index efc0f5a..527d9ec 100644 --- a/library/src/main/cpp/libx264/common/x86/predict-a.asm +++ b/library/src/main/cpp/libx264/common/x86/predict-a.asm @@ -468,7 +468,7 @@ PREDICT_4x4 w, wd, dq, qdq INIT_MMX mmx2 PREDICT_4x4 b, bw, wd, dq INIT_MMX ssse3 -%define predict_4x4_vr_ssse3 predict_4x4_vr_ssse3_cache64 +%define predict_4x4_vr_ssse3 predict_4x4_vr_cache64_ssse3 PREDICT_4x4 b, bw, wd, dq %endif @@ -940,7 +940,7 @@ INIT_XMM sse2 PREDICT_8x8_DDLR INIT_XMM ssse3 PREDICT_8x8_DDLR -INIT_XMM ssse3, cache64 +INIT_XMM cache64, ssse3 PREDICT_8x8_DDLR %elif ARCH_X86_64 == 0 INIT_MMX mmx2 diff --git a/library/src/main/cpp/libx264/common/x86/predict-c.c b/library/src/main/cpp/libx264/common/x86/predict-c.c index fcf8413..27da63a 100644 --- a/library/src/main/cpp/libx264/common/x86/predict-c.c +++ b/library/src/main/cpp/libx264/common/x86/predict-c.c @@ -511,8 +511,8 @@ void x264_predict_8x8_init_mmx( int cpu, x264_predict8x8_t pf[12], x264_predict_ *predict_8x8_filter = x264_predict_8x8_filter_ssse3; if( cpu&X264_CPU_CACHELINE_64 ) { - pf[I_PRED_8x8_DDL]= x264_predict_8x8_ddl_ssse3_cache64; - pf[I_PRED_8x8_DDR]= x264_predict_8x8_ddr_ssse3_cache64; + pf[I_PRED_8x8_DDL]= x264_predict_8x8_ddl_cache64_ssse3; + pf[I_PRED_8x8_DDR]= x264_predict_8x8_ddr_cache64_ssse3; } if( !(cpu&X264_CPU_AVX) ) return; @@ -604,6 +604,6 @@ void x264_predict_4x4_init_mmx( int cpu, x264_predict_t pf[12] ) pf[I_PRED_4x4_VR] = x264_predict_4x4_vr_ssse3; pf[I_PRED_4x4_HD] = x264_predict_4x4_hd_ssse3; if( cpu&X264_CPU_CACHELINE_64 ) - pf[I_PRED_4x4_VR] = x264_predict_4x4_vr_ssse3_cache64; + pf[I_PRED_4x4_VR] = x264_predict_4x4_vr_cache64_ssse3; #endif // HIGH_BIT_DEPTH } diff --git a/library/src/main/cpp/libx264/common/x86/predict.h b/library/src/main/cpp/libx264/common/x86/predict.h index ddc7de6..9f9052c 100644 --- a/library/src/main/cpp/libx264/common/x86/predict.h +++ b/library/src/main/cpp/libx264/common/x86/predict.h @@ -93,12 +93,12 @@ void x264_predict_8x8_dc_left_sse2( uint16_t *src, uint16_t edge[36] ); void x264_predict_8x8_ddl_mmx2( uint8_t *src, uint8_t edge[36] ); void x264_predict_8x8_ddl_sse2( pixel *src, pixel edge[36] ); void x264_predict_8x8_ddl_ssse3( pixel *src, pixel edge[36] ); -void x264_predict_8x8_ddl_ssse3_cache64( pixel *src, pixel edge[36] ); +void x264_predict_8x8_ddl_cache64_ssse3( pixel *src, pixel edge[36] ); void x264_predict_8x8_ddl_avx( pixel *src, pixel edge[36] ); void x264_predict_8x8_ddr_mmx2( uint8_t *src, uint8_t edge[36] ); void x264_predict_8x8_ddr_sse2( pixel *src, pixel edge[36] ); void x264_predict_8x8_ddr_ssse3( pixel *src, pixel edge[36] ); -void x264_predict_8x8_ddr_ssse3_cache64( pixel *src, pixel edge[36] ); +void x264_predict_8x8_ddr_cache64_ssse3( pixel *src, pixel edge[36] ); void x264_predict_8x8_ddr_avx( pixel *src, pixel edge[36] ); void x264_predict_8x8_vl_sse2( pixel *src, pixel edge[36] ); void x264_predict_8x8_vl_ssse3( pixel *src, pixel edge[36] ); @@ -129,7 +129,7 @@ void x264_predict_4x4_vl_avx( uint16_t *src ); void x264_predict_4x4_vr_mmx2( uint8_t *src ); void x264_predict_4x4_vr_sse2( uint16_t *src ); void x264_predict_4x4_vr_ssse3( pixel *src ); -void x264_predict_4x4_vr_ssse3_cache64( uint8_t *src ); +void x264_predict_4x4_vr_cache64_ssse3( uint8_t *src ); void x264_predict_4x4_vr_avx( uint16_t *src ); void x264_predict_4x4_hd_mmx2( pixel *src ); void x264_predict_4x4_hd_sse2( uint16_t *src ); diff --git a/library/src/main/cpp/libx264/common/x86/quant-a.asm b/library/src/main/cpp/libx264/common/x86/quant-a.asm index 2391b57..f8ebbe5 100644 --- a/library/src/main/cpp/libx264/common/x86/quant-a.asm +++ b/library/src/main/cpp/libx264/common/x86/quant-a.asm @@ -30,7 +30,14 @@ %include "x86inc.asm" %include "x86util.asm" -SECTION_RODATA 32 +SECTION_RODATA 64 + +%if HIGH_BIT_DEPTH +decimate_shuf_avx512: dd 0, 4, 8,12, 1, 5, 9,13, 2, 6,10,14, 3, 7,11,15 +%else +dequant_shuf_avx512: dw 0, 2, 4, 6, 8,10,12,14,16,18,20,22,24,26,28,30 + dw 32,34,36,38,40,42,44,46,48,50,52,54,56,58,60,62 +%endif %macro DQM4 3 dw %1, %2, %1, %2, %2, %3, %2, %3 @@ -42,14 +49,6 @@ SECTION_RODATA 32 dw %4, %2, %6, %2, %4, %2, %6, %2 %endmacro -dequant4_scale: - DQM4 10, 13, 16 - DQM4 11, 14, 18 - DQM4 13, 16, 20 - DQM4 14, 18, 23 - DQM4 16, 20, 25 - DQM4 18, 23, 29 - dequant8_scale: DQM8 20, 18, 32, 19, 25, 24 DQM8 22, 19, 35, 21, 28, 26 @@ -58,6 +57,14 @@ dequant8_scale: DQM8 32, 28, 51, 30, 40, 38 DQM8 36, 32, 58, 34, 46, 43 +dequant4_scale: + DQM4 10, 13, 16 + DQM4 11, 14, 18 + DQM4 13, 16, 20 + DQM4 14, 18, 23 + DQM4 16, 20, 25 + DQM4 18, 23, 29 + decimate_mask_table4: db 0,3,2,6,2,5,5,9,1,5,4,8,5,8,8,12,1,4,4,8,4,7,7,11,4,8,7,11,8,11,11,15,1,4 db 3,7,4,7,7,11,3,7,6,10,7,10,10,14,4,7,7,11,7,10,10,14,7,11,10,14,11,14,14 @@ -743,6 +750,163 @@ DEQUANT 4, 4, 4 DEQUANT 8, 6, 4 %endif +%macro DEQUANT_START_AVX512 1-2 0 ; shift, flat +%if %2 == 0 + movifnidn t2d, r2m +%endif + imul t0d, t2d, 0x2b + shr t0d, 8 ; i_qbits = i_qp / 6 + lea t1d, [t0*5] + sub t2d, t0d + sub t2d, t1d ; i_mf = i_qp % 6 + shl t2d, %1 +%if %2 +%ifdef PIC +%define dmf r1+t2 + lea r1, [dequant8_scale] +%else +%define dmf t2+dequant8_scale +%endif +%elif ARCH_X86_64 +%define dmf r1+t2 +%else +%define dmf r1 + add r1, r1mp ; dequant_mf[i_mf] +%endif + movifnidn r0, r0mp +%endmacro + +INIT_ZMM avx512 +cglobal dequant_4x4, 0,3 + DEQUANT_START_AVX512 6 + mova m0, [dmf] +%if HIGH_BIT_DEPTH + pmaddwd m0, [r0] +%endif + sub t0d, 4 + jl .rshift +%if HIGH_BIT_DEPTH + vpbroadcastd m1, t0d + vpsllvd m0, m1 + mova [r0], m0 +%else + vpbroadcastw ym1, t0d + vpmovsdw ym0, m0 + pmullw ym0, [r0] + vpsllvw ym0, ym1 + mova [r0], ym0 +%endif + RET +.rshift: +%if HIGH_BIT_DEPTH == 0 + pmovzxwd m1, [r0] + pmaddwd m0, m1 +%endif + mov r1d, 1<<31 + shrx r1d, r1d, t0d ; 1 << (-i_qbits-1) + neg t0d + vpbroadcastd m1, r1d + vpbroadcastd m2, t0d + paddd m0, m1 + vpsravd m0, m2 +%if HIGH_BIT_DEPTH + mova [r0], m0 +%else + vpmovsdw [r0], m0 +%endif + RET + +cglobal dequant_8x8, 0,3 + DEQUANT_START_AVX512 8 + mova m0, [dmf+0*64] + mova m1, [dmf+1*64] + mova m2, [dmf+2*64] + mova m3, [dmf+3*64] +%if HIGH_BIT_DEPTH + pmaddwd m0, [r0+0*64] + pmaddwd m1, [r0+1*64] + pmaddwd m2, [r0+2*64] + pmaddwd m3, [r0+3*64] +%else + mova m6, [dequant_shuf_avx512] +%endif + sub t0d, 6 + jl .rshift +%if HIGH_BIT_DEPTH + vpbroadcastd m4, t0d + vpsllvd m0, m4 + vpsllvd m1, m4 + vpsllvd m2, m4 + vpsllvd m3, m4 + jmp .end +.rshift: +%else + vpbroadcastw m4, t0d + vpermt2w m0, m6, m1 + vpermt2w m2, m6, m3 + pmullw m0, [r0] + pmullw m2, [r0+64] + vpsllvw m0, m4 + vpsllvw m2, m4 + mova [r0], m0 + mova [r0+64], m2 + RET +.rshift: + pmovzxwd m4, [r0+0*32] + pmovzxwd m5, [r0+1*32] + pmaddwd m0, m4 + pmaddwd m1, m5 + pmovzxwd m4, [r0+2*32] + pmovzxwd m5, [r0+3*32] + pmaddwd m2, m4 + pmaddwd m3, m5 +%endif + mov r1d, 1<<31 + shrx r1d, r1d, t0d ; 1 << (-i_qbits-1) + neg t0d + vpbroadcastd m4, r1d + vpbroadcastd m5, t0d + paddd m0, m4 + paddd m1, m4 + vpsravd m0, m5 + vpsravd m1, m5 + paddd m2, m4 + paddd m3, m4 + vpsravd m2, m5 + vpsravd m3, m5 +%if HIGH_BIT_DEPTH +.end: + mova [r0+0*64], m0 + mova [r0+1*64], m1 + mova [r0+2*64], m2 + mova [r0+3*64], m3 +%else + vpermt2w m0, m6, m1 + vpermt2w m2, m6, m3 + mova [r0], m0 + mova [r0+64], m2 +%endif + RET + +%if HIGH_BIT_DEPTH == 0 +cglobal dequant_8x8_flat16, 0,3 + movifnidn t2d, r2m + cmp t2d, 12 + jl dequant_8x8_avx512 + sub t2d, 12 + DEQUANT_START_AVX512 6, 1 + vpbroadcastw m0, t0d + mova m1, [dmf] + vpsllvw m1, m0 + pmullw m0, m1, [r0] + pmullw m1, [r0+64] + mova [r0], m0 + mova [r0+64], m1 + RET +%endif + +%undef dmf + %macro DEQUANT_DC 2 cglobal dequant_4x4dc, 0,3,6 DEQUANT_START 6, 6 @@ -1208,13 +1372,12 @@ cglobal denoise_dct, 4,4,4 ; int decimate_score( dctcoef *dct ) ;----------------------------------------------------------------------------- -%macro DECIMATE_MASK 5 -%if mmsize==16 +%macro DECIMATE_MASK 4 %if HIGH_BIT_DEPTH - movdqa m0, [%3+ 0] - movdqa m1, [%3+32] - packssdw m0, [%3+16] - packssdw m1, [%3+48] + mova m0, [%3+0*16] + packssdw m0, [%3+1*16] + mova m1, [%3+2*16] + packssdw m1, [%3+3*16] ABSW2 m0, m1, m0, m1, m3, m4 %else ABSW m0, [%3+ 0], m3 @@ -1226,40 +1389,35 @@ cglobal denoise_dct, 4,4,4 pcmpgtb m0, %4 pmovmskb %1, m2 pmovmskb %2, m0 -%else ; mmsize==8 +%endmacro + +%macro DECIMATE_MASK16_AVX512 0 + mova m0, [r0] %if HIGH_BIT_DEPTH - movq m0, [%3+ 0] - movq m1, [%3+16] - movq m2, [%3+32] - movq m3, [%3+48] - packssdw m0, [%3+ 8] - packssdw m1, [%3+24] - packssdw m2, [%3+40] - packssdw m3, [%3+56] -%else - movq m0, [%3+ 0] - movq m1, [%3+ 8] - movq m2, [%3+16] - movq m3, [%3+24] -%endif - ABSW2 m0, m1, m0, m1, m6, m7 - ABSW2 m2, m3, m2, m3, m6, m7 - packsswb m0, m1 - packsswb m2, m3 - pxor m4, m4 - pxor m6, m6 - pcmpeqb m4, m0 - pcmpeqb m6, m2 - pcmpgtb m0, %4 - pcmpgtb m2, %4 - pmovmskb %5, m4 - pmovmskb %1, m6 - shl %1, 8 - or %1, %5 - pmovmskb %5, m0 - pmovmskb %2, m2 - shl %2, 8 - or %2, %5 + vptestmd k0, m0, m0 + pabsd m0, m0 + vpcmpud k1, m0, [pd_1] {1to16}, 6 +%else + vptestmw k0, m0, m0 + pabsw m0, m0 + vpcmpuw k1, m0, [pw_1], 6 +%endif +%endmacro + +%macro SHRX 2 +%if cpuflag(bmi2) + shrx %1, %1, %2 +%else + shr %1, %2b ; %2 has to be rcx/ecx +%endif +%endmacro + +%macro BLSR 2 +%if cpuflag(bmi1) + blsr %1, %2 +%else + lea %1, [%2-1] + and %1, %2 %endif %endmacro @@ -1269,33 +1427,60 @@ cextern decimate_table8 %macro DECIMATE4x4 1 cglobal decimate_score%1, 1,3 -%ifdef PIC - lea r4, [decimate_table4] - lea r5, [decimate_mask_table4] - %define table r4 - %define mask_table r5 +%if cpuflag(avx512) + DECIMATE_MASK16_AVX512 + xor eax, eax + kmovw edx, k0 +%if %1 == 15 + shr edx, 1 %else - %define table decimate_table4 - %define mask_table decimate_mask_table4 + test edx, edx %endif - DECIMATE_MASK edx, eax, r0, [pb_1], ecx + jz .ret + ktestw k1, k1 + jnz .ret9 +%else + DECIMATE_MASK edx, eax, r0, [pb_1] xor edx, 0xffff - je .ret + jz .ret test eax, eax - jne .ret9 -%if %1==15 + jnz .ret9 +%if %1 == 15 shr edx, 1 +%endif +%endif +%ifdef PIC + lea r4, [decimate_mask_table4] + %define mask_table r4 +%else + %define mask_table decimate_mask_table4 %endif movzx ecx, dl movzx eax, byte [mask_table + rcx] +%if ARCH_X86_64 + xor edx, ecx + jz .ret +%if cpuflag(lzcnt) + lzcnt ecx, ecx + lea r5, [decimate_table4-32] + add r5, rcx +%else + bsr ecx, ecx + lea r5, [decimate_table4-1] + sub r5, rcx +%endif + %define table r5 +%else cmp edx, ecx - je .ret + jz .ret bsr ecx, ecx shr edx, 1 - shr edx, cl + SHRX edx, ecx + %define table decimate_table4 +%endif tzcnt ecx, edx shr edx, 1 - shr edx, cl + SHRX edx, ecx add al, byte [table + rcx] add al, byte [mask_table + rdx] .ret: @@ -1303,175 +1488,224 @@ cglobal decimate_score%1, 1,3 .ret9: mov eax, 9 RET - %endmacro -%if ARCH_X86_64 == 0 -INIT_MMX mmx2 -DECIMATE4x4 15 -DECIMATE4x4 16 -%endif -INIT_XMM sse2 -DECIMATE4x4 15 -DECIMATE4x4 16 -INIT_XMM ssse3 -DECIMATE4x4 15 -DECIMATE4x4 16 - -; 2x gt1 output, 2x nz output, 1x mask -%macro DECIMATE_MASK64_AVX2 5 - pabsw m0, [r0+ 0] - pabsw m2, [r0+32] - pabsw m1, [r0+64] - pabsw m3, [r0+96] - packsswb m0, m2 - packsswb m1, m3 - pcmpgtb m2, m0, %5 ; the > 1 checks don't care about order, so - pcmpgtb m3, m1, %5 ; we can save latency by doing them here - pmovmskb %1, m2 - pmovmskb %2, m3 - or %1, %2 - jne .ret9 +%macro DECIMATE_MASK64_AVX2 2 ; nz_low, nz_high + mova m0, [r0+0*32] + packsswb m0, [r0+1*32] + mova m1, [r0+2*32] + packsswb m1, [r0+3*32] + mova m4, [pb_1] + pabsb m2, m0 + pabsb m3, m1 + por m2, m3 ; the > 1 checks don't care about order, so + ptest m4, m2 ; we can save latency by doing them here + jnc .ret9 vpermq m0, m0, q3120 vpermq m1, m1, q3120 pxor m4, m4 pcmpeqb m0, m4 pcmpeqb m1, m4 - pmovmskb %3, m0 - pmovmskb %4, m1 + pmovmskb %1, m0 + pmovmskb %2, m1 %endmacro -%macro DECIMATE8x8 0 +%macro DECIMATE_MASK64_AVX512 0 + mova m0, [r0] +%if HIGH_BIT_DEPTH + packssdw m0, [r0+1*64] + mova m1, [r0+2*64] + packssdw m1, [r0+3*64] + packsswb m0, m1 + vbroadcasti32x4 m1, [pb_1] + pabsb m2, m0 + vpcmpub k0, m2, m1, 6 + ktestq k0, k0 + jnz .ret9 + mova m1, [decimate_shuf_avx512] + vpermd m0, m1, m0 + vptestmb k1, m0, m0 +%else + mova m1, [r0+64] + vbroadcasti32x4 m3, [pb_1] + packsswb m2, m0, m1 + pabsb m2, m2 + vpcmpub k0, m2, m3, 6 + ktestq k0, k0 + jnz .ret9 + vptestmw k1, m0, m0 + vptestmw k2, m1, m1 +%endif +%endmacro +%macro DECIMATE8x8 0 %if ARCH_X86_64 cglobal decimate_score64, 1,5 +%if mmsize == 64 + DECIMATE_MASK64_AVX512 + xor eax, eax +%if HIGH_BIT_DEPTH + kmovq r1, k1 + test r1, r1 + jz .ret +%else + kortestd k1, k2 + jz .ret + kunpckdq k1, k2, k1 + kmovq r1, k1 +%endif +%elif mmsize == 32 + DECIMATE_MASK64_AVX2 r1d, eax + not r1 + shl rax, 32 + xor r1, rax + jz .ret +%else + mova m5, [pb_1] + DECIMATE_MASK r1d, eax, r0+SIZEOF_DCTCOEF* 0, m5 + test eax, eax + jnz .ret9 + DECIMATE_MASK r2d, eax, r0+SIZEOF_DCTCOEF*16, m5 + shl r2d, 16 + or r1d, r2d + DECIMATE_MASK r2d, r3d, r0+SIZEOF_DCTCOEF*32, m5 + shl r2, 32 + or eax, r3d + or r1, r2 + DECIMATE_MASK r2d, r3d, r0+SIZEOF_DCTCOEF*48, m5 + not r1 + shl r2, 48 + xor r1, r2 + jz .ret + add eax, r3d + jnz .ret9 +%endif %ifdef PIC lea r4, [decimate_table8] %define table r4 %else %define table decimate_table8 %endif - mova m5, [pb_1] -%if mmsize==32 - DECIMATE_MASK64_AVX2 eax, r2d, r1d, r3d, m5 - shl r3, 32 - or r1, r3 - xor r1, -1 - je .ret -%else - DECIMATE_MASK r1d, eax, r0+SIZEOF_DCTCOEF* 0, m5, null - test eax, eax - jne .ret9 - DECIMATE_MASK r2d, eax, r0+SIZEOF_DCTCOEF*16, m5, null - shl r2d, 16 - or r1d, r2d - DECIMATE_MASK r2d, r3d, r0+SIZEOF_DCTCOEF*32, m5, null - shl r2, 32 - or eax, r3d - or r1, r2 - DECIMATE_MASK r2d, r3d, r0+SIZEOF_DCTCOEF*48, m5, null - shl r2, 48 - or r1, r2 - xor r1, -1 - je .ret - add eax, r3d - jne .ret9 -%endif - mov al, -6 + mov al, -6 .loop: tzcnt rcx, r1 - shr r1, cl - add al, byte [table + rcx] - jge .ret9 - shr r1, 1 - jne .loop - add al, 6 + add al, byte [table + rcx] + jge .ret9 + shr r1, 1 + SHRX r1, rcx +%if cpuflag(bmi2) + test r1, r1 +%endif + jnz .loop + add al, 6 .ret: REP_RET .ret9: - mov eax, 9 + mov eax, 9 RET %else ; ARCH -%if mmsize == 8 -cglobal decimate_score64, 1,6 +cglobal decimate_score64, 1,4 +%if mmsize == 64 + DECIMATE_MASK64_AVX512 + xor eax, eax +%if HIGH_BIT_DEPTH + kshiftrq k2, k1, 32 +%endif + kmovd r2, k1 + kmovd r3, k2 + test r2, r2 + jz .tryret +%elif mmsize == 32 + DECIMATE_MASK64_AVX2 r2, r3 + xor eax, eax + not r3 + xor r2, -1 + jz .tryret %else -cglobal decimate_score64, 1,5 -%endif - mova m5, [pb_1] -%if mmsize==32 - DECIMATE_MASK64_AVX2 r0, r2, r3, r4, m5 - xor r3, -1 - je .tryret - xor r4, -1 -.cont: -%else - DECIMATE_MASK r3, r2, r0+SIZEOF_DCTCOEF* 0, m5, r5 - test r2, r2 - jne .ret9 - DECIMATE_MASK r4, r2, r0+SIZEOF_DCTCOEF*16, m5, r5 - shl r4, 16 - or r3, r4 - DECIMATE_MASK r4, r1, r0+SIZEOF_DCTCOEF*32, m5, r5 - or r2, r1 - DECIMATE_MASK r1, r0, r0+SIZEOF_DCTCOEF*48, m5, r5 - shl r1, 16 - or r4, r1 - xor r3, -1 - je .tryret - xor r4, -1 -.cont: - add r0, r2 - jne .ret9 -%endif - mov al, -6 + mova m5, [pb_1] + DECIMATE_MASK r2, r1, r0+SIZEOF_DCTCOEF* 0, m5 + test r1, r1 + jnz .ret9 + DECIMATE_MASK r3, r1, r0+SIZEOF_DCTCOEF*16, m5 + not r2 + shl r3, 16 + xor r2, r3 + mov r0m, r2 + DECIMATE_MASK r3, r2, r0+SIZEOF_DCTCOEF*32, m5 + or r2, r1 + DECIMATE_MASK r1, r0, r0+SIZEOF_DCTCOEF*48, m5 + add r0, r2 + jnz .ret9 + mov r2, r0m + not r3 + shl r1, 16 + xor r3, r1 + test r2, r2 + jz .tryret +%endif + mov al, -6 .loop: + tzcnt ecx, r2 + add al, byte [decimate_table8 + ecx] + jge .ret9 + sub ecx, 31 ; increase the shift count by one to shift away the lowest set bit as well + jz .run31 ; only bits 0-4 are used so we have to explicitly handle the case of 1<<31 + shrd r2, r3, cl + SHRX r3, ecx +%if notcpuflag(bmi2) + test r2, r2 +%endif + jnz .loop + BLSR r2, r3 + jz .end +.largerun: tzcnt ecx, r3 - test r3, r3 - je .largerun - shrd r3, r4, cl - shr r4, cl - add al, byte [decimate_table8 + ecx] - jge .ret9 - shrd r3, r4, 1 - shr r4, 1 - test r3, r3 - jne .loop - test r4, r4 - jne .loop - add al, 6 -.ret: - REP_RET -.tryret: - xor r4, -1 - jne .cont + shr r3, 1 + SHRX r3, ecx +.loop2: + tzcnt ecx, r3 + add al, byte [decimate_table8 + ecx] + jge .ret9 + shr r3, 1 + SHRX r3, ecx +.run31: + test r3, r3 + jnz .loop2 +.end: + add al, 6 RET +.tryret: + BLSR r2, r3 + jz .ret + mov al, -6 + jmp .largerun .ret9: mov eax, 9 - RET -.largerun: - mov r3, r4 - xor r4, r4 - tzcnt ecx, r3 - shr r3, cl - shr r3, 1 - jne .loop - add al, 6 - RET +.ret: + REP_RET %endif ; ARCH - %endmacro -%if ARCH_X86_64 == 0 -INIT_MMX mmx2 -DECIMATE8x8 -%endif INIT_XMM sse2 +DECIMATE4x4 15 +DECIMATE4x4 16 DECIMATE8x8 INIT_XMM ssse3 +DECIMATE4x4 15 +DECIMATE4x4 16 DECIMATE8x8 +%if HIGH_BIT_DEPTH +INIT_ZMM avx512 +%else INIT_YMM avx2 DECIMATE8x8 +INIT_YMM avx512 +%endif +DECIMATE4x4 15 +DECIMATE4x4 16 +INIT_ZMM avx512 +DECIMATE8x8 ;----------------------------------------------------------------------------- ; int coeff_last( dctcoef *dct ) @@ -1556,7 +1790,7 @@ cglobal coeff_last4, 1,3 INIT_MMX mmx2 COEFF_LAST4 -INIT_MMX mmx2, lzcnt +INIT_MMX lzcnt COEFF_LAST4 %macro COEFF_LAST8 0 @@ -1579,7 +1813,7 @@ COEFF_LAST8 %endif INIT_XMM sse2 COEFF_LAST8 -INIT_XMM sse2, lzcnt +INIT_XMM lzcnt COEFF_LAST8 %else ; !HIGH_BIT_DEPTH @@ -1642,7 +1876,7 @@ cglobal coeff_last8, 1,3 INIT_MMX mmx2 COEFF_LAST48 -INIT_MMX mmx2, lzcnt +INIT_MMX lzcnt COEFF_LAST48 %endif ; HIGH_BIT_DEPTH @@ -1707,7 +1941,7 @@ COEFF_LAST %endif INIT_XMM sse2 COEFF_LAST -INIT_XMM sse2, lzcnt +INIT_XMM lzcnt COEFF_LAST %macro LAST_MASK_AVX2 2 @@ -1729,7 +1963,7 @@ COEFF_LAST %endmacro %if ARCH_X86_64 == 0 -INIT_YMM avx2,lzcnt +INIT_YMM avx2 cglobal coeff_last64, 1,2 pxor m2, m2 LAST_MASK_AVX2 r1d, r0+SIZEOF_DCTCOEF*32 @@ -1744,7 +1978,7 @@ cglobal coeff_last64, 1,2 add eax, 32 RET %else -INIT_YMM avx2,lzcnt +INIT_YMM avx2 cglobal coeff_last64, 1,3 pxor m2, m2 LAST_MASK_AVX2 r1d, r0+SIZEOF_DCTCOEF* 0 @@ -1756,6 +1990,70 @@ cglobal coeff_last64, 1,3 RET %endif +%macro COEFF_LAST_AVX512 2 ; num, w/d +cglobal coeff_last%1, 1,2 + mova m0, [r0-(%1&1)*SIZEOF_DCTCOEF] + vptestm%2 k0, m0, m0 +%if %1 == 15 + mov eax, 30 + kmovw r1d, k0 + lzcnt r1d, r1d + sub eax, r1d +%else + kmovw eax, k0 + lzcnt eax, eax + xor eax, 31 +%endif + RET +%endmacro + +%macro COEFF_LAST64_AVX512 1 ; w/d +cglobal coeff_last64, 1,2 + pxor xm0, xm0 + vpcmp%1 k0, m0, [r0+0*64], 4 + vpcmp%1 k1, m0, [r0+1*64], 4 +%if HIGH_BIT_DEPTH + vpcmp%1 k2, m0, [r0+2*64], 4 + vpcmp%1 k3, m0, [r0+3*64], 4 + kunpckwd k0, k1, k0 + kunpckwd k1, k3, k2 +%endif +%if ARCH_X86_64 + kunpckdq k0, k1, k0 + kmovq rax, k0 + lzcnt rax, rax + xor eax, 63 +%else + kmovd r1d, k1 + kmovd eax, k0 + lzcnt r1d, r1d + lzcnt eax, eax + xor r1d, 32 + cmovnz eax, r1d + xor eax, 31 +%endif + RET +%endmacro + +%if HIGH_BIT_DEPTH +INIT_XMM avx512 +COEFF_LAST_AVX512 4, d +INIT_YMM avx512 +COEFF_LAST_AVX512 8, d +INIT_ZMM avx512 +COEFF_LAST_AVX512 15, d +COEFF_LAST_AVX512 16, d +COEFF_LAST64_AVX512 d +%else ; !HIGH_BIT_DEPTH +INIT_XMM avx512 +COEFF_LAST_AVX512 8, w +INIT_YMM avx512 +COEFF_LAST_AVX512 15, w +COEFF_LAST_AVX512 16, w +INIT_ZMM avx512 +COEFF_LAST64_AVX512 w +%endif ; !HIGH_BIT_DEPTH + ;----------------------------------------------------------------------------- ; int coeff_level_run( dctcoef *dct, run_level_t *runlevel ) ;----------------------------------------------------------------------------- @@ -1833,15 +2131,17 @@ COEFF_LEVELRUN 8 %endif COEFF_LEVELRUN 15 COEFF_LEVELRUN 16 -INIT_XMM sse2, lzcnt +INIT_MMX lzcnt +COEFF_LEVELRUN 4 +%if HIGH_BIT_DEPTH == 0 +COEFF_LEVELRUN 8 +%endif +INIT_XMM lzcnt %if HIGH_BIT_DEPTH COEFF_LEVELRUN 8 %endif COEFF_LEVELRUN 15 COEFF_LEVELRUN 16 -INIT_MMX mmx2, lzcnt -COEFF_LEVELRUN 4 -COEFF_LEVELRUN 8 ; Similar to the one above, but saves the DCT ; coefficients in m0/m1 so we don't have to load @@ -1968,7 +2268,7 @@ INIT_XMM ssse3, lzcnt COEFF_LEVELRUN_LUT 8 COEFF_LEVELRUN_LUT 15 COEFF_LEVELRUN_LUT 16 -INIT_XMM avx2, lzcnt +INIT_XMM avx2 COEFF_LEVELRUN_LUT 15 COEFF_LEVELRUN_LUT 16 %endif diff --git a/library/src/main/cpp/libx264/common/x86/quant.h b/library/src/main/cpp/libx264/common/x86/quant.h index 9596a58..6b74aac 100644 --- a/library/src/main/cpp/libx264/common/x86/quant.h +++ b/library/src/main/cpp/libx264/common/x86/quant.h @@ -66,12 +66,15 @@ void x264_dequant_8x8_xop( dctcoef dct[64], int dequant_mf[6][64], int i_qp ); void x264_dequant_4x4_avx2( dctcoef dct[16], int dequant_mf[6][16], int i_qp ); void x264_dequant_4x4dc_avx2( dctcoef dct[16], int dequant_mf[6][16], int i_qp ); void x264_dequant_8x8_avx2( dctcoef dct[64], int dequant_mf[6][64], int i_qp ); +void x264_dequant_4x4_avx512( dctcoef dct[16], int dequant_mf[6][16], int i_qp ); +void x264_dequant_8x8_avx512( dctcoef dct[64], int dequant_mf[6][64], int i_qp ); void x264_dequant_4x4_flat16_mmx( int16_t dct[16], int dequant_mf[6][16], int i_qp ); void x264_dequant_8x8_flat16_mmx( int16_t dct[64], int dequant_mf[6][64], int i_qp ); void x264_dequant_4x4_flat16_sse2( int16_t dct[16], int dequant_mf[6][16], int i_qp ); void x264_dequant_8x8_flat16_sse2( int16_t dct[64], int dequant_mf[6][64], int i_qp ); void x264_dequant_4x4_flat16_avx2( int16_t dct[16], int dequant_mf[6][16], int i_qp ); void x264_dequant_8x8_flat16_avx2( int16_t dct[64], int dequant_mf[6][64], int i_qp ); +void x264_dequant_8x8_flat16_avx512( int16_t dct[64], int dequant_mf[6][64], int i_qp ); void x264_idct_dequant_2x4_dc_sse2( dctcoef dct[8], dctcoef dct4x4[8][16], int dequant_mf[6][16], int i_qp ); void x264_idct_dequant_2x4_dc_avx ( dctcoef dct[8], dctcoef dct4x4[8][16], int dequant_mf[6][16], int i_qp ); void x264_idct_dequant_2x4_dconly_sse2( dctcoef dct[8], int dequant_mf[6][16], int i_qp ); @@ -85,16 +88,16 @@ void x264_denoise_dct_sse2 ( dctcoef *dct, uint32_t *sum, udctcoef *offset, int void x264_denoise_dct_ssse3( dctcoef *dct, uint32_t *sum, udctcoef *offset, int size ); void x264_denoise_dct_avx ( dctcoef *dct, uint32_t *sum, udctcoef *offset, int size ); void x264_denoise_dct_avx2 ( dctcoef *dct, uint32_t *sum, udctcoef *offset, int size ); -int x264_decimate_score15_mmx2( dctcoef *dct ); int x264_decimate_score15_sse2( dctcoef *dct ); int x264_decimate_score15_ssse3( dctcoef *dct ); -int x264_decimate_score16_mmx2( dctcoef *dct ); +int x264_decimate_score15_avx512( dctcoef *dct ); int x264_decimate_score16_sse2( dctcoef *dct ); int x264_decimate_score16_ssse3( dctcoef *dct ); -int x264_decimate_score64_mmx2( dctcoef *dct ); +int x264_decimate_score16_avx512( dctcoef *dct ); int x264_decimate_score64_sse2( dctcoef *dct ); int x264_decimate_score64_ssse3( dctcoef *dct ); int x264_decimate_score64_avx2( int16_t *dct ); +int x264_decimate_score64_avx512( dctcoef *dct ); int x264_coeff_last4_mmx2( dctcoef *dct ); int x264_coeff_last8_mmx2( dctcoef *dct ); int x264_coeff_last15_mmx2( dctcoef *dct ); @@ -104,33 +107,37 @@ int x264_coeff_last8_sse2( dctcoef *dct ); int x264_coeff_last15_sse2( dctcoef *dct ); int x264_coeff_last16_sse2( dctcoef *dct ); int x264_coeff_last64_sse2( dctcoef *dct ); -int x264_coeff_last4_mmx2_lzcnt( dctcoef *dct ); -int x264_coeff_last8_mmx2_lzcnt( dctcoef *dct ); -int x264_coeff_last8_sse2_lzcnt( dctcoef *dct ); -int x264_coeff_last15_sse2_lzcnt( dctcoef *dct ); -int x264_coeff_last16_sse2_lzcnt( dctcoef *dct ); -int x264_coeff_last64_sse2_lzcnt( dctcoef *dct ); -int x264_coeff_last64_avx2_lzcnt( dctcoef *dct ); +int x264_coeff_last4_lzcnt( dctcoef *dct ); +int x264_coeff_last8_lzcnt( dctcoef *dct ); +int x264_coeff_last15_lzcnt( dctcoef *dct ); +int x264_coeff_last16_lzcnt( dctcoef *dct ); +int x264_coeff_last64_lzcnt( dctcoef *dct ); +int x264_coeff_last64_avx2 ( dctcoef *dct ); +int x264_coeff_last4_avx512( int32_t *dct ); +int x264_coeff_last8_avx512( dctcoef *dct ); +int x264_coeff_last15_avx512( dctcoef *dct ); +int x264_coeff_last16_avx512( dctcoef *dct ); +int x264_coeff_last64_avx512( dctcoef *dct ); int x264_coeff_level_run16_mmx2( dctcoef *dct, x264_run_level_t *runlevel ); int x264_coeff_level_run16_sse2( dctcoef *dct, x264_run_level_t *runlevel ); -int x264_coeff_level_run16_sse2_lzcnt( dctcoef *dct, x264_run_level_t *runlevel ); +int x264_coeff_level_run16_lzcnt( dctcoef *dct, x264_run_level_t *runlevel ); int x264_coeff_level_run16_ssse3( dctcoef *dct, x264_run_level_t *runlevel ); int x264_coeff_level_run16_ssse3_lzcnt( dctcoef *dct, x264_run_level_t *runlevel ); -int x264_coeff_level_run16_avx2_lzcnt( dctcoef *dct, x264_run_level_t *runlevel ); +int x264_coeff_level_run16_avx2( dctcoef *dct, x264_run_level_t *runlevel ); int x264_coeff_level_run15_mmx2( dctcoef *dct, x264_run_level_t *runlevel ); int x264_coeff_level_run15_sse2( dctcoef *dct, x264_run_level_t *runlevel ); -int x264_coeff_level_run15_sse2_lzcnt( dctcoef *dct, x264_run_level_t *runlevel ); +int x264_coeff_level_run15_lzcnt( dctcoef *dct, x264_run_level_t *runlevel ); int x264_coeff_level_run15_ssse3( dctcoef *dct, x264_run_level_t *runlevel ); int x264_coeff_level_run15_ssse3_lzcnt( dctcoef *dct, x264_run_level_t *runlevel ); -int x264_coeff_level_run15_avx2_lzcnt( dctcoef *dct, x264_run_level_t *runlevel ); +int x264_coeff_level_run15_avx2( dctcoef *dct, x264_run_level_t *runlevel ); int x264_coeff_level_run4_mmx2( dctcoef *dct, x264_run_level_t *runlevel ); -int x264_coeff_level_run4_mmx2_lzcnt( dctcoef *dct, x264_run_level_t *runlevel ); +int x264_coeff_level_run4_lzcnt( dctcoef *dct, x264_run_level_t *runlevel ); int x264_coeff_level_run4_ssse3( dctcoef *dct, x264_run_level_t *runlevel ); int x264_coeff_level_run4_ssse3_lzcnt( dctcoef *dct, x264_run_level_t *runlevel ); int x264_coeff_level_run8_mmx2( dctcoef *dct, x264_run_level_t *runlevel ); -int x264_coeff_level_run8_mmx2_lzcnt( dctcoef *dct, x264_run_level_t *runlevel ); +int x264_coeff_level_run8_lzcnt( dctcoef *dct, x264_run_level_t *runlevel ); int x264_coeff_level_run8_sse2( dctcoef *dct, x264_run_level_t *runlevel ); -int x264_coeff_level_run8_sse2_lzcnt( dctcoef *dct, x264_run_level_t *runlevel ); +int x264_coeff_level_run8_lzcnt( dctcoef *dct, x264_run_level_t *runlevel ); int x264_coeff_level_run8_ssse3( dctcoef *dct, x264_run_level_t *runlevel ); int x264_coeff_level_run8_ssse3_lzcnt( dctcoef *dct, x264_run_level_t *runlevel ); int x264_trellis_cabac_4x4_sse2 ( TRELLIS_PARAMS, int b_ac ); diff --git a/library/src/main/cpp/libx264/common/x86/sad-a.asm b/library/src/main/cpp/libx264/common/x86/sad-a.asm index ede52ae..8029e11 100644 --- a/library/src/main/cpp/libx264/common/x86/sad-a.asm +++ b/library/src/main/cpp/libx264/common/x86/sad-a.asm @@ -106,8 +106,6 @@ SAD 4, 16 SAD 4, 8 SAD 4, 4 - - ;============================================================================= ; SAD XMM ;============================================================================= @@ -119,118 +117,64 @@ SAD 4, 4 RET %endmacro -%macro SAD_W16 0 ;----------------------------------------------------------------------------- ; int pixel_sad_16x16( uint8_t *, intptr_t, uint8_t *, intptr_t ) ;----------------------------------------------------------------------------- -cglobal pixel_sad_16x16, 4,4,8 - movu m0, [r2] - movu m1, [r2+r3] - lea r2, [r2+2*r3] - movu m2, [r2] - movu m3, [r2+r3] - lea r2, [r2+2*r3] - psadbw m0, [r0] - psadbw m1, [r0+r1] - lea r0, [r0+2*r1] - movu m4, [r2] - paddw m0, m1 - psadbw m2, [r0] - psadbw m3, [r0+r1] - lea r0, [r0+2*r1] - movu m5, [r2+r3] - lea r2, [r2+2*r3] - paddw m2, m3 - movu m6, [r2] - movu m7, [r2+r3] - lea r2, [r2+2*r3] - paddw m0, m2 - psadbw m4, [r0] - psadbw m5, [r0+r1] - lea r0, [r0+2*r1] - movu m1, [r2] - paddw m4, m5 - psadbw m6, [r0] - psadbw m7, [r0+r1] - lea r0, [r0+2*r1] - movu m2, [r2+r3] - lea r2, [r2+2*r3] - paddw m6, m7 - movu m3, [r2] - paddw m0, m4 - movu m4, [r2+r3] - lea r2, [r2+2*r3] - paddw m0, m6 - psadbw m1, [r0] - psadbw m2, [r0+r1] - lea r0, [r0+2*r1] - movu m5, [r2] - paddw m1, m2 - psadbw m3, [r0] - psadbw m4, [r0+r1] - lea r0, [r0+2*r1] - movu m6, [r2+r3] - lea r2, [r2+2*r3] - paddw m3, m4 - movu m7, [r2] - paddw m0, m1 - movu m1, [r2+r3] - paddw m0, m3 - psadbw m5, [r0] - psadbw m6, [r0+r1] - lea r0, [r0+2*r1] - paddw m5, m6 - psadbw m7, [r0] - psadbw m1, [r0+r1] - paddw m7, m1 - paddw m0, m5 - paddw m0, m7 - SAD_END_SSE2 - -;----------------------------------------------------------------------------- -; int pixel_sad_16x8( uint8_t *, intptr_t, uint8_t *, intptr_t ) -;----------------------------------------------------------------------------- -cglobal pixel_sad_16x8, 4,4 - movu m0, [r2] - movu m2, [r2+r3] - lea r2, [r2+2*r3] - movu m3, [r2] - movu m4, [r2+r3] - psadbw m0, [r0] - psadbw m2, [r0+r1] - lea r0, [r0+2*r1] - psadbw m3, [r0] - psadbw m4, [r0+r1] - lea r0, [r0+2*r1] - lea r2, [r2+2*r3] - paddw m0, m2 - paddw m3, m4 - paddw m0, m3 - movu m1, [r2] - movu m2, [r2+r3] - lea r2, [r2+2*r3] - movu m3, [r2] - movu m4, [r2+r3] - psadbw m1, [r0] - psadbw m2, [r0+r1] - lea r0, [r0+2*r1] - psadbw m3, [r0] - psadbw m4, [r0+r1] - lea r0, [r0+2*r1] - lea r2, [r2+2*r3] - paddw m1, m2 - paddw m3, m4 - paddw m0, m1 - paddw m0, m3 +%macro SAD_W16 1 ; h +cglobal pixel_sad_16x%1, 4,4 +%ifidn cpuname, sse2 +.skip_prologue: +%endif +%assign %%i 0 +%if ARCH_X86_64 + lea r6, [3*r1] ; r6 results in fewer REX prefixes than r4 and both are volatile + lea r5, [3*r3] +%rep %1/4 + movu m1, [r2] + psadbw m1, [r0] + movu m3, [r2+r3] + psadbw m3, [r0+r1] + movu m2, [r2+2*r3] + psadbw m2, [r0+2*r1] + movu m4, [r2+r5] + psadbw m4, [r0+r6] +%if %%i != %1/4-1 + lea r2, [r2+4*r3] + lea r0, [r0+4*r1] +%endif + paddw m1, m3 + paddw m2, m4 + ACCUM paddw, 0, 1, %%i + paddw m0, m2 + %assign %%i %%i+1 +%endrep +%else ; The cost of having to save and restore registers on x86-32 +%rep %1/2 ; nullifies the benefit of having 3*stride in registers. + movu m1, [r2] + psadbw m1, [r0] + movu m2, [r2+r3] + psadbw m2, [r0+r1] +%if %%i != %1/2-1 + lea r2, [r2+2*r3] + lea r0, [r0+2*r1] +%endif + ACCUM paddw, 0, 1, %%i + paddw m0, m2 + %assign %%i %%i+1 +%endrep +%endif SAD_END_SSE2 %endmacro INIT_XMM sse2 -SAD_W16 +SAD_W16 16 +SAD_W16 8 INIT_XMM sse3 -SAD_W16 +SAD_W16 16 +SAD_W16 8 INIT_XMM sse2, aligned -SAD_W16 +SAD_W16 16 +SAD_W16 8 %macro SAD_INC_4x8P_SSE 1 movq m1, [r0] @@ -259,7 +203,132 @@ cglobal pixel_sad_8x16_sse2, 4,4 SAD_INC_4x8P_SSE 1 SAD_INC_4x8P_SSE 1 SAD_END_SSE2 + +%macro SAD_W48_AVX512 3 ; w, h, d/q +cglobal pixel_sad_%1x%2, 4,4 + kxnorb k1, k1, k1 + kaddb k1, k1, k1 +%assign %%i 0 +%if ARCH_X86_64 && %2 != 4 + lea r6, [3*r1] + lea r5, [3*r3] +%rep %2/4 + mov%3 m1, [r0] + vpbroadcast%3 m1 {k1}, [r0+r1] + mov%3 m3, [r2] + vpbroadcast%3 m3 {k1}, [r2+r3] + mov%3 m2, [r0+2*r1] + vpbroadcast%3 m2 {k1}, [r0+r6] + mov%3 m4, [r2+2*r3] + vpbroadcast%3 m4 {k1}, [r2+r5] +%if %%i != %2/4-1 + lea r0, [r0+4*r1] + lea r2, [r2+4*r3] +%endif + psadbw m1, m3 + psadbw m2, m4 + ACCUM paddd, 0, 1, %%i + paddd m0, m2 + %assign %%i %%i+1 +%endrep +%else +%rep %2/2 + mov%3 m1, [r0] + vpbroadcast%3 m1 {k1}, [r0+r1] + mov%3 m2, [r2] + vpbroadcast%3 m2 {k1}, [r2+r3] +%if %%i != %2/2-1 + lea r0, [r0+2*r1] + lea r2, [r2+2*r3] +%endif + psadbw m1, m2 + ACCUM paddd, 0, 1, %%i + %assign %%i %%i+1 +%endrep +%endif +%if %1 == 8 + punpckhqdq m1, m0, m0 + paddd m0, m1 +%endif + movd eax, m0 + RET +%endmacro + +INIT_XMM avx512 +SAD_W48_AVX512 4, 4, d +SAD_W48_AVX512 4, 8, d +SAD_W48_AVX512 4, 16, d +SAD_W48_AVX512 8, 4, q +SAD_W48_AVX512 8, 8, q +SAD_W48_AVX512 8, 16, q + +%macro SAD_W16_AVX512_START 1 ; h + cmp r1d, FENC_STRIDE ; optimized for the most common fenc case, which + jne pixel_sad_16x%1_sse2.skip_prologue ; has the rows laid out contiguously in memory + lea r1, [3*r3] +%endmacro + +%macro SAD_W16_AVX512_END 0 + paddd m0, m1 + paddd m0, m2 + paddd m0, m3 +%if mmsize == 64 + vextracti32x8 ym1, m0, 1 + paddd ym0, ym1 +%endif + vextracti128 xm1, ym0, 1 + paddd xmm0, xm0, xm1 + punpckhqdq xmm1, xmm0, xmm0 + paddd xmm0, xmm1 + movd eax, xmm0 RET +%endmacro + +INIT_YMM avx512 +cglobal pixel_sad_16x8, 4,4 + SAD_W16_AVX512_START 8 + movu xm0, [r2] + vinserti128 m0, [r2+r3], 1 + psadbw m0, [r0+0*32] + movu xm1, [r2+2*r3] + vinserti128 m1, [r2+r1], 1 + lea r2, [r2+4*r3] + psadbw m1, [r0+1*32] + movu xm2, [r2] + vinserti128 m2, [r2+r3], 1 + psadbw m2, [r0+2*32] + movu xm3, [r2+2*r3] + vinserti128 m3, [r2+r1], 1 + psadbw m3, [r0+3*32] + SAD_W16_AVX512_END + +INIT_ZMM avx512 +cglobal pixel_sad_16x16, 4,4 + SAD_W16_AVX512_START 16 + movu xm0, [r2] + vinserti128 ym0, [r2+r3], 1 + movu xm1, [r2+4*r3] + vinserti32x4 m0, [r2+2*r3], 2 + vinserti32x4 m1, [r2+2*r1], 2 + vinserti32x4 m0, [r2+r1], 3 + lea r2, [r2+4*r3] + vinserti32x4 m1, [r2+r3], 1 + psadbw m0, [r0+0*64] + vinserti32x4 m1, [r2+r1], 3 + lea r2, [r2+4*r3] + psadbw m1, [r0+1*64] + movu xm2, [r2] + vinserti128 ym2, [r2+r3], 1 + movu xm3, [r2+4*r3] + vinserti32x4 m2, [r2+2*r3], 2 + vinserti32x4 m3, [r2+2*r1], 2 + vinserti32x4 m2, [r2+r1], 3 + lea r2, [r2+4*r3] + vinserti32x4 m3, [r2+r3], 1 + psadbw m2, [r0+2*64] + vinserti32x4 m3, [r2+r1], 3 + psadbw m3, [r0+3*64] + SAD_W16_AVX512_END ;----------------------------------------------------------------------------- ; void pixel_vsad( pixel *src, intptr_t stride ); @@ -1548,6 +1617,225 @@ SAD_X_AVX2 3, 16, 8, 7 SAD_X_AVX2 4, 16, 16, 8 SAD_X_AVX2 4, 16, 8, 8 +%macro SAD_X_W4_AVX512 2 ; x, h +cglobal pixel_sad_x%1_4x%2, %1+2,%1+3 + mov t1d, 0xa + kmovb k1, t1d + lea t1, [3*t0] + kaddb k2, k1, k1 + kshiftlb k3, k1, 2 +%assign %%i 0 +%rep %2/4 + movu m6, [r0+%%i*64] + vmovddup m6 {k1}, [r0+%%i*64+32] + movd xmm2, [r1] + movd xmm4, [r1+t0] + vpbroadcastd xmm2 {k1}, [r1+2*t0] + vpbroadcastd xmm4 {k1}, [r1+t1] + vpbroadcastd xmm2 {k2}, [r2+t0] + vpbroadcastd xmm4 {k2}, [r2] + vpbroadcastd xmm2 {k3}, [r2+t1] ; a0 a2 b1 b3 + vpbroadcastd xmm4 {k3}, [r2+2*t0] ; a1 a3 b0 b2 + vpmovqd s1, m6 ; s0 s2 s1 s3 + movd xmm3, [r3] + movd xmm5, [r3+t0] + vpbroadcastd xmm3 {k1}, [r3+2*t0] + vpbroadcastd xmm5 {k1}, [r3+t1] +%if %1 == 4 + vpbroadcastd xmm3 {k2}, [r4+t0] + vpbroadcastd xmm5 {k2}, [r4] + vpbroadcastd xmm3 {k3}, [r4+t1] ; c0 c2 d1 d3 + vpbroadcastd xmm5 {k3}, [r4+2*t0] ; c1 c3 d0 d2 +%endif +%if %%i != %2/4-1 +%assign %%j 1 +%rep %1 + lea r%+%%j, [r%+%%j+4*t0] + %assign %%j %%j+1 +%endrep +%endif + pshufd s2, s1, q1032 + psadbw xmm2, s1 + psadbw xmm4, s2 + psadbw xmm3, s1 + psadbw xmm5, s2 +%if %%i + paddd xmm0, xmm2 + paddd xmm1, xmm3 + paddd xmm0, xmm4 + paddd xmm1, xmm5 +%else + paddd xmm0, xmm2, xmm4 + paddd xmm1, xmm3, xmm5 +%endif + %assign %%i %%i+1 +%endrep +%if %1 == 4 + movifnidn t2, r6mp +%else + movifnidn t2, r5mp +%endif + packusdw xmm0, xmm1 + mova [t2], xmm0 + RET +%endmacro + +%macro SAD_X_W8_AVX512 2 ; x, h +cglobal pixel_sad_x%1_8x%2, %1+2,%1+3 + kxnorb k3, k3, k3 + lea t1, [3*t0] + kaddb k1, k3, k3 + kshiftlb k2, k3, 2 + kshiftlb k3, k3, 3 +%assign %%i 0 +%rep %2/4 + movddup m6, [r0+%%i*64] ; s0 s0 s1 s1 + movq xm2, [r1] + movq xm4, [r1+2*t0] + vpbroadcastq xm2 {k1}, [r2] + vpbroadcastq xm4 {k1}, [r2+2*t0] + vpbroadcastq m2 {k2}, [r1+t0] + vpbroadcastq m4 {k2}, [r1+t1] + vpbroadcastq m2 {k3}, [r2+t0] ; a0 b0 a1 b1 + vpbroadcastq m4 {k3}, [r2+t1] ; a2 b2 a3 b3 + movddup m7, [r0+%%i*64+32] ; s2 s2 s3 s3 + movq xm3, [r3] + movq xm5, [r3+2*t0] +%if %1 == 4 + vpbroadcastq xm3 {k1}, [r4] + vpbroadcastq xm5 {k1}, [r4+2*t0] +%endif + vpbroadcastq m3 {k2}, [r3+t0] + vpbroadcastq m5 {k2}, [r3+t1] +%if %1 == 4 + vpbroadcastq m3 {k3}, [r4+t0] ; c0 d0 c1 d1 + vpbroadcastq m5 {k3}, [r4+t1] ; c2 d2 c3 d3 +%endif +%if %%i != %2/4-1 +%assign %%j 1 +%rep %1 + lea r%+%%j, [r%+%%j+4*t0] + %assign %%j %%j+1 +%endrep +%endif + psadbw m2, m6 + psadbw m4, m7 + psadbw m3, m6 + psadbw m5, m7 + ACCUM paddd, 0, 2, %%i + ACCUM paddd, 1, 3, %%i + paddd m0, m4 + paddd m1, m5 + %assign %%i %%i+1 +%endrep +%if %1 == 4 + movifnidn t2, r6mp +%else + movifnidn t2, r5mp +%endif + packusdw m0, m1 + vextracti128 xm1, m0, 1 + paddd xm0, xm1 + mova [t2], xm0 + RET +%endmacro + +%macro SAD_X_W16_AVX512 2 ; x, h +cglobal pixel_sad_x%1_16x%2, %1+2,%1+3 + lea t1, [3*t0] +%assign %%i 0 +%rep %2/4 + mova m6, [r0+%%i*64] ; s0 s1 s2 s3 + movu xm2, [r3] + movu xm4, [r3+t0] +%if %1 == 4 + vinserti128 ym2, [r4+t0], 1 + vinserti128 ym4, [r4], 1 +%endif + vinserti32x4 m2, [r1+2*t0], 2 + vinserti32x4 m4, [r1+t1], 2 + vinserti32x4 m2, [r2+t1], 3 ; c0 d1 a2 b3 + vinserti32x4 m4, [r2+2*t0], 3 ; c1 d0 a3 b2 + vpermq m7, m6, q1032 ; s1 s0 s3 s2 + movu xm3, [r1] + movu xm5, [r1+t0] + vinserti128 ym3, [r2+t0], 1 + vinserti128 ym5, [r2], 1 + vinserti32x4 m3, [r3+2*t0], 2 + vinserti32x4 m5, [r3+t1], 2 +%if %1 == 4 + vinserti32x4 m3, [r4+t1], 3 ; a0 b1 c2 d3 + vinserti32x4 m5, [r4+2*t0], 3 ; a1 b0 c3 d2 +%endif +%if %%i != %2/4-1 +%assign %%j 1 +%rep %1 + lea r%+%%j, [r%+%%j+4*t0] + %assign %%j %%j+1 +%endrep +%endif + psadbw m2, m6 + psadbw m4, m7 + psadbw m3, m6 + psadbw m5, m7 + ACCUM paddd, 0, 2, %%i + ACCUM paddd, 1, 3, %%i + paddd m0, m4 + paddd m1, m5 + %assign %%i %%i+1 +%endrep +%if %1 == 4 + movifnidn t2, r6mp +%else + movifnidn t2, r5mp +%endif + mov t1d, 0x1111 + kmovw k1, t1d + vshufi32x4 m0, m0, q1032 + paddd m0, m1 + punpckhqdq m1, m0, m0 + paddd m0, m1 + vpcompressd m0 {k1}{z}, m0 + mova [t2], xm0 + RET +%endmacro + +; t0 = stride, t1 = tmp/stride3, t2 = scores +%if WIN64 + %define s1 xmm16 ; xmm6 and xmm7 reduces code size, but + %define s2 xmm17 ; they're callee-saved on win64 + DECLARE_REG_TMP 4, 6, 0 +%else + %define s1 xmm6 + %define s2 xmm7 +%if ARCH_X86_64 + DECLARE_REG_TMP 4, 6, 5 ; scores is passed in a register on unix64 +%else + DECLARE_REG_TMP 4, 5, 0 +%endif +%endif + +INIT_YMM avx512 +SAD_X_W4_AVX512 3, 4 ; x3_4x4 +SAD_X_W4_AVX512 3, 8 ; x3_4x8 +SAD_X_W8_AVX512 3, 4 ; x3_8x4 +SAD_X_W8_AVX512 3, 8 ; x3_8x8 +SAD_X_W8_AVX512 3, 16 ; x3_8x16 +INIT_ZMM avx512 +SAD_X_W16_AVX512 3, 8 ; x3_16x8 +SAD_X_W16_AVX512 3, 16 ; x3_16x16 + +DECLARE_REG_TMP 5, 6, 0 +INIT_YMM avx512 +SAD_X_W4_AVX512 4, 4 ; x4_4x4 +SAD_X_W4_AVX512 4, 8 ; x4_4x8 +SAD_X_W8_AVX512 4, 4 ; x4_8x4 +SAD_X_W8_AVX512 4, 8 ; x4_8x8 +SAD_X_W8_AVX512 4, 16 ; x4_8x16 +INIT_ZMM avx512 +SAD_X_W16_AVX512 4, 8 ; x4_16x8 +SAD_X_W16_AVX512 4, 16 ; x4_16x16 + ;============================================================================= ; SAD cacheline split ;============================================================================= diff --git a/library/src/main/cpp/libx264/common/x86/x86inc.asm b/library/src/main/cpp/libx264/common/x86/x86inc.asm index 03304c4..3be387d 100644 --- a/library/src/main/cpp/libx264/common/x86/x86inc.asm +++ b/library/src/main/cpp/libx264/common/x86/x86inc.asm @@ -323,6 +323,8 @@ DECLARE_REG_TMP_SIZE 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14 %endmacro %define required_stack_alignment ((mmsize + 15) & ~15) +%define vzeroupper_required (mmsize > 16 && (ARCH_X86_64 == 0 || xmm_regs_used > 16 || notcpuflag(avx512))) +%define high_mm_regs (16*cpuflag(avx512)) %macro ALLOC_STACK 1-2 0 ; stack_size, n_xmm_regs (for win64 only) %ifnum %1 @@ -414,10 +416,10 @@ DECLARE_REG 7, rdi, 64 DECLARE_REG 8, rsi, 72 DECLARE_REG 9, rbx, 80 DECLARE_REG 10, rbp, 88 -DECLARE_REG 11, R12, 96 -DECLARE_REG 12, R13, 104 -DECLARE_REG 13, R14, 112 -DECLARE_REG 14, R15, 120 +DECLARE_REG 11, R14, 96 +DECLARE_REG 12, R15, 104 +DECLARE_REG 13, R12, 112 +DECLARE_REG 14, R13, 120 %macro PROLOGUE 2-5+ 0 ; #args, #regs, #xmm_regs, [stack_size,] arg_names... %assign num_args %1 @@ -436,15 +438,16 @@ DECLARE_REG 14, R15, 120 %macro WIN64_PUSH_XMM 0 ; Use the shadow space to store XMM6 and XMM7, the rest needs stack space allocated. - %if xmm_regs_used > 6 + %if xmm_regs_used > 6 + high_mm_regs movaps [rstk + stack_offset + 8], xmm6 %endif - %if xmm_regs_used > 7 + %if xmm_regs_used > 7 + high_mm_regs movaps [rstk + stack_offset + 24], xmm7 %endif - %if xmm_regs_used > 8 + %assign %%xmm_regs_on_stack xmm_regs_used - high_mm_regs - 8 + %if %%xmm_regs_on_stack > 0 %assign %%i 8 - %rep xmm_regs_used-8 + %rep %%xmm_regs_on_stack movaps [rsp + (%%i-8)*16 + stack_size + 32], xmm %+ %%i %assign %%i %%i+1 %endrep @@ -453,53 +456,56 @@ DECLARE_REG 14, R15, 120 %macro WIN64_SPILL_XMM 1 %assign xmm_regs_used %1 - ASSERT xmm_regs_used <= 16 - %if xmm_regs_used > 8 + ASSERT xmm_regs_used <= 16 + high_mm_regs + %assign %%xmm_regs_on_stack xmm_regs_used - high_mm_regs - 8 + %if %%xmm_regs_on_stack > 0 ; Allocate stack space for callee-saved xmm registers plus shadow space and align the stack. - %assign %%pad (xmm_regs_used-8)*16 + 32 + %assign %%pad %%xmm_regs_on_stack*16 + 32 %assign stack_size_padded %%pad + ((-%%pad-stack_offset-gprsize) & (STACK_ALIGNMENT-1)) SUB rsp, stack_size_padded %endif WIN64_PUSH_XMM %endmacro -%macro WIN64_RESTORE_XMM_INTERNAL 1 +%macro WIN64_RESTORE_XMM_INTERNAL 0 %assign %%pad_size 0 - %if xmm_regs_used > 8 - %assign %%i xmm_regs_used - %rep xmm_regs_used-8 + %assign %%xmm_regs_on_stack xmm_regs_used - high_mm_regs - 8 + %if %%xmm_regs_on_stack > 0 + %assign %%i xmm_regs_used - high_mm_regs + %rep %%xmm_regs_on_stack %assign %%i %%i-1 - movaps xmm %+ %%i, [%1 + (%%i-8)*16 + stack_size + 32] + movaps xmm %+ %%i, [rsp + (%%i-8)*16 + stack_size + 32] %endrep %endif %if stack_size_padded > 0 %if stack_size > 0 && required_stack_alignment > STACK_ALIGNMENT mov rsp, rstkm %else - add %1, stack_size_padded + add rsp, stack_size_padded %assign %%pad_size stack_size_padded %endif %endif - %if xmm_regs_used > 7 - movaps xmm7, [%1 + stack_offset - %%pad_size + 24] + %if xmm_regs_used > 7 + high_mm_regs + movaps xmm7, [rsp + stack_offset - %%pad_size + 24] %endif - %if xmm_regs_used > 6 - movaps xmm6, [%1 + stack_offset - %%pad_size + 8] + %if xmm_regs_used > 6 + high_mm_regs + movaps xmm6, [rsp + stack_offset - %%pad_size + 8] %endif %endmacro -%macro WIN64_RESTORE_XMM 1 - WIN64_RESTORE_XMM_INTERNAL %1 +%macro WIN64_RESTORE_XMM 0 + WIN64_RESTORE_XMM_INTERNAL %assign stack_offset (stack_offset-stack_size_padded) + %assign stack_size_padded 0 %assign xmm_regs_used 0 %endmacro -%define has_epilogue regs_used > 7 || xmm_regs_used > 6 || mmsize == 32 || stack_size > 0 +%define has_epilogue regs_used > 7 || stack_size > 0 || vzeroupper_required || xmm_regs_used > 6+high_mm_regs %macro RET 0 - WIN64_RESTORE_XMM_INTERNAL rsp + WIN64_RESTORE_XMM_INTERNAL POP_IF_USED 14, 13, 12, 11, 10, 9, 8, 7 - %if mmsize == 32 + %if vzeroupper_required vzeroupper %endif AUTO_REP_RET @@ -518,14 +524,15 @@ DECLARE_REG 7, R10, 16 DECLARE_REG 8, R11, 24 DECLARE_REG 9, rbx, 32 DECLARE_REG 10, rbp, 40 -DECLARE_REG 11, R12, 48 -DECLARE_REG 12, R13, 56 -DECLARE_REG 13, R14, 64 -DECLARE_REG 14, R15, 72 +DECLARE_REG 11, R14, 48 +DECLARE_REG 12, R15, 56 +DECLARE_REG 13, R12, 64 +DECLARE_REG 14, R13, 72 -%macro PROLOGUE 2-5+ ; #args, #regs, #xmm_regs, [stack_size,] arg_names... +%macro PROLOGUE 2-5+ 0 ; #args, #regs, #xmm_regs, [stack_size,] arg_names... %assign num_args %1 %assign regs_used %2 + %assign xmm_regs_used %3 ASSERT regs_used >= num_args SETUP_STACK_POINTER %4 ASSERT regs_used <= 15 @@ -535,7 +542,7 @@ DECLARE_REG 14, R15, 72 DEFINE_ARGS_INTERNAL %0, %4, %5 %endmacro -%define has_epilogue regs_used > 9 || mmsize == 32 || stack_size > 0 +%define has_epilogue regs_used > 9 || stack_size > 0 || vzeroupper_required %macro RET 0 %if stack_size_padded > 0 @@ -546,7 +553,7 @@ DECLARE_REG 14, R15, 72 %endif %endif POP_IF_USED 14, 13, 12, 11, 10, 9 - %if mmsize == 32 + %if vzeroupper_required vzeroupper %endif AUTO_REP_RET @@ -591,7 +598,7 @@ DECLARE_ARG 7, 8, 9, 10, 11, 12, 13, 14 DEFINE_ARGS_INTERNAL %0, %4, %5 %endmacro -%define has_epilogue regs_used > 3 || mmsize == 32 || stack_size > 0 +%define has_epilogue regs_used > 3 || stack_size > 0 || vzeroupper_required %macro RET 0 %if stack_size_padded > 0 @@ -602,7 +609,7 @@ DECLARE_ARG 7, 8, 9, 10, 11, 12, 13, 14 %endif %endif POP_IF_USED 6, 5, 4, 3 - %if mmsize == 32 + %if vzeroupper_required vzeroupper %endif AUTO_REP_RET @@ -613,7 +620,7 @@ DECLARE_ARG 7, 8, 9, 10, 11, 12, 13, 14 %if WIN64 == 0 %macro WIN64_SPILL_XMM 1 %endmacro - %macro WIN64_RESTORE_XMM 1 + %macro WIN64_RESTORE_XMM 0 %endmacro %macro WIN64_PUSH_XMM 0 %endmacro @@ -624,7 +631,7 @@ DECLARE_ARG 7, 8, 9, 10, 11, 12, 13, 14 ; We can automatically detect "follows a branch", but not a branch target. ; (SSSE3 is a sufficient condition to know that your cpu doesn't have this problem.) %macro REP_RET 0 - %if has_epilogue + %if has_epilogue || cpuflag(ssse3) RET %else rep ret @@ -712,7 +719,7 @@ BRANCH_INSTR jz, je, jnz, jne, jl, jle, jnl, jnle, jg, jge, jng, jnge, ja, jae, %assign stack_offset 0 ; stack pointer offset relative to the return address %assign stack_size 0 ; amount of stack space that can be freely used inside a function %assign stack_size_padded 0 ; total amount of allocated stack space, including space for callee-saved xmm registers on WIN64 and alignment padding - %assign xmm_regs_used 0 ; number of XMM registers requested, used for dealing with callee-saved registers on WIN64 + %assign xmm_regs_used 0 ; number of XMM registers requested, used for dealing with callee-saved registers on WIN64 and vzeroupper %ifnidn %3, "" PROLOGUE %3 %endif @@ -775,24 +782,25 @@ BRANCH_INSTR jz, je, jnz, jne, jl, jle, jnl, jnle, jg, jge, jng, jnge, ja, jae, %assign cpuflags_sse (1<<4) | cpuflags_mmx2 %assign cpuflags_sse2 (1<<5) | cpuflags_sse %assign cpuflags_sse2slow (1<<6) | cpuflags_sse2 -%assign cpuflags_sse3 (1<<7) | cpuflags_sse2 -%assign cpuflags_ssse3 (1<<8) | cpuflags_sse3 -%assign cpuflags_sse4 (1<<9) | cpuflags_ssse3 -%assign cpuflags_sse42 (1<<10)| cpuflags_sse4 -%assign cpuflags_avx (1<<11)| cpuflags_sse42 -%assign cpuflags_xop (1<<12)| cpuflags_avx -%assign cpuflags_fma4 (1<<13)| cpuflags_avx -%assign cpuflags_fma3 (1<<14)| cpuflags_avx -%assign cpuflags_avx2 (1<<15)| cpuflags_fma3 - -%assign cpuflags_cache32 (1<<16) -%assign cpuflags_cache64 (1<<17) -%assign cpuflags_slowctz (1<<18) -%assign cpuflags_lzcnt (1<<19) -%assign cpuflags_aligned (1<<20) ; not a cpu feature, but a function variant -%assign cpuflags_atom (1<<21) -%assign cpuflags_bmi1 (1<<22)|cpuflags_lzcnt -%assign cpuflags_bmi2 (1<<23)|cpuflags_bmi1 +%assign cpuflags_lzcnt (1<<7) | cpuflags_sse2 +%assign cpuflags_sse3 (1<<8) | cpuflags_sse2 +%assign cpuflags_ssse3 (1<<9) | cpuflags_sse3 +%assign cpuflags_sse4 (1<<10)| cpuflags_ssse3 +%assign cpuflags_sse42 (1<<11)| cpuflags_sse4 +%assign cpuflags_aesni (1<<12)| cpuflags_sse42 +%assign cpuflags_avx (1<<13)| cpuflags_sse42 +%assign cpuflags_xop (1<<14)| cpuflags_avx +%assign cpuflags_fma4 (1<<15)| cpuflags_avx +%assign cpuflags_fma3 (1<<16)| cpuflags_avx +%assign cpuflags_bmi1 (1<<17)| cpuflags_avx|cpuflags_lzcnt +%assign cpuflags_bmi2 (1<<18)| cpuflags_bmi1 +%assign cpuflags_avx2 (1<<19)| cpuflags_fma3|cpuflags_bmi2 +%assign cpuflags_avx512 (1<<20)| cpuflags_avx2 ; F, CD, BW, DQ, VL + +%assign cpuflags_cache32 (1<<21) +%assign cpuflags_cache64 (1<<22) +%assign cpuflags_aligned (1<<23) ; not a cpu feature, but a function variant +%assign cpuflags_atom (1<<24) ; Returns a boolean value expressing whether or not the specified cpuflag is enabled. %define cpuflag(x) (((((cpuflags & (cpuflags_ %+ x)) ^ (cpuflags_ %+ x)) - 1) >> 31) & 1) @@ -835,7 +843,7 @@ BRANCH_INSTR jz, je, jnz, jne, jl, jle, jnl, jnle, jg, jge, jng, jnge, ja, jae, %if ARCH_X86_64 || cpuflag(sse2) %ifdef __NASM_VER__ - ALIGNMODE k8 + ALIGNMODE p6 %else CPU amdnop %endif @@ -848,11 +856,12 @@ BRANCH_INSTR jz, je, jnz, jne, jl, jle, jnl, jnle, jg, jge, jng, jnge, ja, jae, %endif %endmacro -; Merge mmx and sse* +; Merge mmx, sse*, and avx* ; m# is a simd register of the currently selected size ; xm# is the corresponding xmm register if mmsize >= 16, otherwise the same as m# ; ym# is the corresponding ymm register if mmsize >= 32, otherwise the same as m# -; (All 3 remain in sync through SWAP.) +; zm# is the corresponding zmm register if mmsize >= 64, otherwise the same as m# +; (All 4 remain in sync through SWAP.) %macro CAT_XDEFINE 3 %xdefine %1%2 %3 @@ -862,6 +871,18 @@ BRANCH_INSTR jz, je, jnz, jne, jl, jle, jnl, jnle, jg, jge, jng, jnge, ja, jae, %undef %1%2 %endmacro +; Prefer registers 16-31 over 0-15 to avoid having to use vzeroupper +%macro AVX512_MM_PERMUTATION 0-1 0 ; start_reg + %if ARCH_X86_64 && cpuflag(avx512) + %assign %%i %1 + %rep 16-%1 + %assign %%i_high %%i+16 + SWAP %%i, %%i_high + %assign %%i %%i+1 + %endrep + %endif +%endmacro + %macro INIT_MMX 0-1+ %assign avx_enabled 0 %define RESET_MM_PERMUTATION INIT_MMX %1 @@ -877,7 +898,7 @@ BRANCH_INSTR jz, je, jnz, jne, jl, jle, jnl, jnle, jg, jge, jng, jnge, ja, jae, CAT_XDEFINE nnmm, %%i, %%i %assign %%i %%i+1 %endrep - %rep 8 + %rep 24 CAT_UNDEF m, %%i CAT_UNDEF nnmm, %%i %assign %%i %%i+1 @@ -891,7 +912,7 @@ BRANCH_INSTR jz, je, jnz, jne, jl, jle, jnl, jnle, jg, jge, jng, jnge, ja, jae, %define mmsize 16 %define num_mmregs 8 %if ARCH_X86_64 - %define num_mmregs 16 + %define num_mmregs 32 %endif %define mova movdqa %define movu movdqu @@ -904,6 +925,10 @@ BRANCH_INSTR jz, je, jnz, jne, jl, jle, jnl, jnle, jg, jge, jng, jnge, ja, jae, %assign %%i %%i+1 %endrep INIT_CPUFLAGS %1 + %if WIN64 + ; Swap callee-saved registers with volatile registers + AVX512_MM_PERMUTATION 6 + %endif %endmacro %macro INIT_YMM 0-1+ @@ -912,7 +937,7 @@ BRANCH_INSTR jz, je, jnz, jne, jl, jle, jnl, jnle, jg, jge, jng, jnge, ja, jae, %define mmsize 32 %define num_mmregs 8 %if ARCH_X86_64 - %define num_mmregs 16 + %define num_mmregs 32 %endif %define mova movdqa %define movu movdqu @@ -925,6 +950,29 @@ BRANCH_INSTR jz, je, jnz, jne, jl, jle, jnl, jnle, jg, jge, jng, jnge, ja, jae, %assign %%i %%i+1 %endrep INIT_CPUFLAGS %1 + AVX512_MM_PERMUTATION +%endmacro + +%macro INIT_ZMM 0-1+ + %assign avx_enabled 1 + %define RESET_MM_PERMUTATION INIT_ZMM %1 + %define mmsize 64 + %define num_mmregs 8 + %if ARCH_X86_64 + %define num_mmregs 32 + %endif + %define mova movdqa + %define movu movdqu + %undef movh + %define movnta movntdq + %assign %%i 0 + %rep num_mmregs + CAT_XDEFINE m, %%i, zmm %+ %%i + CAT_XDEFINE nnzmm, %%i, %%i + %assign %%i %%i+1 + %endrep + INIT_CPUFLAGS %1 + AVX512_MM_PERMUTATION %endmacro INIT_XMM @@ -933,18 +981,26 @@ INIT_XMM %define mmmm%1 mm%1 %define mmxmm%1 mm%1 %define mmymm%1 mm%1 + %define mmzmm%1 mm%1 %define xmmmm%1 mm%1 %define xmmxmm%1 xmm%1 %define xmmymm%1 xmm%1 + %define xmmzmm%1 xmm%1 %define ymmmm%1 mm%1 %define ymmxmm%1 xmm%1 %define ymmymm%1 ymm%1 + %define ymmzmm%1 ymm%1 + %define zmmmm%1 mm%1 + %define zmmxmm%1 xmm%1 + %define zmmymm%1 ymm%1 + %define zmmzmm%1 zmm%1 %define xm%1 xmm %+ m%1 %define ym%1 ymm %+ m%1 + %define zm%1 zmm %+ m%1 %endmacro %assign i 0 -%rep 16 +%rep 32 DECLARE_MMCAST i %assign i i+1 %endrep @@ -1032,7 +1088,11 @@ INIT_XMM ; Append cpuflags to the callee's name iff the appended name is known and the plain name isn't %macro call 1 - call_internal %1 %+ SUFFIX, %1 + %ifid %1 + call_internal %1 %+ SUFFIX, %1 + %else + call %1 + %endif %endmacro %macro call_internal 2 %xdefine %%i %2 @@ -1075,12 +1135,17 @@ INIT_XMM ;============================================================================= %assign i 0 -%rep 16 +%rep 32 %if i < 8 CAT_XDEFINE sizeofmm, i, 8 + CAT_XDEFINE regnumofmm, i, i %endif CAT_XDEFINE sizeofxmm, i, 16 CAT_XDEFINE sizeofymm, i, 32 + CAT_XDEFINE sizeofzmm, i, 64 + CAT_XDEFINE regnumofxmm, i, i + CAT_XDEFINE regnumofymm, i, i + CAT_XDEFINE regnumofzmm, i, i %assign i i+1 %endrep %undef i @@ -1197,7 +1262,7 @@ INIT_XMM %endmacro %endmacro -; Instructions with both VEX and non-VEX encodings +; Instructions with both VEX/EVEX and legacy encodings ; Non-destructive instructions are written without parameters AVX_INSTR addpd, sse2, 1, 0, 1 AVX_INSTR addps, sse, 1, 0, 1 @@ -1529,15 +1594,48 @@ FMA4_INSTR fmsubadd, pd, ps FMA4_INSTR fnmadd, pd, ps, sd, ss FMA4_INSTR fnmsub, pd, ps, sd, ss -; workaround: vpbroadcastq is broken in x86_32 due to a yasm bug (fixed in 1.3.0) -%ifdef __YASM_VER__ - %if __YASM_VERSION_ID__ < 0x01030000 && ARCH_X86_64 == 0 - %macro vpbroadcastq 2 - %if sizeof%1 == 16 - movddup %1, %2 - %else - vbroadcastsd %1, %2 +; Macros for converting VEX instructions to equivalent EVEX ones. +%macro EVEX_INSTR 2-3 0 ; vex, evex, prefer_evex + %macro %1 2-7 fnord, fnord, %1, %2, %3 + %ifidn %3, fnord + %define %%args %1, %2 + %elifidn %4, fnord + %define %%args %1, %2, %3 + %else + %define %%args %1, %2, %3, %4 + %endif + %assign %%evex_required cpuflag(avx512) & %7 + %ifnum regnumof%1 + %if regnumof%1 >= 16 || sizeof%1 > 32 + %assign %%evex_required 1 %endif - %endmacro - %endif -%endif + %endif + %ifnum regnumof%2 + %if regnumof%2 >= 16 || sizeof%2 > 32 + %assign %%evex_required 1 + %endif + %endif + %if %%evex_required + %6 %%args + %else + %5 %%args ; Prefer VEX over EVEX due to shorter instruction length + %endif + %endmacro +%endmacro + +EVEX_INSTR vbroadcastf128, vbroadcastf32x4 +EVEX_INSTR vbroadcasti128, vbroadcasti32x4 +EVEX_INSTR vextractf128, vextractf32x4 +EVEX_INSTR vextracti128, vextracti32x4 +EVEX_INSTR vinsertf128, vinsertf32x4 +EVEX_INSTR vinserti128, vinserti32x4 +EVEX_INSTR vmovdqa, vmovdqa32 +EVEX_INSTR vmovdqu, vmovdqu32 +EVEX_INSTR vpand, vpandd +EVEX_INSTR vpandn, vpandnd +EVEX_INSTR vpor, vpord +EVEX_INSTR vpxor, vpxord +EVEX_INSTR vrcpps, vrcp14ps, 1 ; EVEX versions have higher precision +EVEX_INSTR vrcpss, vrcp14ss, 1 +EVEX_INSTR vrsqrtps, vrsqrt14ps, 1 +EVEX_INSTR vrsqrtss, vrsqrt14ss, 1 diff --git a/library/src/main/cpp/libx264/common/x86/x86util.asm b/library/src/main/cpp/libx264/common/x86/x86util.asm index ea40bc8..7a140eb 100644 --- a/library/src/main/cpp/libx264/common/x86/x86util.asm +++ b/library/src/main/cpp/libx264/common/x86/x86util.asm @@ -303,24 +303,24 @@ %endmacro %macro HADDD 2 ; sum junk -%if sizeof%1 == 32 -%define %2 xmm%2 - vextracti128 %2, %1, 1 -%define %1 xmm%1 - paddd %1, %2 +%if sizeof%1 >= 64 + vextracti32x8 ymm%2, zmm%1, 1 + paddd ymm%1, ymm%2 %endif -%if mmsize >= 16 - MOVHL %2, %1 - paddd %1, %2 +%if sizeof%1 >= 32 + vextracti128 xmm%2, ymm%1, 1 + paddd xmm%1, xmm%2 +%endif +%if sizeof%1 >= 16 + MOVHL xmm%2, xmm%1 + paddd xmm%1, xmm%2 %endif %if cpuflag(xop) && sizeof%1 == 16 - vphadddq %1, %1 + vphadddq xmm%1, xmm%1 %else - PSHUFLW %2, %1, q0032 - paddd %1, %2 + PSHUFLW xmm%2, xmm%1, q1032 + paddd xmm%1, xmm%2 %endif -%undef %1 -%undef %2 %endmacro %macro HADDW 2 ; reg, tmp diff --git a/library/src/main/cpp/libx264/encoder/analyse.c b/library/src/main/cpp/libx264/encoder/analyse.c index 1941bf2..036d6c1 100644 --- a/library/src/main/cpp/libx264/encoder/analyse.c +++ b/library/src/main/cpp/libx264/encoder/analyse.c @@ -34,37 +34,23 @@ typedef struct { - /* 16x16 */ - int i_rd16x16; x264_me_t me16x16; x264_me_t bi16x16; /* for b16x16 BI mode, since MVs can differ from l0/l1 */ - - /* 8x8 */ - int i_cost8x8; - /* [ref][0] is 16x16 mv, [ref][1..4] are 8x8 mv from partition [0..3] */ - ALIGNED_4( int16_t mvc[32][5][2] ); x264_me_t me8x8[4]; - - /* Sub 4x4 */ - int i_cost4x4[4]; /* cost per 8x8 partition */ x264_me_t me4x4[4][4]; - - /* Sub 8x4 */ - int i_cost8x4[4]; /* cost per 8x8 partition */ x264_me_t me8x4[4][2]; - - /* Sub 4x8 */ - int i_cost4x8[4]; /* cost per 8x8 partition */ x264_me_t me4x8[4][2]; - - /* 16x8 */ - int i_cost16x8; x264_me_t me16x8[2]; - - /* 8x16 */ - int i_cost8x16; x264_me_t me8x16[2]; - + int i_rd16x16; + int i_cost8x8; + int i_cost4x4[4]; /* cost per 8x8 partition */ + int i_cost8x4[4]; /* cost per 8x8 partition */ + int i_cost4x8[4]; /* cost per 8x8 partition */ + int i_cost16x8; + int i_cost8x16; + /* [ref][0] is 16x16 mv, [ref][1..4] are 8x8 mv from partition [0..3] */ + ALIGNED_4( int16_t mvc[32][5][2] ); } x264_mb_analysis_list_t; typedef struct @@ -278,29 +264,31 @@ static uint16_t x264_cost_i4x4_mode[(QP_MAX+2)*32]; static int init_costs( x264_t *h, float *logs, int qp ) { - int lambda = x264_lambda_tab[qp]; if( h->cost_mv[qp] ) return 0; + + int mv_range = h->param.analyse.i_mv_range; + int lambda = x264_lambda_tab[qp]; /* factor of 4 from qpel, 2 from sign, and 2 because mv can be opposite from mvp */ - CHECKED_MALLOC( h->cost_mv[qp], (4*4*2048 + 1) * sizeof(uint16_t) ); - h->cost_mv[qp] += 2*4*2048; - for( int i = 0; i <= 2*4*2048; i++ ) + CHECKED_MALLOC( h->cost_mv[qp], (4*4*mv_range + 1) * sizeof(uint16_t) ); + h->cost_mv[qp] += 2*4*mv_range; + for( int i = 0; i <= 2*4*mv_range; i++ ) { h->cost_mv[qp][-i] = - h->cost_mv[qp][i] = X264_MIN( lambda * logs[i] + .5f, (1<<16)-1 ); + h->cost_mv[qp][i] = X264_MIN( (int)(lambda * logs[i] + .5f), UINT16_MAX ); } x264_pthread_mutex_lock( &cost_ref_mutex ); for( int i = 0; i < 3; i++ ) for( int j = 0; j < 33; j++ ) - x264_cost_ref[qp][i][j] = X264_MIN( i ? lambda * bs_size_te( i, j ) : 0, (1<<16)-1 ); + x264_cost_ref[qp][i][j] = i ? X264_MIN( lambda * bs_size_te( i, j ), UINT16_MAX ) : 0; x264_pthread_mutex_unlock( &cost_ref_mutex ); if( h->param.analyse.i_me_method >= X264_ME_ESA && !h->cost_mv_fpel[qp][0] ) { for( int j = 0; j < 4; j++ ) { - CHECKED_MALLOC( h->cost_mv_fpel[qp][j], (4*2048 + 1) * sizeof(uint16_t) ); - h->cost_mv_fpel[qp][j] += 2*2048; - for( int i = -2*2048; i < 2*2048; i++ ) + CHECKED_MALLOC( h->cost_mv_fpel[qp][j], (4*mv_range + 1) * sizeof(uint16_t) ); + h->cost_mv_fpel[qp][j] += 2*mv_range; + for( int i = -2*mv_range; i < 2*mv_range; i++ ) h->cost_mv_fpel[qp][j][i] = h->cost_mv[qp][i*4+j]; } } @@ -314,12 +302,13 @@ fail: int x264_analyse_init_costs( x264_t *h ) { - float *logs = x264_malloc( (2*4*2048+1) * sizeof(float) ); + int mv_range = h->param.analyse.i_mv_range; + float *logs = x264_malloc( (2*4*mv_range+1) * sizeof(float) ); if( !logs ) return -1; logs[0] = 0.718f; - for( int i = 1; i <= 2*4*2048; i++ ) + for( int i = 1; i <= 2*4*mv_range; i++ ) logs[i] = log2f( i+1 ) * 2.0f + 1.718f; for( int qp = X264_MIN( h->param.rc.i_qp_min, QP_MAX_SPEC ); qp <= h->param.rc.i_qp_max; qp++ ) @@ -338,13 +327,14 @@ fail: void x264_analyse_free_costs( x264_t *h ) { + int mv_range = h->param.analyse.i_mv_range; for( int i = 0; i < QP_MAX+1; i++ ) { if( h->cost_mv[i] ) - x264_free( h->cost_mv[i] - 2*4*2048 ); + x264_free( h->cost_mv[i] - 2*4*mv_range ); if( h->cost_mv_fpel[i][0] ) for( int j = 0; j < 4; j++ ) - x264_free( h->cost_mv_fpel[i][j] - 2*2048 ); + x264_free( h->cost_mv_fpel[i][j] - 2*mv_range ); } } @@ -465,11 +455,10 @@ static void x264_mb_analyse_init( x264_t *h, x264_mb_analysis_t *a, int qp ) int i_fpel_border = 6; // umh: 1 for diamond, 2 for octagon, 2 for hpel /* Calculate max allowed MV range */ -#define CLIP_FMV(mv) x264_clip3( mv, -i_fmv_range, i_fmv_range-1 ) h->mb.mv_min[0] = 4*( -16*h->mb.i_mb_x - 24 ); h->mb.mv_max[0] = 4*( 16*( h->mb.i_mb_width - h->mb.i_mb_x - 1 ) + 24 ); - h->mb.mv_min_spel[0] = CLIP_FMV( h->mb.mv_min[0] ); - h->mb.mv_max_spel[0] = CLIP_FMV( h->mb.mv_max[0] ); + h->mb.mv_min_spel[0] = X264_MAX( h->mb.mv_min[0], -i_fmv_range ); + h->mb.mv_max_spel[0] = X264_MIN( h->mb.mv_max[0], i_fmv_range-1 ); if( h->param.b_intra_refresh && h->sh.i_type == SLICE_TYPE_P ) { int max_x = (h->fref[0][0]->i_pir_end_col * 16 - 3)*4; /* 3 pixels of hpel border */ @@ -513,9 +502,8 @@ static void x264_mb_analyse_init( x264_t *h, x264_mb_analysis_t *a, int qp ) mb_y = (h->mb.i_mb_y >> j) + (i == 1); h->mb.mv_miny_row[i] = 4*( -16*mb_y - 24 ); h->mb.mv_maxy_row[i] = 4*( 16*( (h->mb.i_mb_height>>j) - mb_y - 1 ) + 24 ); - h->mb.mv_miny_spel_row[i] = x264_clip3( h->mb.mv_miny_row[i], -i_fmv_range, i_fmv_range ); - h->mb.mv_maxy_spel_row[i] = CLIP_FMV( h->mb.mv_maxy_row[i] ); - h->mb.mv_maxy_spel_row[i] = X264_MIN( h->mb.mv_maxy_spel_row[i], thread_mvy_range*4 ); + h->mb.mv_miny_spel_row[i] = X264_MAX( h->mb.mv_miny_row[i], -i_fmv_range ); + h->mb.mv_maxy_spel_row[i] = X264_MIN3( h->mb.mv_maxy_row[i], i_fmv_range-1, 4*thread_mvy_range ); h->mb.mv_miny_fpel_row[i] = (h->mb.mv_miny_spel_row[i]>>2) + i_fpel_border; h->mb.mv_maxy_fpel_row[i] = (h->mb.mv_maxy_spel_row[i]>>2) - i_fpel_border; } @@ -524,9 +512,8 @@ static void x264_mb_analyse_init( x264_t *h, x264_mb_analysis_t *a, int qp ) { h->mb.mv_min[1] = 4*( -16*mb_y - 24 ); h->mb.mv_max[1] = 4*( 16*( h->mb.i_mb_height - mb_y - 1 ) + 24 ); - h->mb.mv_min_spel[1] = x264_clip3( h->mb.mv_min[1], -i_fmv_range, i_fmv_range ); - h->mb.mv_max_spel[1] = CLIP_FMV( h->mb.mv_max[1] ); - h->mb.mv_max_spel[1] = X264_MIN( h->mb.mv_max_spel[1], thread_mvy_range*4 ); + h->mb.mv_min_spel[1] = X264_MAX( h->mb.mv_min[1], -i_fmv_range ); + h->mb.mv_max_spel[1] = X264_MIN3( h->mb.mv_max[1], i_fmv_range-1, 4*thread_mvy_range ); h->mb.mv_limit_fpel[0][1] = (h->mb.mv_min_spel[1]>>2) + i_fpel_border; h->mb.mv_limit_fpel[1][1] = (h->mb.mv_max_spel[1]>>2) - i_fpel_border; } @@ -541,7 +528,6 @@ static void x264_mb_analyse_init( x264_t *h, x264_mb_analysis_t *a, int qp ) h->mb.mv_limit_fpel[0][1] = h->mb.mv_miny_fpel_row[i]; h->mb.mv_limit_fpel[1][1] = h->mb.mv_maxy_fpel_row[i]; } -#undef CLIP_FMV a->l0.me16x16.cost = a->l0.i_rd16x16 = @@ -713,8 +699,12 @@ static inline void x264_mb_init_fenc_cache( x264_t *h, int b_satd ) x264_psy_trellis_init( h, h->param.analyse.b_transform_8x8 ); if( !h->mb.i_psy_rd ) return; - /* Writes beyond the end of the array, but not a problem since fenc_satd_cache is right after. */ - h->mc.memzero_aligned( h->mb.pic.fenc_hadamard_cache, sizeof(h->mb.pic.fenc_hadamard_cache) ); + + M128( &h->mb.pic.fenc_hadamard_cache[0] ) = M128_ZERO; + M128( &h->mb.pic.fenc_hadamard_cache[2] ) = M128_ZERO; + M128( &h->mb.pic.fenc_hadamard_cache[4] ) = M128_ZERO; + M128( &h->mb.pic.fenc_hadamard_cache[6] ) = M128_ZERO; + h->mb.pic.fenc_hadamard_cache[8] = 0; if( b_satd ) h->mc.memzero_aligned( h->mb.pic.fenc_satd_cache, sizeof(h->mb.pic.fenc_satd_cache) ); } @@ -743,8 +733,8 @@ static void x264_mb_analyse_intra_chroma( x264_t *h, x264_mb_analysis_t *a ) h->predict_16x16[a->i_predict16x16]( h->mb.pic.p_fdec[1] ); h->predict_16x16[a->i_predict16x16]( h->mb.pic.p_fdec[2] ); } - a->i_satd_chroma = h->pixf.mbcmp[PIXEL_16x16]( h->mb.pic.p_fdec[1], FDEC_STRIDE, h->mb.pic.p_fenc[1], FENC_STRIDE ) - + h->pixf.mbcmp[PIXEL_16x16]( h->mb.pic.p_fdec[2], FDEC_STRIDE, h->mb.pic.p_fenc[2], FENC_STRIDE ); + a->i_satd_chroma = h->pixf.mbcmp[PIXEL_16x16]( h->mb.pic.p_fenc[1], FENC_STRIDE, h->mb.pic.p_fdec[1], FDEC_STRIDE ) + + h->pixf.mbcmp[PIXEL_16x16]( h->mb.pic.p_fenc[2], FENC_STRIDE, h->mb.pic.p_fdec[2], FDEC_STRIDE ); return; } @@ -759,8 +749,8 @@ static void x264_mb_analyse_intra_chroma( x264_t *h, x264_mb_analysis_t *a ) h->pixf.intra_mbcmp_x3_chroma( h->mb.pic.p_fenc[2], h->mb.pic.p_fdec[2], satdv ); h->predict_chroma[I_PRED_CHROMA_P]( h->mb.pic.p_fdec[1] ); h->predict_chroma[I_PRED_CHROMA_P]( h->mb.pic.p_fdec[2] ); - satdu[I_PRED_CHROMA_P] = h->pixf.mbcmp[chromapix]( h->mb.pic.p_fdec[1], FDEC_STRIDE, h->mb.pic.p_fenc[1], FENC_STRIDE ); - satdv[I_PRED_CHROMA_P] = h->pixf.mbcmp[chromapix]( h->mb.pic.p_fdec[2], FDEC_STRIDE, h->mb.pic.p_fenc[2], FENC_STRIDE ); + satdu[I_PRED_CHROMA_P] = h->pixf.mbcmp[chromapix]( h->mb.pic.p_fenc[1], FENC_STRIDE, h->mb.pic.p_fdec[1], FDEC_STRIDE ); + satdv[I_PRED_CHROMA_P] = h->pixf.mbcmp[chromapix]( h->mb.pic.p_fenc[2], FENC_STRIDE, h->mb.pic.p_fdec[2], FDEC_STRIDE ); for( ; *predict_mode >= 0; predict_mode++ ) { @@ -788,8 +778,8 @@ static void x264_mb_analyse_intra_chroma( x264_t *h, x264_mb_analysis_t *a ) } /* we calculate the cost */ - i_satd = h->pixf.mbcmp[chromapix]( h->mb.pic.p_fdec[1], FDEC_STRIDE, h->mb.pic.p_fenc[1], FENC_STRIDE ) + - h->pixf.mbcmp[chromapix]( h->mb.pic.p_fdec[2], FDEC_STRIDE, h->mb.pic.p_fenc[2], FENC_STRIDE ) + + i_satd = h->pixf.mbcmp[chromapix]( h->mb.pic.p_fenc[1], FENC_STRIDE, h->mb.pic.p_fdec[1], FDEC_STRIDE ) + + h->pixf.mbcmp[chromapix]( h->mb.pic.p_fenc[2], FENC_STRIDE, h->mb.pic.p_fdec[2], FDEC_STRIDE ) + a->i_lambda * bs_size_ue( x264_mb_chroma_pred_mode_fix[i_mode] ); a->i_satd_chroma_dir[i_mode] = i_satd; @@ -845,7 +835,7 @@ static void x264_mb_analyse_intra( x264_t *h, x264_mb_analysis_t *a, int i_satd_ if( a->i_satd_i16x16 <= i16x16_thresh ) { h->predict_16x16[I_PRED_16x16_P]( p_dst ); - a->i_satd_i16x16_dir[I_PRED_16x16_P] = h->pixf.mbcmp[PIXEL_16x16]( p_dst, FDEC_STRIDE, p_src, FENC_STRIDE ); + a->i_satd_i16x16_dir[I_PRED_16x16_P] = h->pixf.mbcmp[PIXEL_16x16]( p_src, FENC_STRIDE, p_dst, FDEC_STRIDE ); a->i_satd_i16x16_dir[I_PRED_16x16_P] += lambda * bs_size_ue(3); COPY2_IF_LT( a->i_satd_i16x16, a->i_satd_i16x16_dir[I_PRED_16x16_P], a->i_predict16x16, 3 ); } @@ -862,7 +852,7 @@ static void x264_mb_analyse_intra( x264_t *h, x264_mb_analysis_t *a, int i_satd_ else h->predict_16x16[i_mode]( p_dst ); - i_satd = h->pixf.mbcmp[PIXEL_16x16]( p_dst, FDEC_STRIDE, p_src, FENC_STRIDE ) + + i_satd = h->pixf.mbcmp[PIXEL_16x16]( p_src, FENC_STRIDE, p_dst, FDEC_STRIDE ) + lambda * bs_size_ue( x264_mb_pred_mode16x16_fix[i_mode] ); COPY2_IF_LT( a->i_satd_i16x16, i_satd, a->i_predict16x16, i_mode ); a->i_satd_i16x16_dir[i_mode] = i_satd; @@ -1065,7 +1055,7 @@ static void x264_mb_analyse_intra( x264_t *h, x264_mb_analysis_t *a, int i_satd_ else h->predict_4x4[i_mode]( p_dst_by ); - i_satd = h->pixf.mbcmp[PIXEL_4x4]( p_dst_by, FDEC_STRIDE, p_src_by, FENC_STRIDE ); + i_satd = h->pixf.mbcmp[PIXEL_4x4]( p_src_by, FENC_STRIDE, p_dst_by, FDEC_STRIDE ); if( i_pred_mode == x264_mb_pred_mode4x4_fix(i_mode) ) { i_satd -= lambda * 3; @@ -1735,7 +1725,7 @@ static void x264_mb_analyse_inter_p8x16( x264_t *h, x264_mb_analysis_t *a, int i static ALWAYS_INLINE int x264_mb_analyse_inter_p4x4_chroma_internal( x264_t *h, x264_mb_analysis_t *a, pixel **p_fref, int i8x8, int size, int chroma ) { - ALIGNED_ARRAY_N( pixel, pix1,[16*16] ); + ALIGNED_ARRAY_32( pixel, pix1,[16*16] ); pixel *pix2 = pix1+8; int i_stride = h->mb.pic.i_stride[1]; int chroma_h_shift = chroma <= CHROMA_422; @@ -1919,8 +1909,8 @@ static void x264_mb_analyse_inter_p4x8( x264_t *h, x264_mb_analysis_t *a, int i8 static ALWAYS_INLINE int x264_analyse_bi_chroma( x264_t *h, x264_mb_analysis_t *a, int idx, int i_pixel ) { - ALIGNED_ARRAY_N( pixel, pix, [4],[16*16] ); - ALIGNED_ARRAY_N( pixel, bi, [2],[16*16] ); + ALIGNED_ARRAY_32( pixel, pix, [4],[16*16] ); + ALIGNED_ARRAY_32( pixel, bi, [2],[16*16] ); int i_chroma_cost = 0; int chromapix = h->luma2chroma_pixel[i_pixel]; @@ -2013,8 +2003,8 @@ static void x264_mb_analyse_inter_direct( x264_t *h, x264_mb_analysis_t *a ) static void x264_mb_analyse_inter_b16x16( x264_t *h, x264_mb_analysis_t *a ) { - ALIGNED_ARRAY_N( pixel, pix0,[16*16] ); - ALIGNED_ARRAY_N( pixel, pix1,[16*16] ); + ALIGNED_ARRAY_32( pixel, pix0,[16*16] ); + ALIGNED_ARRAY_32( pixel, pix1,[16*16] ); pixel *src0, *src1; intptr_t stride0 = 16, stride1 = 16; int i_ref, i_mvc; @@ -2147,7 +2137,7 @@ static void x264_mb_analyse_inter_b16x16( x264_t *h, x264_mb_analysis_t *a ) } else { - ALIGNED_ARRAY_N( pixel, pixuv, [2],[16*FENC_STRIDE] ); + ALIGNED_ARRAY_32( pixel, pixuv, [2],[16*FENC_STRIDE] ); int chromapix = h->luma2chroma_pixel[PIXEL_16x16]; int v_shift = CHROMA_V_SHIFT; @@ -2483,7 +2473,7 @@ static void x264_mb_analyse_inter_b8x8( x264_t *h, x264_mb_analysis_t *a ) static void x264_mb_analyse_inter_b16x8( x264_t *h, x264_mb_analysis_t *a, int i_best_satd ) { - ALIGNED_ARRAY_N( pixel, pix,[2],[16*8] ); + ALIGNED_ARRAY_32( pixel, pix,[2],[16*8] ); ALIGNED_4( int16_t mvc[3][2] ); h->mb.i_partition = D_16x8; diff --git a/library/src/main/cpp/libx264/encoder/cabac.c b/library/src/main/cpp/libx264/encoder/cabac.c index 27052cd..9debd1e 100644 --- a/library/src/main/cpp/libx264/encoder/cabac.c +++ b/library/src/main/cpp/libx264/encoder/cabac.c @@ -801,7 +801,7 @@ void x264_cabac_block_residual_c( x264_t *h, x264_cabac_t *cb, int ctx_block_cat static void ALWAYS_INLINE x264_cabac_block_residual( x264_t *h, x264_cabac_t *cb, int ctx_block_cat, dctcoef *l ) { -#if ARCH_X86_64 && HAVE_MMX +#if ARCH_X86_64 && HAVE_MMX && !defined( __MACH__ ) h->bsf.cabac_block_residual_internal( l, MB_INTERLACED, ctx_block_cat, cb ); #else x264_cabac_block_residual_c( h, cb, ctx_block_cat, l ); @@ -915,7 +915,7 @@ void x264_cabac_block_residual_rd_c( x264_t *h, x264_cabac_t *cb, int ctx_block_ static ALWAYS_INLINE void x264_cabac_block_residual_8x8( x264_t *h, x264_cabac_t *cb, int ctx_block_cat, dctcoef *l ) { -#if ARCH_X86_64 && HAVE_MMX +#if ARCH_X86_64 && HAVE_MMX && !defined( __MACH__ ) h->bsf.cabac_block_residual_8x8_rd_internal( l, MB_INTERLACED, ctx_block_cat, cb ); #else x264_cabac_block_residual_8x8_rd_c( h, cb, ctx_block_cat, l ); @@ -923,7 +923,7 @@ static ALWAYS_INLINE void x264_cabac_block_residual_8x8( x264_t *h, x264_cabac_t } static ALWAYS_INLINE void x264_cabac_block_residual( x264_t *h, x264_cabac_t *cb, int ctx_block_cat, dctcoef *l ) { -#if ARCH_X86_64 && HAVE_MMX +#if ARCH_X86_64 && HAVE_MMX && !defined( __MACH__ ) h->bsf.cabac_block_residual_rd_internal( l, MB_INTERLACED, ctx_block_cat, cb ); #else x264_cabac_block_residual_rd_c( h, cb, ctx_block_cat, l ); @@ -1057,29 +1057,29 @@ static ALWAYS_INLINE void x264_macroblock_write_cabac_internal( x264_t *h, x264_ src = dst; #define MUNGE_8x8_NNZ( MUNGE )\ -if( (h->mb.i_neighbour & MB_LEFT) && !h->mb.mb_transform_size[h->mb.i_mb_left_xy[0]] )\ +if( (h->mb.i_neighbour & MB_LEFT) && !h->mb.mb_transform_size[h->mb.i_mb_left_xy[0]] && !(h->mb.cbp[h->mb.i_mb_left_xy[0]] & 0x1000) )\ {\ - MUNGE( nnzbak[0][0], h->mb.cache.non_zero_count[x264_scan8[16*0+ 0] - 1], 0x80 )\ - MUNGE( nnzbak[0][1], h->mb.cache.non_zero_count[x264_scan8[16*0+ 2] - 1], 0x80 )\ - MUNGE( nnzbak[1][0], h->mb.cache.non_zero_count[x264_scan8[16*1+ 0] - 1], 0x80 )\ - MUNGE( nnzbak[1][1], h->mb.cache.non_zero_count[x264_scan8[16*1+ 2] - 1], 0x80 )\ - MUNGE( nnzbak[2][0], h->mb.cache.non_zero_count[x264_scan8[16*2+ 0] - 1], 0x80 )\ - MUNGE( nnzbak[2][1], h->mb.cache.non_zero_count[x264_scan8[16*2+ 2] - 1], 0x80 )\ + MUNGE( nnzbak[0][0], h->mb.cache.non_zero_count[x264_scan8[16*0+ 0] - 1], 0x00 )\ + MUNGE( nnzbak[0][1], h->mb.cache.non_zero_count[x264_scan8[16*0+ 2] - 1], 0x00 )\ + MUNGE( nnzbak[1][0], h->mb.cache.non_zero_count[x264_scan8[16*1+ 0] - 1], 0x00 )\ + MUNGE( nnzbak[1][1], h->mb.cache.non_zero_count[x264_scan8[16*1+ 2] - 1], 0x00 )\ + MUNGE( nnzbak[2][0], h->mb.cache.non_zero_count[x264_scan8[16*2+ 0] - 1], 0x00 )\ + MUNGE( nnzbak[2][1], h->mb.cache.non_zero_count[x264_scan8[16*2+ 2] - 1], 0x00 )\ }\ -if( (h->mb.i_neighbour & MB_LEFT) && !h->mb.mb_transform_size[h->mb.i_mb_left_xy[1]] )\ +if( (h->mb.i_neighbour & MB_LEFT) && !h->mb.mb_transform_size[h->mb.i_mb_left_xy[1]] && !(h->mb.cbp[h->mb.i_mb_left_xy[1]] & 0x1000) )\ {\ - MUNGE( nnzbak[0][2], h->mb.cache.non_zero_count[x264_scan8[16*0+ 8] - 1], 0x80 )\ - MUNGE( nnzbak[0][3], h->mb.cache.non_zero_count[x264_scan8[16*0+10] - 1], 0x80 )\ - MUNGE( nnzbak[1][2], h->mb.cache.non_zero_count[x264_scan8[16*1+ 8] - 1], 0x80 )\ - MUNGE( nnzbak[1][3], h->mb.cache.non_zero_count[x264_scan8[16*1+10] - 1], 0x80 )\ - MUNGE( nnzbak[2][2], h->mb.cache.non_zero_count[x264_scan8[16*2+ 8] - 1], 0x80 )\ - MUNGE( nnzbak[2][3], h->mb.cache.non_zero_count[x264_scan8[16*2+10] - 1], 0x80 )\ + MUNGE( nnzbak[0][2], h->mb.cache.non_zero_count[x264_scan8[16*0+ 8] - 1], 0x00 )\ + MUNGE( nnzbak[0][3], h->mb.cache.non_zero_count[x264_scan8[16*0+10] - 1], 0x00 )\ + MUNGE( nnzbak[1][2], h->mb.cache.non_zero_count[x264_scan8[16*1+ 8] - 1], 0x00 )\ + MUNGE( nnzbak[1][3], h->mb.cache.non_zero_count[x264_scan8[16*1+10] - 1], 0x00 )\ + MUNGE( nnzbak[2][2], h->mb.cache.non_zero_count[x264_scan8[16*2+ 8] - 1], 0x00 )\ + MUNGE( nnzbak[2][3], h->mb.cache.non_zero_count[x264_scan8[16*2+10] - 1], 0x00 )\ }\ -if( (h->mb.i_neighbour & MB_TOP) && !h->mb.mb_transform_size[h->mb.i_mb_top_xy] )\ +if( (h->mb.i_neighbour & MB_TOP) && !h->mb.mb_transform_size[h->mb.i_mb_top_xy] && !(h->mb.cbp[h->mb.i_mb_top_xy] & 0x1000) )\ {\ - MUNGE( M32( &nnzbak[0][4] ), M32( &h->mb.cache.non_zero_count[x264_scan8[16*0] - 8] ), 0x80808080U )\ - MUNGE( M32( &nnzbak[1][4] ), M32( &h->mb.cache.non_zero_count[x264_scan8[16*1] - 8] ), 0x80808080U )\ - MUNGE( M32( &nnzbak[2][4] ), M32( &h->mb.cache.non_zero_count[x264_scan8[16*2] - 8] ), 0x80808080U )\ + MUNGE( M32( &nnzbak[0][4] ), M32( &h->mb.cache.non_zero_count[x264_scan8[16*0] - 8] ), 0x00000000U )\ + MUNGE( M32( &nnzbak[1][4] ), M32( &h->mb.cache.non_zero_count[x264_scan8[16*1] - 8] ), 0x00000000U )\ + MUNGE( M32( &nnzbak[2][4] ), M32( &h->mb.cache.non_zero_count[x264_scan8[16*2] - 8] ), 0x00000000U )\ } MUNGE_8x8_NNZ( BACKUP ) diff --git a/library/src/main/cpp/libx264/encoder/encoder.c b/library/src/main/cpp/libx264/encoder/encoder.c index 27db1bd..d183460 100644 --- a/library/src/main/cpp/libx264/encoder/encoder.c +++ b/library/src/main/cpp/libx264/encoder/encoder.c @@ -444,11 +444,6 @@ static int x264_validate_parameters( x264_t *h, int b_open ) fail = 1; } #endif - if( !fail && !(cpuflags & X264_CPU_CMOV) ) - { - x264_log( h, X264_LOG_ERROR, "your cpu does not support CMOV, but x264 was compiled with asm\n"); - fail = 1; - } if( fail ) { x264_log( h, X264_LOG_ERROR, "to run x264, recompile without asm (configure --disable-asm)\n"); @@ -494,7 +489,8 @@ static int x264_validate_parameters( x264_t *h, int b_open ) #endif if( i_csp <= X264_CSP_NONE || i_csp >= X264_CSP_MAX ) { - x264_log( h, X264_LOG_ERROR, "invalid CSP (only I420/YV12/NV12/NV21/I422/YV16/NV16/I444/YV24/BGR/BGRA/RGB supported)\n" ); + x264_log( h, X264_LOG_ERROR, "invalid CSP (only I420/YV12/NV12/NV21/I422/YV16/NV16/YUYV/UYVY/" + "I444/YV24/BGR/BGRA/RGB supported)\n" ); return -1; } @@ -859,6 +855,11 @@ static int x264_validate_parameters( x264_t *h, int b_open ) h->param.analyse.inter &= ~X264_ANALYSE_I8x8; h->param.analyse.intra &= ~X264_ANALYSE_I8x8; } + if( i_csp >= X264_CSP_I444 && h->param.b_cabac ) + { + /* Disable 8x8dct during 4:4:4+CABAC encoding for compatibility with libavcodec */ + h->param.analyse.b_transform_8x8 = 0; + } if( h->param.rc.i_rc_method == X264_RC_CQP ) { float qp_p = h->param.rc.i_qp_constant; @@ -1170,7 +1171,7 @@ static int x264_validate_parameters( x264_t *h, int b_open ) if( h->param.analyse.i_mv_range <= 0 ) h->param.analyse.i_mv_range = l->mv_range >> PARAM_INTERLACED; else - h->param.analyse.i_mv_range = x264_clip3(h->param.analyse.i_mv_range, 32, 512 >> PARAM_INTERLACED); + h->param.analyse.i_mv_range = x264_clip3(h->param.analyse.i_mv_range, 32, 8192 >> PARAM_INTERLACED); } h->param.analyse.i_weighted_pred = x264_clip3( h->param.analyse.i_weighted_pred, X264_WEIGHTP_NONE, X264_WEIGHTP_SMART ); @@ -1530,6 +1531,12 @@ x264_t *x264_encoder_open( x264_param_t *param ) x264_rdo_init(); /* init CPU functions */ +#if (ARCH_X86 || ARCH_X86_64) && HIGH_BIT_DEPTH + /* FIXME: Only 8-bit has been optimized for AVX-512 so far. The few AVX-512 functions + * enabled in high bit-depth are insignificant and just causes potential issues with + * unnecessary thermal throttling and whatnot, so keep it disabled for now. */ + h->param.cpu &= ~X264_CPU_AVX512; +#endif x264_predict_16x16_init( h->param.cpu, h->predict_16x16 ); x264_predict_8x8c_init( h->param.cpu, h->predict_8x8c ); x264_predict_8x16c_init( h->param.cpu, h->predict_8x16c ); @@ -1566,9 +1573,15 @@ x264_t *x264_encoder_open( x264_param_t *param ) if( !strcmp(x264_cpu_names[i].name, "SSE4.1") && (h->param.cpu & X264_CPU_SSE42) ) continue; + if( !strcmp(x264_cpu_names[i].name, "LZCNT") + && (h->param.cpu & X264_CPU_BMI1) ) + continue; if( !strcmp(x264_cpu_names[i].name, "BMI1") && (h->param.cpu & X264_CPU_BMI2) ) continue; + if( !strcmp(x264_cpu_names[i].name, "FMA4") + && (h->param.cpu & X264_CPU_FMA3) ) + continue; if( (h->param.cpu & x264_cpu_names[i].flags) == x264_cpu_names[i].flags && (!i || x264_cpu_names[i].flags != x264_cpu_names[i-1].flags) ) p += sprintf( p, " %s", x264_cpu_names[i].name ); @@ -1580,14 +1593,6 @@ x264_t *x264_encoder_open( x264_param_t *param ) if( x264_analyse_init_costs( h ) ) goto fail; - static const uint16_t cost_mv_correct[7] = { 24, 47, 95, 189, 379, 757, 1515 }; - /* Checks for known miscompilation issues. */ - if( h->cost_mv[X264_LOOKAHEAD_QP][2013] != cost_mv_correct[BIT_DEPTH-8] ) - { - x264_log( h, X264_LOG_ERROR, "MV cost test failed: x264 has been miscompiled!\n" ); - goto fail; - } - /* Must be volatile or else GCC will optimize it out. */ volatile int temp = 392; if( x264_clz( temp ) != 23 ) diff --git a/library/src/main/cpp/libx264/encoder/macroblock.c b/library/src/main/cpp/libx264/encoder/macroblock.c index 87ba7f2..929fcc8 100644 --- a/library/src/main/cpp/libx264/encoder/macroblock.c +++ b/library/src/main/cpp/libx264/encoder/macroblock.c @@ -128,8 +128,8 @@ static void x264_mb_encode_i16x16( x264_t *h, int p, int i_qp ) pixel *p_src = h->mb.pic.p_fenc[p]; pixel *p_dst = h->mb.pic.p_fdec[p]; - ALIGNED_ARRAY_N( dctcoef, dct4x4,[16],[16] ); - ALIGNED_ARRAY_N( dctcoef, dct_dc4x4,[16] ); + ALIGNED_ARRAY_64( dctcoef, dct4x4,[16],[16] ); + ALIGNED_ARRAY_64( dctcoef, dct_dc4x4,[16] ); int nz, block_cbp = 0; int decimate_score = h->mb.b_dct_decimate ? 0 : 9; @@ -283,13 +283,10 @@ static ALWAYS_INLINE void x264_mb_encode_chroma_internal( x264_t *h, int b_inter if( b_decimate && i_qp >= (h->mb.b_trellis ? 12 : 18) && !h->mb.b_noise_reduction ) { int thresh = chroma422 ? (x264_lambda2_tab[i_qp] + 16) >> 5 : (x264_lambda2_tab[i_qp] + 32) >> 6; - int ssd[2]; + ALIGNED_ARRAY_8( int, ssd,[2] ); int chromapix = chroma422 ? PIXEL_8x16 : PIXEL_8x8; - int score = h->pixf.var2[chromapix]( h->mb.pic.p_fenc[1], FENC_STRIDE, h->mb.pic.p_fdec[1], FDEC_STRIDE, &ssd[0] ); - if( score < thresh*4 ) - score += h->pixf.var2[chromapix]( h->mb.pic.p_fenc[2], FENC_STRIDE, h->mb.pic.p_fdec[2], FDEC_STRIDE, &ssd[1] ); - if( score < thresh*4 ) + if( h->pixf.var2[chromapix]( h->mb.pic.p_fenc[1], h->mb.pic.p_fdec[1], ssd ) < thresh*4 ) { h->mb.cache.non_zero_count[x264_scan8[CHROMA_DC+0]] = 0; h->mb.cache.non_zero_count[x264_scan8[CHROMA_DC+1]] = 0; @@ -350,7 +347,7 @@ static ALWAYS_INLINE void x264_mb_encode_chroma_internal( x264_t *h, int b_inter int i_decimate_score = b_decimate ? 0 : 7; int nz_ac = 0; - ALIGNED_ARRAY_N( dctcoef, dct4x4,[8],[16] ); + ALIGNED_ARRAY_64( dctcoef, dct4x4,[8],[16] ); if( h->mb.b_lossless ) { @@ -561,9 +558,16 @@ void x264_predict_lossless_4x4( x264_t *h, pixel *p_dst, int p, int idx, int i_m pixel *p_src = h->mb.pic.p_fenc_plane[p] + block_idx_x[idx]*4 + block_idx_y[idx]*4 * stride; if( i_mode == I_PRED_4x4_V ) + { h->mc.copy[PIXEL_4x4]( p_dst, FDEC_STRIDE, p_src-stride, stride, 4 ); + memcpy( p_dst, p_dst-FDEC_STRIDE, 4*sizeof(pixel) ); + } else if( i_mode == I_PRED_4x4_H ) + { h->mc.copy[PIXEL_4x4]( p_dst, FDEC_STRIDE, p_src-1, stride, 4 ); + for( int i = 0; i < 4; i++ ) + p_dst[i*FDEC_STRIDE] = p_dst[i*FDEC_STRIDE-1]; + } else h->predict_4x4[i_mode]( p_dst ); } @@ -574,9 +578,16 @@ void x264_predict_lossless_8x8( x264_t *h, pixel *p_dst, int p, int idx, int i_m pixel *p_src = h->mb.pic.p_fenc_plane[p] + (idx&1)*8 + (idx>>1)*8*stride; if( i_mode == I_PRED_8x8_V ) + { h->mc.copy[PIXEL_8x8]( p_dst, FDEC_STRIDE, p_src-stride, stride, 8 ); + memcpy( p_dst, &edge[16], 8*sizeof(pixel) ); + } else if( i_mode == I_PRED_8x8_H ) + { h->mc.copy[PIXEL_8x8]( p_dst, FDEC_STRIDE, p_src-1, stride, 8 ); + for( int i = 0; i < 8; i++ ) + p_dst[i*FDEC_STRIDE] = edge[14-i]; + } else h->predict_8x8[i_mode]( p_dst, edge ); } @@ -584,12 +595,21 @@ void x264_predict_lossless_8x8( x264_t *h, pixel *p_dst, int p, int idx, int i_m void x264_predict_lossless_16x16( x264_t *h, int p, int i_mode ) { int stride = h->fenc->i_stride[p] << MB_INTERLACED; + pixel *p_dst = h->mb.pic.p_fdec[p]; + if( i_mode == I_PRED_16x16_V ) - h->mc.copy[PIXEL_16x16]( h->mb.pic.p_fdec[p], FDEC_STRIDE, h->mb.pic.p_fenc_plane[p]-stride, stride, 16 ); + { + h->mc.copy[PIXEL_16x16]( p_dst, FDEC_STRIDE, h->mb.pic.p_fenc_plane[p]-stride, stride, 16 ); + memcpy( p_dst, p_dst-FDEC_STRIDE, 16*sizeof(pixel) ); + } else if( i_mode == I_PRED_16x16_H ) - h->mc.copy_16x16_unaligned( h->mb.pic.p_fdec[p], FDEC_STRIDE, h->mb.pic.p_fenc_plane[p]-1, stride, 16 ); + { + h->mc.copy_16x16_unaligned( p_dst, FDEC_STRIDE, h->mb.pic.p_fenc_plane[p]-1, stride, 16 ); + for( int i = 0; i < 16; i++ ) + p_dst[i*FDEC_STRIDE] = p_dst[i*FDEC_STRIDE-1]; + } else - h->predict_16x16[i_mode]( h->mb.pic.p_fdec[p] ); + h->predict_16x16[i_mode]( p_dst ); } /***************************************************************************** @@ -780,7 +800,7 @@ static ALWAYS_INLINE void x264_macroblock_encode_internal( x264_t *h, int plane_ } else if( h->mb.b_transform_8x8 ) { - ALIGNED_ARRAY_N( dctcoef, dct8x8,[4],[64] ); + ALIGNED_ARRAY_64( dctcoef, dct8x8,[4],[64] ); b_decimate &= !h->mb.b_trellis || !h->param.b_cabac; // 8x8 trellis is inherently optimal decimation for CABAC for( int p = 0; p < plane_count; p++, i_qp = h->mb.i_chroma_qp ) @@ -824,7 +844,7 @@ static ALWAYS_INLINE void x264_macroblock_encode_internal( x264_t *h, int plane_ } else { - ALIGNED_ARRAY_N( dctcoef, dct4x4,[16],[16] ); + ALIGNED_ARRAY_64( dctcoef, dct4x4,[16],[16] ); for( int p = 0; p < plane_count; p++, i_qp = h->mb.i_chroma_qp ) { int quant_cat = p ? CQM_4PC : CQM_4PY; @@ -965,8 +985,8 @@ void x264_macroblock_encode( x264_t *h ) *****************************************************************************/ static ALWAYS_INLINE int x264_macroblock_probe_skip_internal( x264_t *h, int b_bidir, int plane_count, int chroma ) { - ALIGNED_ARRAY_N( dctcoef, dct4x4,[8],[16] ); - ALIGNED_ARRAY_16( dctcoef, dctscan,[16] ); + ALIGNED_ARRAY_64( dctcoef, dct4x4,[8],[16] ); + ALIGNED_ARRAY_64( dctcoef, dctscan,[16] ); ALIGNED_4( int16_t mvp[2] ); int i_qp = h->mb.i_qp; @@ -1219,7 +1239,7 @@ static ALWAYS_INLINE void x264_macroblock_encode_p8x8_internal( x264_t *h, int i int quant_cat = p ? CQM_8PC : CQM_8PY; pixel *p_fenc = h->mb.pic.p_fenc[p] + 8*x + 8*y*FENC_STRIDE; pixel *p_fdec = h->mb.pic.p_fdec[p] + 8*x + 8*y*FDEC_STRIDE; - ALIGNED_ARRAY_N( dctcoef, dct8x8,[64] ); + ALIGNED_ARRAY_64( dctcoef, dct8x8,[64] ); h->dctf.sub8x8_dct8( dct8x8, p_fenc, p_fdec ); int nnz8x8 = x264_quant_8x8( h, dct8x8, i_qp, ctx_cat_plane[DCT_LUMA_8x8][p], 0, p, i8 ); @@ -1252,7 +1272,7 @@ static ALWAYS_INLINE void x264_macroblock_encode_p8x8_internal( x264_t *h, int i pixel *p_fenc = h->mb.pic.p_fenc[p] + 8*x + 8*y*FENC_STRIDE; pixel *p_fdec = h->mb.pic.p_fdec[p] + 8*x + 8*y*FDEC_STRIDE; int i_decimate_8x8 = b_decimate ? 0 : 4; - ALIGNED_ARRAY_N( dctcoef, dct4x4,[4],[16] ); + ALIGNED_ARRAY_64( dctcoef, dct4x4,[4],[16] ); int nnz8x8 = 0; h->dctf.sub8x8_dct( dct4x4, p_fenc, p_fdec ); @@ -1311,7 +1331,7 @@ static ALWAYS_INLINE void x264_macroblock_encode_p8x8_internal( x264_t *h, int i i_qp = h->mb.i_chroma_qp; for( int ch = 0; ch < 2; ch++ ) { - ALIGNED_ARRAY_N( dctcoef, dct4x4,[2],[16] ); + ALIGNED_ARRAY_64( dctcoef, dct4x4,[2],[16] ); pixel *p_fenc = h->mb.pic.p_fenc[1+ch] + 4*x + (chroma422?8:4)*y*FENC_STRIDE; pixel *p_fdec = h->mb.pic.p_fdec[1+ch] + 4*x + (chroma422?8:4)*y*FDEC_STRIDE; @@ -1376,7 +1396,7 @@ static ALWAYS_INLINE void x264_macroblock_encode_p4x4_internal( x264_t *h, int i } else { - ALIGNED_ARRAY_N( dctcoef, dct4x4,[16] ); + ALIGNED_ARRAY_64( dctcoef, dct4x4,[16] ); h->dctf.sub4x4_dct( dct4x4, p_fenc, p_fdec ); nz = x264_quant_4x4( h, dct4x4, i_qp, ctx_cat_plane[DCT_LUMA_4x4][p], 0, p, i4 ); h->mb.cache.non_zero_count[x264_scan8[p*16+i4]] = nz; diff --git a/library/src/main/cpp/libx264/encoder/macroblock.h b/library/src/main/cpp/libx264/encoder/macroblock.h index 0bf2711..1c901a8 100644 --- a/library/src/main/cpp/libx264/encoder/macroblock.h +++ b/library/src/main/cpp/libx264/encoder/macroblock.h @@ -55,6 +55,9 @@ void x264_macroblock_encode_p4x4( x264_t *h, int i4 ); void x264_mb_encode_chroma( x264_t *h, int b_inter, int i_qp ); void x264_cabac_mb_skip( x264_t *h, int b_skip ); +void x264_cabac_block_residual_c( x264_t *h, x264_cabac_t *cb, int ctx_block_cat, dctcoef *l ); +void x264_cabac_block_residual_8x8_rd_c( x264_t *h, x264_cabac_t *cb, int ctx_block_cat, dctcoef *l ); +void x264_cabac_block_residual_rd_c( x264_t *h, x264_cabac_t *cb, int ctx_block_cat, dctcoef *l ); int x264_quant_luma_dc_trellis( x264_t *h, dctcoef *dct, int i_quant_cat, int i_qp, int ctx_block_cat, int b_intra, int idx ); @@ -113,7 +116,7 @@ static ALWAYS_INLINE void x264_mb_encode_i4x4( x264_t *h, int p, int idx, int i_ int nz; pixel *p_src = &h->mb.pic.p_fenc[p][block_idx_xy_fenc[idx]]; pixel *p_dst = &h->mb.pic.p_fdec[p][block_idx_xy_fdec[idx]]; - ALIGNED_ARRAY_N( dctcoef, dct4x4,[16] ); + ALIGNED_ARRAY_64( dctcoef, dct4x4,[16] ); if( b_predict ) { @@ -151,7 +154,7 @@ static ALWAYS_INLINE void x264_mb_encode_i8x8( x264_t *h, int p, int idx, int i_ int nz; pixel *p_src = &h->mb.pic.p_fenc[p][8*x + 8*y*FENC_STRIDE]; pixel *p_dst = &h->mb.pic.p_fdec[p][8*x + 8*y*FDEC_STRIDE]; - ALIGNED_ARRAY_N( dctcoef, dct8x8,[64] ); + ALIGNED_ARRAY_64( dctcoef, dct8x8,[64] ); ALIGNED_ARRAY_32( pixel, edge_buf,[36] ); if( b_predict ) diff --git a/library/src/main/cpp/libx264/encoder/me.c b/library/src/main/cpp/libx264/encoder/me.c index 310bff7..094fc5d 100644 --- a/library/src/main/cpp/libx264/encoder/me.c +++ b/library/src/main/cpp/libx264/encoder/me.c @@ -191,7 +191,7 @@ void x264_me_search_ref( x264_t *h, x264_me_t *m, int16_t (*mvc)[2], int i_mvc, int omx, omy, pmx, pmy; pixel *p_fenc = m->p_fenc[0]; pixel *p_fref_w = m->p_fref_w; - ALIGNED_ARRAY_N( pixel, pix,[16*16] ); + ALIGNED_ARRAY_32( pixel, pix,[16*16] ); ALIGNED_ARRAY_8( int16_t, mvc_temp,[16],[2] ); ALIGNED_ARRAY_16( int, costs,[16] ); @@ -875,7 +875,7 @@ static void refine_subpel( x264_t *h, x264_me_t *m, int hpel_iters, int qpel_ite int chroma_v_shift = CHROMA_V_SHIFT; int mvy_offset = chroma_v_shift & MB_INTERLACED & m->i_ref ? (h->mb.i_mb_y & 1)*4 - 2 : 0; - ALIGNED_ARRAY_N( pixel, pix,[64*18] ); // really 17x17x2, but round up for alignment + ALIGNED_ARRAY_32( pixel, pix,[64*18] ); // really 17x17x2, but round up for alignment ALIGNED_ARRAY_16( int, costs,[4] ); int bmx = m->mv[0]; @@ -1034,9 +1034,9 @@ static void ALWAYS_INLINE x264_me_refine_bidir( x264_t *h, x264_me_t *m0, x264_m const int i_pixel = m0->i_pixel; const int bw = x264_pixel_size[i_pixel].w; const int bh = x264_pixel_size[i_pixel].h; - ALIGNED_ARRAY_N( pixel, pixy_buf,[2],[9][16*16] ); - ALIGNED_ARRAY_N( pixel, pixu_buf,[2],[9][16*16] ); - ALIGNED_ARRAY_N( pixel, pixv_buf,[2],[9][16*16] ); + ALIGNED_ARRAY_32( pixel, pixy_buf,[2],[9][16*16] ); + ALIGNED_ARRAY_32( pixel, pixu_buf,[2],[9][16*16] ); + ALIGNED_ARRAY_32( pixel, pixv_buf,[2],[9][16*16] ); pixel *src[3][2][9]; int chromapix = h->luma2chroma_pixel[i_pixel]; int chroma_v_shift = CHROMA_V_SHIFT; @@ -1059,7 +1059,7 @@ static void ALWAYS_INLINE x264_me_refine_bidir( x264_t *h, x264_me_t *m0, x264_m uint64_t bcostrd = COST_MAX64; uint16_t amvd; /* each byte of visited represents 8 possible m1y positions, so a 4D array isn't needed */ - ALIGNED_ARRAY_N( uint8_t, visited,[8],[8][8] ); + ALIGNED_ARRAY_64( uint8_t, visited,[8],[8][8] ); /* all permutations of an offset in up to 2 of the dimensions */ ALIGNED_4( static const int8_t dia4d[33][4] ) = { diff --git a/library/src/main/cpp/libx264/encoder/me.h b/library/src/main/cpp/libx264/encoder/me.h index 305c42d..505e3ce 100644 --- a/library/src/main/cpp/libx264/encoder/me.h +++ b/library/src/main/cpp/libx264/encoder/me.h @@ -32,10 +32,10 @@ typedef struct { - /* aligning the first member is a gcc hack to force the struct to be - * 16 byte aligned, as well as force sizeof(struct) to be a multiple of 16 */ + /* aligning the first member is a gcc hack to force the struct to be aligned, + * as well as force sizeof(struct) to be a multiple of the alignment. */ /* input */ - ALIGNED_16( int i_pixel ); /* PIXEL_WxH */ + ALIGNED_64( int i_pixel ); /* PIXEL_WxH */ uint16_t *p_cost_mv; /* lambda * nbits for each possible mv */ int i_ref_cost; int i_ref; @@ -53,7 +53,7 @@ typedef struct int cost_mv; /* lambda * nbits for the chosen mv */ int cost; /* satd + lambda * nbits */ ALIGNED_4( int16_t mv[2] ); -} ALIGNED_16( x264_me_t ); +} ALIGNED_64( x264_me_t ); void x264_me_search_ref( x264_t *h, x264_me_t *m, int16_t (*mvc)[2], int i_mvc, int *p_fullpel_thresh ); #define x264_me_search( h, m, mvc, i_mvc )\ @@ -66,8 +66,6 @@ void x264_me_refine_bidir_rd( x264_t *h, x264_me_t *m0, x264_me_t *m1, int i_wei void x264_me_refine_bidir_satd( x264_t *h, x264_me_t *m0, x264_me_t *m1, int i_weight ); uint64_t x264_rd_cost_part( x264_t *h, int i_lambda2, int i8, int i_pixel ); -extern uint16_t *x264_cost_mv_fpel[QP_MAX+1][4]; - #define COPY1_IF_LT(x,y)\ if( (y) < (x) )\ (x) = (y); diff --git a/library/src/main/cpp/libx264/encoder/ratecontrol.c b/library/src/main/cpp/libx264/encoder/ratecontrol.c index dbccb27..5289316 100644 --- a/library/src/main/cpp/libx264/encoder/ratecontrol.c +++ b/library/src/main/cpp/libx264/encoder/ratecontrol.c @@ -243,7 +243,7 @@ static ALWAYS_INLINE uint32_t ac_energy_plane( x264_t *h, int mb_x, int mb_y, x2 stride <<= b_field; if( b_chroma ) { - ALIGNED_ARRAY_N( pixel, pix,[FENC_STRIDE*16] ); + ALIGNED_ARRAY_32( pixel, pix,[FENC_STRIDE*16] ); int chromapix = h->luma2chroma_pixel[PIXEL_16x16]; int shift = 7 - CHROMA_V_SHIFT; @@ -420,7 +420,7 @@ static int x264_macroblock_tree_rescale_init( x264_t *h, x264_ratecontrol_t *rc float dstdim[2] = { h->param.i_width / 16.f, h->param.i_height / 16.f}; int srcdimi[2] = {ceil(srcdim[0]), ceil(srcdim[1])}; int dstdimi[2] = {ceil(dstdim[0]), ceil(dstdim[1])}; - if( PARAM_INTERLACED ) + if( h->param.b_interlaced || h->param.b_fake_interlaced ) { srcdimi[1] = (srcdimi[1]+1)&~1; dstdimi[1] = (dstdimi[1]+1)&~1; @@ -1469,7 +1469,7 @@ void x264_ratecontrol_start( x264_t *h, int i_force_qp, int overhead ) if( h->i_frame == 0 ) { //384 * ( Max( PicSizeInMbs, fR * MaxMBPS ) + MaxMBPS * ( tr( 0 ) - tr,n( 0 ) ) ) / MinCR - double fr = 1. / 172; + double fr = 1. / (h->param.i_level_idc >= 60 ? 300 : 172); int pic_size_in_mbs = h->mb.i_mb_width * h->mb.i_mb_height; rc->frame_size_maximum = 384 * BIT_DEPTH * X264_MAX( pic_size_in_mbs, fr*l->mbps ) / mincr; } diff --git a/library/src/main/cpp/libx264/encoder/ratecontrol.h b/library/src/main/cpp/libx264/encoder/ratecontrol.h index c5b95cb..168b515 100644 --- a/library/src/main/cpp/libx264/encoder/ratecontrol.h +++ b/library/src/main/cpp/libx264/encoder/ratecontrol.h @@ -58,8 +58,6 @@ int x264_ratecontrol_qp( x264_t * ); int x264_ratecontrol_mb_qp( x264_t *h ); int x264_ratecontrol_end( x264_t *, int bits, int *filler ); void x264_ratecontrol_summary( x264_t * ); -void x264_ratecontrol_set_estimated_size( x264_t *, int bits ); -int x264_ratecontrol_get_estimated_size( x264_t const *); int x264_rc_analyse_slice( x264_t *h ); void x264_threads_distribute_ratecontrol( x264_t *h ); void x264_threads_merge_ratecontrol( x264_t *h ); diff --git a/library/src/main/cpp/libx264/encoder/rdo.c b/library/src/main/cpp/libx264/encoder/rdo.c index cd76682..a6865bd 100644 --- a/library/src/main/cpp/libx264/encoder/rdo.c +++ b/library/src/main/cpp/libx264/encoder/rdo.c @@ -64,9 +64,8 @@ static uint16_t cabac_size_5ones[128]; #include "cabac.c" #define COPY_CABAC h->mc.memcpy_aligned( &cabac_tmp.f8_bits_encoded, &h->cabac.f8_bits_encoded, \ - sizeof(x264_cabac_t) - offsetof(x264_cabac_t,f8_bits_encoded) - (CHROMA444 ? 0 : (1024+12)-460) ) -#define COPY_CABAC_PART( pos, size )\ - memcpy( &cb->state[pos], &h->cabac.state[pos], size ) + sizeof(int) + (CHROMA444 ? 1024+12 : 460) ) +#define COPY_CABAC_PART( pos, size ) memcpy( &cb->state[pos], &h->cabac.state[pos], size ) static ALWAYS_INLINE uint64_t cached_hadamard( x264_t *h, int size, int x, int y ) { @@ -634,8 +633,8 @@ int quant_trellis_cabac( x264_t *h, dctcoef *dct, const uint8_t *zigzag, int ctx_block_cat, int lambda2, int b_ac, int b_chroma, int dc, int num_coefs, int idx ) { - ALIGNED_ARRAY_N( dctcoef, orig_coefs, [64] ); - ALIGNED_ARRAY_N( dctcoef, quant_coefs, [64] ); + ALIGNED_ARRAY_64( dctcoef, orig_coefs, [64] ); + ALIGNED_ARRAY_64( dctcoef, quant_coefs, [64] ); const uint32_t *coef_weight1 = num_coefs == 64 ? x264_dct8_weight_tab : x264_dct4_weight_tab; const uint32_t *coef_weight2 = num_coefs == 64 ? x264_dct8_weight2_tab : x264_dct4_weight2_tab; const int b_interlaced = MB_INTERLACED; @@ -695,7 +694,7 @@ int quant_trellis_cabac( x264_t *h, dctcoef *dct, return !!dct[0]; } -#if HAVE_MMX && ARCH_X86_64 +#if HAVE_MMX && ARCH_X86_64 && !defined( __MACH__ ) #define TRELLIS_ARGS unquant_mf, zigzag, lambda2, last_nnz, orig_coefs, quant_coefs, dct,\ cabac_state_sig, cabac_state_last, M64(cabac_state), M16(cabac_state+8) if( num_coefs == 16 && !dc ) diff --git a/library/src/main/cpp/libx264/encoder/set.c b/library/src/main/cpp/libx264/encoder/set.c index f86189f..2ab4e4e 100644 --- a/library/src/main/cpp/libx264/encoder/set.c +++ b/library/src/main/cpp/libx264/encoder/set.c @@ -783,23 +783,26 @@ int x264_sei_avcintra_vanc_write( x264_t *h, bs_t *s, int len ) const x264_level_t x264_levels[] = { - { 10, 1485, 99, 396, 64, 175, 64, 64, 0, 2, 0, 0, 1 }, - { 9, 1485, 99, 396, 128, 350, 64, 64, 0, 2, 0, 0, 1 }, /* "1b" */ - { 11, 3000, 396, 900, 192, 500, 128, 64, 0, 2, 0, 0, 1 }, - { 12, 6000, 396, 2376, 384, 1000, 128, 64, 0, 2, 0, 0, 1 }, - { 13, 11880, 396, 2376, 768, 2000, 128, 64, 0, 2, 0, 0, 1 }, - { 20, 11880, 396, 2376, 2000, 2000, 128, 64, 0, 2, 0, 0, 1 }, - { 21, 19800, 792, 4752, 4000, 4000, 256, 64, 0, 2, 0, 0, 0 }, - { 22, 20250, 1620, 8100, 4000, 4000, 256, 64, 0, 2, 0, 0, 0 }, - { 30, 40500, 1620, 8100, 10000, 10000, 256, 32, 22, 2, 0, 1, 0 }, - { 31, 108000, 3600, 18000, 14000, 14000, 512, 16, 60, 4, 1, 1, 0 }, - { 32, 216000, 5120, 20480, 20000, 20000, 512, 16, 60, 4, 1, 1, 0 }, - { 40, 245760, 8192, 32768, 20000, 25000, 512, 16, 60, 4, 1, 1, 0 }, - { 41, 245760, 8192, 32768, 50000, 62500, 512, 16, 24, 2, 1, 1, 0 }, - { 42, 522240, 8704, 34816, 50000, 62500, 512, 16, 24, 2, 1, 1, 1 }, - { 50, 589824, 22080, 110400, 135000, 135000, 512, 16, 24, 2, 1, 1, 1 }, - { 51, 983040, 36864, 184320, 240000, 240000, 512, 16, 24, 2, 1, 1, 1 }, - { 52, 2073600, 36864, 184320, 240000, 240000, 512, 16, 24, 2, 1, 1, 1 }, + { 10, 1485, 99, 396, 64, 175, 64, 64, 0, 2, 0, 0, 1 }, + { 9, 1485, 99, 396, 128, 350, 64, 64, 0, 2, 0, 0, 1 }, /* "1b" */ + { 11, 3000, 396, 900, 192, 500, 128, 64, 0, 2, 0, 0, 1 }, + { 12, 6000, 396, 2376, 384, 1000, 128, 64, 0, 2, 0, 0, 1 }, + { 13, 11880, 396, 2376, 768, 2000, 128, 64, 0, 2, 0, 0, 1 }, + { 20, 11880, 396, 2376, 2000, 2000, 128, 64, 0, 2, 0, 0, 1 }, + { 21, 19800, 792, 4752, 4000, 4000, 256, 64, 0, 2, 0, 0, 0 }, + { 22, 20250, 1620, 8100, 4000, 4000, 256, 64, 0, 2, 0, 0, 0 }, + { 30, 40500, 1620, 8100, 10000, 10000, 256, 32, 22, 2, 0, 1, 0 }, + { 31, 108000, 3600, 18000, 14000, 14000, 512, 16, 60, 4, 1, 1, 0 }, + { 32, 216000, 5120, 20480, 20000, 20000, 512, 16, 60, 4, 1, 1, 0 }, + { 40, 245760, 8192, 32768, 20000, 25000, 512, 16, 60, 4, 1, 1, 0 }, + { 41, 245760, 8192, 32768, 50000, 62500, 512, 16, 24, 2, 1, 1, 0 }, + { 42, 522240, 8704, 34816, 50000, 62500, 512, 16, 24, 2, 1, 1, 1 }, + { 50, 589824, 22080, 110400, 135000, 135000, 512, 16, 24, 2, 1, 1, 1 }, + { 51, 983040, 36864, 184320, 240000, 240000, 512, 16, 24, 2, 1, 1, 1 }, + { 52, 2073600, 36864, 184320, 240000, 240000, 512, 16, 24, 2, 1, 1, 1 }, + { 60, 4177920, 139264, 696320, 240000, 240000, 8192, 16, 24, 2, 1, 1, 1 }, + { 61, 8355840, 139264, 696320, 480000, 480000, 8192, 16, 24, 2, 1, 1, 1 }, + { 62, 16711680, 139264, 696320, 800000, 800000, 8192, 16, 24, 2, 1, 1, 1 }, { 0 } }; diff --git a/library/src/main/cpp/libx264/encoder/slicetype.c b/library/src/main/cpp/libx264/encoder/slicetype.c index b20bbf3..6c0aaa8 100644 --- a/library/src/main/cpp/libx264/encoder/slicetype.c +++ b/library/src/main/cpp/libx264/encoder/slicetype.c @@ -267,7 +267,7 @@ static NOINLINE unsigned int x264_weight_cost_chroma444( x264_t *h, x264_frame_t int i_lines = fenc->i_lines[p]; int i_width = fenc->i_width[p]; pixel *src = fenc->plane[p]; - ALIGNED_ARRAY_16( pixel, buf, [16*16] ); + ALIGNED_ARRAY_64( pixel, buf, [16*16] ); int pixoff = 0; if( w ) { @@ -544,17 +544,18 @@ static void x264_slicetype_mb_cost( x264_t *h, x264_mb_analysis_t *a, if( p0 == p1 ) goto lowres_intra_mb; + int mv_range = 2 * h->param.analyse.i_mv_range; // no need for h->mb.mv_min[] - h->mb.mv_limit_fpel[0][0] = -8*h->mb.i_mb_x - 4; - h->mb.mv_limit_fpel[1][0] = 8*( h->mb.i_mb_width - h->mb.i_mb_x - 1 ) + 4; - h->mb.mv_min_spel[0] = 4*( h->mb.mv_limit_fpel[0][0] - 8 ); - h->mb.mv_max_spel[0] = 4*( h->mb.mv_limit_fpel[1][0] + 8 ); + h->mb.mv_min_spel[0] = X264_MAX( 4*(-8*h->mb.i_mb_x - 12), -mv_range ); + h->mb.mv_max_spel[0] = X264_MIN( 4*(8*(h->mb.i_mb_width - h->mb.i_mb_x - 1) + 12), mv_range-1 ); + h->mb.mv_limit_fpel[0][0] = h->mb.mv_min_spel[0] >> 2; + h->mb.mv_limit_fpel[1][0] = h->mb.mv_max_spel[0] >> 2; if( h->mb.i_mb_x >= h->mb.i_mb_width - 2 ) { - h->mb.mv_limit_fpel[0][1] = -8*h->mb.i_mb_y - 4; - h->mb.mv_limit_fpel[1][1] = 8*( h->mb.i_mb_height - h->mb.i_mb_y - 1 ) + 4; - h->mb.mv_min_spel[1] = 4*( h->mb.mv_limit_fpel[0][1] - 8 ); - h->mb.mv_max_spel[1] = 4*( h->mb.mv_limit_fpel[1][1] + 8 ); + h->mb.mv_min_spel[1] = X264_MAX( 4*(-8*h->mb.i_mb_y - 12), -mv_range ); + h->mb.mv_max_spel[1] = X264_MIN( 4*(8*( h->mb.i_mb_height - h->mb.i_mb_y - 1) + 12), mv_range-1 ); + h->mb.mv_limit_fpel[0][1] = h->mb.mv_min_spel[1] >> 2; + h->mb.mv_limit_fpel[1][1] = h->mb.mv_max_spel[1] >> 2; } #define LOAD_HPELS_LUMA(dst, src) \ @@ -728,13 +729,13 @@ lowres_intra_mb: if( h->param.analyse.i_subpel_refine > 1 ) { h->predict_8x8c[I_PRED_CHROMA_P]( pix ); - int satd = h->pixf.mbcmp[PIXEL_8x8]( pix, FDEC_STRIDE, h->mb.pic.p_fenc[0], FENC_STRIDE ); + int satd = h->pixf.mbcmp[PIXEL_8x8]( h->mb.pic.p_fenc[0], FENC_STRIDE, pix, FDEC_STRIDE ); i_icost = X264_MIN( i_icost, satd ); h->predict_8x8_filter( pix, edge, ALL_NEIGHBORS, ALL_NEIGHBORS ); for( int i = 3; i < 9; i++ ) { h->predict_8x8[i]( pix, edge ); - satd = h->pixf.mbcmp[PIXEL_8x8]( pix, FDEC_STRIDE, h->mb.pic.p_fenc[0], FENC_STRIDE ); + satd = h->pixf.mbcmp[PIXEL_8x8]( h->mb.pic.p_fenc[0], FENC_STRIDE, pix, FDEC_STRIDE ); i_icost = X264_MIN( i_icost, satd ); } } diff --git a/library/src/main/cpp/libx264/filters/video/resize.c b/library/src/main/cpp/libx264/filters/video/resize.c index 0bacb5b..0d6bd8c 100644 --- a/library/src/main/cpp/libx264/filters/video/resize.c +++ b/library/src/main/cpp/libx264/filters/video/resize.c @@ -154,10 +154,12 @@ static int convert_csp_to_pix_fmt( int csp ) case X264_CSP_RGB: return csp&X264_CSP_HIGH_DEPTH ? AV_PIX_FMT_RGB48 : AV_PIX_FMT_RGB24; case X264_CSP_BGR: return csp&X264_CSP_HIGH_DEPTH ? AV_PIX_FMT_BGR48 : AV_PIX_FMT_BGR24; case X264_CSP_BGRA: return csp&X264_CSP_HIGH_DEPTH ? AV_PIX_FMT_BGRA64 : AV_PIX_FMT_BGRA; - /* the next csp has no equivalent 16bit depth in swscale */ + /* the following has no equivalent 16-bit depth in swscale */ case X264_CSP_NV12: return csp&X264_CSP_HIGH_DEPTH ? AV_PIX_FMT_NONE : AV_PIX_FMT_NV12; case X264_CSP_NV21: return csp&X264_CSP_HIGH_DEPTH ? AV_PIX_FMT_NONE : AV_PIX_FMT_NV21; - /* the next csp is no supported by swscale at all */ + case X264_CSP_YUYV: return csp&X264_CSP_HIGH_DEPTH ? AV_PIX_FMT_NONE : AV_PIX_FMT_YUYV422; + case X264_CSP_UYVY: return csp&X264_CSP_HIGH_DEPTH ? AV_PIX_FMT_NONE : AV_PIX_FMT_UYVY422; + /* the following is not supported by swscale at all */ case X264_CSP_NV16: default: return AV_PIX_FMT_NONE; } diff --git a/library/src/main/cpp/libx264/input/input.c b/library/src/main/cpp/libx264/input/input.c index db29a54..335f601 100644 --- a/library/src/main/cpp/libx264/input/input.c +++ b/library/src/main/cpp/libx264/input/input.c @@ -43,6 +43,8 @@ const x264_cli_csp_t x264_cli_csps[] = { [X264_CSP_NV12] = { "nv12", 2, { 1, 1 }, { 1, .5 }, 2, 2 }, [X264_CSP_NV21] = { "nv21", 2, { 1, 1 }, { 1, .5 }, 2, 2 }, [X264_CSP_NV16] = { "nv16", 2, { 1, 1 }, { 1, 1 }, 2, 1 }, + [X264_CSP_YUYV] = { "yuyv", 1, { 2 }, { 1 }, 2, 1 }, + [X264_CSP_UYVY] = { "uyvy", 1, { 2 }, { 1 }, 2, 1 }, [X264_CSP_BGR] = { "bgr", 1, { 3 }, { 1 }, 1, 1 }, [X264_CSP_BGRA] = { "bgra", 1, { 4 }, { 1 }, 1, 1 }, [X264_CSP_RGB] = { "rgb", 1, { 3 }, { 1 }, 1, 1 }, diff --git a/library/src/main/cpp/libx264/input/raw.c b/library/src/main/cpp/libx264/input/raw.c index f8c0406..1f2e73e 100644 --- a/library/src/main/cpp/libx264/input/raw.c +++ b/library/src/main/cpp/libx264/input/raw.c @@ -98,6 +98,7 @@ static int open_file( char *psz_filename, hnd_t *p_handle, video_info_t *info, c uint64_t size = ftell( h->fh ); fseek( h->fh, 0, SEEK_SET ); info->num_frames = size / h->frame_size; + FAIL_IF_ERROR( !info->num_frames, "empty input file\n" ); /* Attempt to use memory-mapped input frames if possible */ if( !(h->bit_depth & 7) ) diff --git a/library/src/main/cpp/libx264/input/y4m.c b/library/src/main/cpp/libx264/input/y4m.c index 8948f68..09dbb13 100644 --- a/library/src/main/cpp/libx264/input/y4m.c +++ b/library/src/main/cpp/libx264/input/y4m.c @@ -223,6 +223,7 @@ static int open_file( char *psz_filename, hnd_t *p_handle, video_info_t *info, c uint64_t i_size = ftell( h->fh ); fseek( h->fh, init_pos, SEEK_SET ); info->num_frames = (i_size - h->seq_header_len) / h->frame_size; + FAIL_IF_ERROR( !info->num_frames, "empty input file\n" ); /* Attempt to use memory-mapped input frames if possible */ if( !(h->bit_depth & 7) ) diff --git a/library/src/main/cpp/libx264/libs/armeabi-v7a/libx264.a b/library/src/main/cpp/libx264/libs/armeabi-v7a/libx264.a index 566f60d3987ae45e790789c098b8fd29e5cec4f5..4319a96f7b177fab2b3ee35a8bf8c2d6d3fa6a55 100644 GIT binary patch delta 303557 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

rmUZHlEt;tQ;TH6q9P#58ImMEmwO(YtA$Jg2 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

b@)GvSYyaL-8tK&%2h$F^ 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