[PATCH v2 1/2] avcodec/x86/h264_intrapred: add AVX2 for 10-bit pred16x16 functions
ZaneHam via ffmpeg-devel <[email protected]> Tue, 28 Jul 2026 12:21:48 +1200
| Newsgroups | gmane.comp.video.ffmpeg.devel |
|---|---|
| Message-ID | <[email protected]> |
From: Zane Hambly <[email protected]> Add AVX2 implementations for 10-bit H.264 16x16 intra prediction: - pred16x16_vertical_10 - pred16x16_horizontal_10 - pred16x16_dc_10 - pred16x16_top_dc_10 - pred16x16_left_dc_10 - pred16x16_128_dc_10 10-bit 16x16 blocks are 32 bytes per row, perfectly matching AVX2's 256-bit YMM registers, allowing single-instruction row operations versus two XMM operations with SSE2. checkasm benchmarks on Zen3 (cycles, lower is better): C SSE2 AVX2 pred16x16_dc_10 65.7 40.3 27.3 (1.48x vs SSE2) pred16x16_128_dc_10 31.1 28.1 21.4 (1.31x vs SSE2) pred16x16_horizontal 67.8 28.1 21.6 (1.30x vs SSE2) pred16x16_left_dc_10 55.6 35.0 22.9 (1.53x vs SSE2) pred16x16_top_dc_10 49.5 32.3 21.8 (1.48x vs SSE2) pred16x16_vertical_10 32.3 28.3 24.1 (1.17x vs SSE2) Signed-off-by: Zane Hambly <[email protected]> --- libavcodec/x86/h264_intrapred_10bit.asm | 186 ++++++++++++++++++++++++ libavcodec/x86/h264_intrapred_init.c | 14 ++ 2 files changed, 200 insertions(+) diff --git a/libavcodec/x86/h264_intrapred_10bit.asm b/libavcodec/x86/h264_intrapred_10bit.asm index 2f30807332..78e2f263bc 100644 --- a/libavcodec/x86/h264_intrapred_10bit.asm +++ b/libavcodec/x86/h264_intrapred_10bit.asm @@ -1117,3 +1117,189 @@ cglobal pred16x16_128_dc_10, 2,3 dec r2d jg .loop RET + +;----------------------------------------------------------------------------- +; AVX2 versions of pred16x16 10-bit functions +; For 10-bit: 16 pixels * 2 bytes = 32 bytes = 1 YMM register (perfect match\!) +;----------------------------------------------------------------------------- + +%if HAVE_AVX2_EXTERNAL + +;----------------------------------------------------------------------------- +; void ff_pred16x16_vertical_10_avx2(pixel *src, ptrdiff_t stride) +;----------------------------------------------------------------------------- +INIT_YMM avx2 +cglobal pred16x16_vertical_10, 2, 4 + sub r0, r1 + movu m0, [r0] ; Load all 16 pixels (32 bytes) from top row + mov r2d, 4 + lea r3, [r1*3] +.loop: + movu [r0+r1*1], m0 + movu [r0+r1*2], m0 + movu [r0+r3 ], m0 + lea r0, [r0+r1*2] + movu [r0+r1*2], m0 + lea r0, [r0+r1*2] + dec r2d + jg .loop + RET + +;----------------------------------------------------------------------------- +; void ff_pred16x16_horizontal_10_avx2(pixel *src, ptrdiff_t stride) +;----------------------------------------------------------------------------- +INIT_YMM avx2 +cglobal pred16x16_horizontal_10, 2, 4 + lea r2, [r1*3] + mov r3d, 4 +.loop: + vpbroadcastw m0, [r0-2] + movu [r0], m0 + vpbroadcastw m0, [r0+r1-2] + movu [r0+r1], m0 + vpbroadcastw m0, [r0+r1*2-2] + movu [r0+r1*2], m0 + vpbroadcastw m0, [r0+r2-2] + movu [r0+r2], m0 + lea r0, [r0+r1*4] + dec r3d + jg .loop + RET + +;----------------------------------------------------------------------------- +; void ff_pred16x16_dc_10_avx2(pixel *src, ptrdiff_t stride) +; DC = (sum of 16 top pixels + sum of 16 left pixels + 16) >> 5 +;----------------------------------------------------------------------------- +INIT_YMM avx2 +cglobal pred16x16_dc_10, 2, 6 + mov r5, r0 ; Save dest pointer + sub r0, r1 + movu m0, [r0] ; Load top row (32 bytes) + vextracti128 xm1, m0, 1 ; Get high 128 bits + paddw xm0, xm1 ; Sum to 8 words + phaddw xm0, xm0 ; 4 words + phaddw xm0, xm0 ; 2 words + phaddw xm0, xm0 ; 1 word (top sum in low word) + movd r3d, xm0 + and r3d, 0xFFFF ; Keep only low 16 bits + + ; Sum left column using lea-based pointer advancement + lea r0, [r0+r1-2] ; Point to left pixel of row 0 + movzx r4d, word [r0] + add r3d, r4d + movzx r4d, word [r0+r1] + add r3d, r4d +%rep 7 + lea r0, [r0+r1*2] + movzx r4d, word [r0] + add r3d, r4d + movzx r4d, word [r0+r1] + add r3d, r4d +%endrep + add r3d, 16 ; Rounding + shr r3d, 5 ; Divide by 32 + + movd xm0, r3d + vpbroadcastw m0, xm0 ; Broadcast to all 16 words + + ; Fill all 16 rows + mov r3d, 4 + lea r4, [r1*3] +.loop: + movu [r5+r1*0], m0 + movu [r5+r1*1], m0 + movu [r5+r1*2], m0 + movu [r5+r4 ], m0 + lea r5, [r5+r1*4] + dec r3d + jg .loop + RET + +;----------------------------------------------------------------------------- +; void ff_pred16x16_top_dc_10_avx2(pixel *src, ptrdiff_t stride) +; DC = (sum of 16 top pixels + 8) >> 4 +;----------------------------------------------------------------------------- +INIT_YMM avx2 +cglobal pred16x16_top_dc_10, 2, 4 + sub r0, r1 + movu m0, [r0] ; Load top row + vextracti128 xm1, m0, 1 + paddw xm0, xm1 + phaddw xm0, xm0 + phaddw xm0, xm0 + phaddw xm0, xm0 + paddw xm0, [pw_8] ; Add 8 for rounding + psrlw xm0, 4 ; Divide by 16 + vpbroadcastw m0, xm0 + + mov r2d, 4 + lea r3, [r1*3] +.loop: + movu [r0+r1*1], m0 + movu [r0+r1*2], m0 + movu [r0+r3 ], m0 + lea r0, [r0+r1*2] + movu [r0+r1*2], m0 + lea r0, [r0+r1*2] + dec r2d + jg .loop + RET + +;----------------------------------------------------------------------------- +; void ff_pred16x16_left_dc_10_avx2(pixel *src, ptrdiff_t stride) +; DC = (sum of 16 left pixels + 8) >> 4 +;----------------------------------------------------------------------------- +INIT_YMM avx2 +cglobal pred16x16_left_dc_10, 2, 5 + mov r4, r0 ; Save dest pointer + + ; Sum left column using lea-based pointer advancement + sub r0, 2 ; Point to left pixel of row 0 + movzx r2d, word [r0] + movzx r3d, word [r0+r1] +%rep 7 + lea r0, [r0+r1*2] + movzx eax, word [r0] + add r2d, eax + movzx eax, word [r0+r1] + add r3d, eax +%endrep + lea r2d, [r2+r3+8] ; Sum with rounding + shr r2d, 4 ; Divide by 16 + + movd xm0, r2d + vpbroadcastw m0, xm0 + + ; Fill all 16 rows + mov r2d, 4 + lea r3, [r1*3] +.loop: + movu [r4+r1*0], m0 + movu [r4+r1*1], m0 + movu [r4+r1*2], m0 + movu [r4+r3 ], m0 + lea r4, [r4+r1*4] + dec r2d + jg .loop + RET + +;----------------------------------------------------------------------------- +; void ff_pred16x16_128_dc_10_avx2(pixel *src, ptrdiff_t stride) +; Fill with constant 512 (1 << 9 for 10-bit midpoint) +;----------------------------------------------------------------------------- +INIT_YMM avx2 +cglobal pred16x16_128_dc_10, 2, 4 + vpbroadcastw m0, [pw_512] + mov r2d, 4 + lea r3, [r1*3] +.loop: + movu [r0+r1*0], m0 + movu [r0+r1*1], m0 + movu [r0+r1*2], m0 + movu [r0+r3 ], m0 + lea r0, [r0+r1*4] + dec r2d + jg .loop + RET + +%endif ; HAVE_AVX2_EXTERNAL diff --git a/libavcodec/x86/h264_intrapred_init.c b/libavcodec/x86/h264_intrapred_init.c index 0248f86491..852c9ed7d6 100644 --- a/libavcodec/x86/h264_intrapred_init.c +++ b/libavcodec/x86/h264_intrapred_init.c @@ -97,6 +97,12 @@ PRED16x16(128_dc, 10, sse2) PRED16x16(left_dc, 10, sse2) PRED16x16(vertical, 10, sse2) PRED16x16(horizontal, 10, sse2) +PRED16x16(dc, 10, avx2) +PRED16x16(top_dc, 10, avx2) +PRED16x16(128_dc, 10, avx2) +PRED16x16(left_dc, 10, avx2) +PRED16x16(vertical, 10, avx2) +PRED16x16(horizontal, 10, avx2) /* 8-bit versions */ PRED16x16(vertical, 8, sse) @@ -308,5 +314,13 @@ av_cold void ff_h264_pred_init_x86(H264PredContext *h, int codec_id, h->pred8x8l[VERT_RIGHT_PRED ] = ff_pred8x8l_vertical_right_10_avx; h->pred8x8l[HOR_UP_PRED ] = ff_pred8x8l_horizontal_up_10_avx; } + if (EXTERNAL_AVX2(cpu_flags)) { + h->pred16x16[DC_PRED8x8 ] = ff_pred16x16_dc_10_avx2; + h->pred16x16[TOP_DC_PRED8x8 ] = ff_pred16x16_top_dc_10_avx2; + h->pred16x16[DC_128_PRED8x8 ] = ff_pred16x16_128_dc_10_avx2; + h->pred16x16[LEFT_DC_PRED8x8 ] = ff_pred16x16_left_dc_10_avx2; + h->pred16x16[VERT_PRED8x8 ] = ff_pred16x16_vertical_10_avx2; + h->pred16x16[HOR_PRED8x8 ] = ff_pred16x16_horizontal_10_avx2; + } } } -- 2.51.0.windows.2 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]