Commit ab1ac4b066 for ffmpeg
commit ab1ac4b066fd9b3c6bbe25cdca730a1e889f86f5
Author: Marcos Ashton Iglesias <marcosashiglesias@gmail.com>
Date: Thu Sep 10 23:51:59 2026 +0100
avcodec/x86/vc1dsp_inv_trans: add AVX2 vc1_inv_trans_8x8
Same arithmetic as the SSE2 version with the two column halves in the
two 128-bit lanes, halving the instruction count. The measured gain is
smaller because checkasm calls it in place on one block, so the 32 byte
loads of a call wait for the 16 byte stores of the previous one. Eight
registers would do, but it stays x86-64 only like the SSE2 version as it
was not tested on x86-32.
checkasm --bench on a Core Ultra 7 155H:
vc1dsp.vc1_inv_trans_8x8_c: 120.8
vc1dsp.vc1_inv_trans_8x8_sse2: 90.8 ( 1.32x)
vc1dsp.vc1_inv_trans_8x8_avx2: 85.1 ( 1.41x)
diff --git a/libavcodec/x86/vc1dsp_init.c b/libavcodec/x86/vc1dsp_init.c
index 77dca06385..49747feb60 100644
--- a/libavcodec/x86/vc1dsp_init.c
+++ b/libavcodec/x86/vc1dsp_init.c
@@ -81,6 +81,7 @@ void ff_vc1_inv_trans_4x8_sse2(uint8_t *dest, ptrdiff_t linesize,
void ff_vc1_inv_trans_8x4_sse2(uint8_t *dest, ptrdiff_t linesize,
int16_t *block);
void ff_vc1_inv_trans_8x8_sse2(int16_t block[64]);
+void ff_vc1_inv_trans_8x8_avx2(int16_t block[64]);
#define MSPEL_FUNC(OP, X, Y, SIZE, XMM) \
void ff_vc1_ ## OP ## _mspel_mc ## X ## Y ## _ ## SIZE ##_ ## XMM \
@@ -150,4 +151,8 @@ av_cold void ff_vc1dsp_init_x86(VC1DSPContext *dsp)
dsp->vc1_h_loop_filter8 = ff_vc1_h_loop_filter8_sse4;
dsp->vc1_h_loop_filter16 = vc1_h_loop_filter16_sse4;
}
+#if ARCH_X86_64
+ if (EXTERNAL_AVX2_FAST(cpu_flags))
+ dsp->vc1_inv_trans_8x8 = ff_vc1_inv_trans_8x8_avx2;
+#endif
}
diff --git a/libavcodec/x86/vc1dsp_inv_trans.asm b/libavcodec/x86/vc1dsp_inv_trans.asm
index a5a4074a0c..f9ef835254 100644
--- a/libavcodec/x86/vc1dsp_inv_trans.asm
+++ b/libavcodec/x86/vc1dsp_inv_trans.asm
@@ -459,4 +459,58 @@ cglobal vc1_inv_trans_8x8, 1, 1, 12, block
punpckhqdq m2, m3
mova [blockq+ 64], m2
RET
-%endif
+
+%if HAVE_AVX2_EXTERNAL
+INIT_YMM avx2
+; void ff_vc1_inv_trans_8x8_avx2(int16_t block[64])
+; Same as above with columns 0-3 in the low and 4-7 in the high 128-bit lane.
+cglobal vc1_inv_trans_8x8, 1, 1, 8, block
+ movu m0, [blockq+ 0] ; rows 0, 1; checkasm only guarantees
+ movu m1, [blockq+32] ; rows 2, 3; 16-byte alignment
+ movu m2, [blockq+64] ; rows 4, 5
+ movu m3, [blockq+96] ; rows 6, 7
+ vpermq m0, m0, q3120 ; columns 0-3 of both rows | columns 4-7
+ vpermq m1, m1, q3120
+ vpermq m2, m2, q3120
+ vpermq m3, m3, q3120
+ punpcklwd m4, m0, m2 ; (row0,row4) pairs
+ punpckhwd m0, m2 ; (row1,row5)
+ punpcklwd m2, m1, m3 ; (row2,row6)
+ punpckhwd m1, m3 ; (row3,row7)
+ VC1_IDCT8_1D 4, 0, 2, 1, 3, 5, 6, 7, pd_4, 3, 0
+ ; 0|7: m6, 1|6: m7, 2|5: m2, 3|4: m0
+ vpermq m6, m6, q3120 ; row 0 | row 7
+ vpermq m7, m7, q3120 ; row 1 | row 6
+ vpermq m2, m2, q3120 ; row 2 | row 5
+ vpermq m0, m0, q3120 ; row 3 | row 4
+ vperm2i128 m1, m6, m0, q0300 ; row 0 | row 4
+ vperm2i128 m3, m0, m6, q0300 ; row 3 | row 7
+ vperm2i128 m4, m7, m2, q0300 ; row 1 | row 5
+ vperm2i128 m5, m2, m7, q0300 ; row 2 | row 6
+ ; transpose the 4x8 halves of each lane into columns, which are the
+ ; inputs of the second pass; the lanes then hold columns 0-3 | 4-7 again
+ SBUTTERFLY wd, 1, 4, 0
+ SBUTTERFLY wd, 5, 3, 0
+ SBUTTERFLY dq, 1, 5, 0 ; m1 = columns 0, 1; m5 = 2, 3
+ SBUTTERFLY dq, 4, 3, 0 ; m4 = columns 4, 5; m3 = 6, 7
+ punpcklwd m0, m1, m4 ; (0,4) pairs
+ punpckhwd m1, m4 ; (1,5)
+ punpcklwd m2, m5, m3 ; (2,6)
+ punpckhwd m5, m3 ; (3,7)
+ VC1_IDCT8_1D 0, 1, 2, 5, 3, 4, 6, 7, pd_64, 7, 1
+ ; 0|7: m6, 1|6: m7, 2|5: m2, 3|4: m1
+ vpermq m6, m6, q3120 ; row 0 | row 7
+ vpermq m7, m7, q3120 ; row 1 | row 6
+ vpermq m2, m2, q3120 ; row 2 | row 5
+ vpermq m1, m1, q3120 ; row 3 | row 4
+ mova [blockq+ 0], xm6
+ vextracti128 [blockq+112], m6, 1
+ mova [blockq+ 16], xm7
+ vextracti128 [blockq+ 96], m7, 1
+ mova [blockq+ 32], xm2
+ vextracti128 [blockq+ 80], m2, 1
+ mova [blockq+ 48], xm1
+ vextracti128 [blockq+ 64], m1, 1
+ RET
+%endif ; HAVE_AVX2_EXTERNAL
+%endif ; ARCH_X86_64