[PATCH v2 2/2] avcodec/x86/h264_intrapred: add AVX2 for 10-bit pred16x16 plane
ZaneHam via ffmpeg-devel <[email protected]> Tue, 28 Jul 2026 12:21:49 +1200
| Newsgroups | gmane.comp.video.ffmpeg.devel |
|---|---|
| Message-ID | <[email protected]> |
From: Zane Hambly <[email protected]> pred16x16_plane had no SIMD for 10-bit and is the most expensive intra 16x16 mode. This AVX2 version holds the 16 columns as 32-bit accumulators in two YMM registers, since 10-bit plane values exceed 16-bit range, and fills each row with a clamped linear ramp. checkasm benchmarks on Ryzen 5 7600X (cycles, lower is better): C AVX2 pred16x16_plane_10 456.6 50.4 (9.05x) Signed-off-by: Zane Hambly <[email protected]> --- libavcodec/x86/h264_intrapred_10bit.asm | 99 +++++++++++++++++++++++++ libavcodec/x86/h264_intrapred_init.c | 2 + 2 files changed, 101 insertions(+) diff --git a/libavcodec/x86/h264_intrapred_10bit.asm b/libavcodec/x86/h264_intrapred_10bit.asm index 78e2f263bc..c2395f824d 100644 --- a/libavcodec/x86/h264_intrapred_10bit.asm +++ b/libavcodec/x86/h264_intrapred_10bit.asm @@ -40,6 +40,13 @@ pw_m32101234: dw -3, -2, -1, 0, 1, 2, 3, 4 pw_m3: times 8 dw -3 pd_17: times 4 dd 17 +; plane prediction: H gradient coefficients for top[-1..6] and top[8..15], +; and the per-column ramp 0..15 (dwords, for the 32-bit accumulators) +plane_coef_lo: dw -8, -7, -6, -5, -4, -3, -2, -1 +plane_coef_hi: dw 1, 2, 3, 4, 5, 6, 7, 8 +plane_ramp: dd 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 +plane_max: times 16 dw 1023 + SECTION .text ; dest, left, right, src @@ -1302,4 +1309,96 @@ cglobal pred16x16_128_dc_10, 2, 4 jg .loop RET +;----------------------------------------------------------------------------- +; void ff_pred16x16_plane_10_avx2(pixel *src, ptrdiff_t stride) +; H.264 intra 16x16 plane prediction, 10-bit. +; H, V = weighted gradients of the top row / left column +; pred[x,y] = clip((a + y*V + x*H) >> 5, 0, 1023) +; Values exceed 16-bit range at 10-bit, so the 16 columns live in two YMM +; registers of 32-bit accumulators. +;----------------------------------------------------------------------------- +INIT_YMM avx2 +cglobal pred16x16_plane_10, 2, 9, 5 + ; ---- H: gradient over the top row (row -1) ---- + mov r2, r0 + sub r2, r1 ; r2 = &top[0] + movu xm0, [r2-2] ; top[-1..6] (8 words) + movu xm1, [r2+16] ; top[8..15] (8 words) + pmaddwd xm0, [plane_coef_lo] + pmaddwd xm1, [plane_coef_hi] + paddd xm0, xm1 ; 4 dword partial sums + pshufd xm1, xm0, 0x0e + paddd xm0, xm1 + pshufd xm1, xm0, 0x01 + paddd xm0, xm1 ; H (raw) in the low dword + movd r3d, xm0 + lea r3d, [r3d*5+32] + sar r3d, 6 ; r3d = H = (5*H+32)>>6 + movzx r8d, word [r2+30] ; top[15], kept for a + + ; ---- V: gradient over the left column (scalar; it is strided) ---- + lea r4, [r0+r1*8] + sub r4, 2 ; &left[8] + lea r5, [r0+r1*4] + lea r5, [r5+r1*2] + sub r5, 2 ; &left[6] + movzx r6d, word [r4] + movzx r7d, word [r5] + sub r6d, r7d + mov r2d, r6d ; V acc, k=1 term +%assign k 2 +%rep 7 + add r4, r1 + sub r5, r1 + movzx r6d, word [r4] + movzx r7d, word [r5] + sub r6d, r7d + imul r6d, r6d, k + add r2d, r6d +%assign k k+1 +%endrep + lea r2d, [r2d*5+32] + sar r2d, 6 ; r2d = V = (5*V+32)>>6 + + ; ---- a = 16*(left[15] + top[15] + 1) - 7*(H+V) ---- + movzx r6d, word [r4] ; r4 == &left[15] after the loop + lea r6d, [r6+r8+1] + shl r6d, 4 ; 16*(left15 + top15 + 1) + mov r7d, r2d + add r7d, r3d ; H+V + mov r8d, r7d + shl r8d, 3 + sub r8d, r7d ; 7*(H+V) + sub r6d, r8d ; r6d = a + + ; ---- build the column ramps: acc = a + col*H (dwords) ---- + movd xm3, r3d + vpbroadcastd m3, xm3 ; H + movd xm2, r6d + vpbroadcastd m2, xm2 ; a + movd xm4, r2d + vpbroadcastd m4, xm4 ; V + pmulld m0, m3, [plane_ramp] + pmulld m1, m3, [plane_ramp+32] + paddd m0, m2 ; a + {0..7}*H + paddd m1, m2 ; a + {8..15}*H + + ; ---- fill 16 rows ---- + ; a and H are spent, so m2/m3 are free scratch and the clamp comes from + ; memory: the loop stays within m0..m4, no ymm6/7, no Win64 save/restore. + mov r2d, 16 +.loop: + vpsrad m2, m0, 5 + vpsrad m3, m1, 5 + vpackusdw m2, m2, m3 ; dword->word, clamps low to 0; lanes scrambled + vpermq m2, m2, 0xd8 ; unscramble to columns 0..15 + vpminuw m2, m2, [plane_max] ; clamp high to 1023 + movu [r0], m2 + paddd m0, m4 ; next row: += V + paddd m1, m4 + add r0, r1 + 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 852c9ed7d6..d8dbcc1374 100644 --- a/libavcodec/x86/h264_intrapred_init.c +++ b/libavcodec/x86/h264_intrapred_init.c @@ -103,6 +103,7 @@ PRED16x16(128_dc, 10, avx2) PRED16x16(left_dc, 10, avx2) PRED16x16(vertical, 10, avx2) PRED16x16(horizontal, 10, avx2) +PRED16x16(plane, 10, avx2) /* 8-bit versions */ PRED16x16(vertical, 8, sse) @@ -321,6 +322,7 @@ av_cold void ff_h264_pred_init_x86(H264PredContext *h, int codec_id, 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; + h->pred16x16[PLANE_PRED8x8 ] = ff_pred16x16_plane_10_avx2; } } } -- 2.51.0.windows.2 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]