PR #24468 opened by Marcos Ashton (MarcosAsh) URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24468 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24468.patch
Adds SSE2 implementations of the four VC-1 inverse transforms (4x4, 4x8, 8x4 and 8x8) and an AVX2 8x8, in two commits so the AVX2 one can be dropped on its own. x86 previously only had the DC variants; aarch64, arm, riscv, loongarch and mips already carry all four full transforms and ppc has 8x8 and 8x4. The transforms are computed exactly rather than with the 16-bit halving trick of the aarch64/arm ports. Each 1-D pass multiplies pmaddwd pairs into dwords, the same approach as x86 simple_idct, so the output is bit-identical to the C code over the whole coefficient range the spec allows. The checkasm test attenuates its inputs to accommodate the inexact ports; this one does not need that. I checked 400000 random blocks per shape with coefficients in [-2048, 2047] against the C code with no mismatches, and fate-vc1 and fate-wmv3-drm produce identical framecrc output with -cpuflags 0, sse2 and avx2. Each finished output pair is packed back to words immediately, which keeps 4x4, 4x8 and 8x4 within eight xmm registers so they build on x86-32 as well. The 8x8 keeps the whole block in registers, needs twelve, and is x86-64 only. The AVX2 8x8 puts the two column halves in the two 128-bit lanes, which halves the instruction count. The 8x8 speedup is the smallest for two reasons. GCC fully autovectorizes the C 8x8, so the baseline is already SIMD; against clang's scalar C the SSE2 and AVX2 8x8 are 1.77x and 2.11x. checkasm also benchmarks consecutive in-place calls on the same block, which serialize through memory, so it measures the dependency chain of one call rather than throughput. checkasm -t vc1dsp passes bit-exact, including 300 runs with different seeds. Benchmarks (Core Ultra 7 155H, GCC build): ``` vc1dsp.vc1_inv_trans_4x4_c: 111.1 vc1dsp.vc1_inv_trans_4x4_sse2: 17.0 ( 6.53x) vc1dsp.vc1_inv_trans_4x8_c: 142.5 vc1dsp.vc1_inv_trans_4x8_sse2: 44.9 ( 3.17x) vc1dsp.vc1_inv_trans_8x4_c: 192.8 vc1dsp.vc1_inv_trans_8x4_sse2: 38.0 ( 5.07x) 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) ``` >From c2d0bffb5104fbee963d121ecb25cdbd868a07b5 Mon Sep 17 00:00:00 2001 From: Marcos Ashton Iglesias <[email protected]> Date: Thu, 10 Sep 2026 23:51:59 +0100 Subject: [PATCH 1/2] avcodec/x86/vc1dsp_inv_trans: add SSE2 inverse transforms Add SSE2 vc1_inv_trans_4x4, 4x8, 8x4 and 8x8. x86 only had the DC variants; every other SIMD arch already has the full transforms. The 1-D passes use pmaddwd pairs into dwords, so the output is bit-identical to the C code for the whole coefficient range the spec allows, unlike the 16-bit aarch64/arm versions the checkasm test has to attenuate its inputs for. 4x4, 4x8 and 8x4 fit in eight registers; 8x8 keeps the whole block in registers and is x86-64 only. checkasm --bench on a Core Ultra 7 155H: vc1dsp.vc1_inv_trans_4x4_c: 111.1 vc1dsp.vc1_inv_trans_4x4_sse2: 17.0 ( 6.53x) vc1dsp.vc1_inv_trans_4x8_c: 142.5 vc1dsp.vc1_inv_trans_4x8_sse2: 44.9 ( 3.17x) vc1dsp.vc1_inv_trans_8x4_c: 192.8 vc1dsp.vc1_inv_trans_8x4_sse2: 38.0 ( 5.07x) vc1dsp.vc1_inv_trans_8x8_c: 120.8 vc1dsp.vc1_inv_trans_8x8_sse2: 90.8 ( 1.32x) --- libavcodec/x86/vc1dsp_init.c | 13 ++ libavcodec/x86/vc1dsp_inv_trans.asm | 333 ++++++++++++++++++++++++++++ 2 files changed, 346 insertions(+) diff --git a/libavcodec/x86/vc1dsp_init.c b/libavcodec/x86/vc1dsp_init.c index 6c86b646f9..77dca06385 100644 --- a/libavcodec/x86/vc1dsp_init.c +++ b/libavcodec/x86/vc1dsp_init.c @@ -74,6 +74,13 @@ void ff_vc1_inv_trans_8x4_dc_sse2(uint8_t *dest, ptrdiff_t linesize, int16_t *block); void ff_vc1_inv_trans_8x8_dc_sse2(uint8_t *dest, ptrdiff_t linesize, int16_t *block); +void ff_vc1_inv_trans_4x4_sse2(uint8_t *dest, ptrdiff_t linesize, + int16_t *block); +void ff_vc1_inv_trans_4x8_sse2(uint8_t *dest, ptrdiff_t linesize, + int16_t *block); +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]); #define MSPEL_FUNC(OP, X, Y, SIZE, XMM) \ void ff_vc1_ ## OP ## _mspel_mc ## X ## Y ## _ ## SIZE ##_ ## XMM \ @@ -115,6 +122,12 @@ av_cold void ff_vc1dsp_init_x86(VC1DSPContext *dsp) dsp->vc1_inv_trans_4x8_dc = ff_vc1_inv_trans_4x8_dc_sse2; dsp->vc1_inv_trans_8x4_dc = ff_vc1_inv_trans_8x4_dc_sse2; dsp->vc1_inv_trans_4x4_dc = ff_vc1_inv_trans_4x4_dc_sse2; + dsp->vc1_inv_trans_4x4 = ff_vc1_inv_trans_4x4_sse2; + dsp->vc1_inv_trans_4x8 = ff_vc1_inv_trans_4x8_sse2; + dsp->vc1_inv_trans_8x4 = ff_vc1_inv_trans_8x4_sse2; +#if ARCH_X86_64 + dsp->vc1_inv_trans_8x8 = ff_vc1_inv_trans_8x8_sse2; +#endif ASSIGN_LF816(sse2); diff --git a/libavcodec/x86/vc1dsp_inv_trans.asm b/libavcodec/x86/vc1dsp_inv_trans.asm index 788ffa24a8..5f78e9db0f 100644 --- a/libavcodec/x86/vc1dsp_inv_trans.asm +++ b/libavcodec/x86/vc1dsp_inv_trans.asm @@ -1,6 +1,7 @@ ;****************************************************************************** ;* VC1 inverse transform ;* Copyright (c) 2009 Fiona Glaser +;* Copyright (c) 2026 Marcos Ashton Iglesias ;* ;* This file is part of FFmpeg. ;* @@ -21,6 +22,31 @@ %include "libavutil/x86/x86util.asm" +SECTION_RODATA 32 + +; pmaddwd coefficient pairs of the 1-D transforms. The 8-point transform +; pairs inputs (0,4), (1,5), (2,6), (3,7); the 4-point one (0,2), (1,3). +pw_12: times 8 dw 12, 12 +pw_12_m12: times 8 dw 12, -12 +pw_16_6: times 8 dw 16, 6 +pw_6_m16: times 8 dw 6, -16 +pw_16_9: times 8 dw 16, 9 +pw_15_4: times 8 dw 15, 4 +pw_15_m16: times 8 dw 15, -16 +pw_m4_m9: times 8 dw -4, -9 +pw_9_4: times 8 dw 9, 4 +pw_m16_15: times 8 dw -16, 15 +pw_4_15: times 8 dw 4, 15 +pw_m9_m16: times 8 dw -9, -16 +pw_17: times 8 dw 17, 17 +pw_17_m17: times 8 dw 17, -17 +pw_22_10: times 8 dw 22, 10 +pw_m10_22: times 8 dw -10, 22 +pd_4: times 8 dd 4 + +cextern pd_1 +cextern pd_64 + SECTION .text %macro INV_TRANS_INIT 1 ; width @@ -120,3 +146,310 @@ cglobal vc1_inv_trans_8x8_dc, 3,3,6, dest, linesize, block lea destq, [destq+linesizeq*4] INV_TRANS_PROCESS q RET + +;----------------------------------------------------------------------------- +; 1-D 8-point inverse transform on the dword lanes of one register, exact +; 32-bit arithmetic. +; Inputs are pmaddwd pairs (x0,x4), (x1,x5), (x2,x6), (x3,x7), one lane per +; transformed vector; all inputs and temporaries are clobbered. +; Each finished output pair is packed to words as soon as it is complete so +; that the whole pass fits in 8 registers. +; %1-%4 = pairs, %5-%8 = temporaries, %9 = rounding constant, %10 = shift, +; %11 = 1 to add the extra 1 to outputs 4-7 (second pass of the C code) +; out: %7 = out0|out7, %8 = out1|out6, %3 = out2|out5, %2 = out3|out4 +; (low qword | high qword, as words) +;----------------------------------------------------------------------------- +%macro VC1_IDCT8_1D 11 + pmaddwd m%5, m%1, [pw_12] ; t1 = 12 * (x0 + x4) + pmaddwd m%1, [pw_12_m12] ; t2 = 12 * (x0 - x4) + pmaddwd m%6, m%3, [pw_16_6] ; t3 = 16 * x2 + 6 * x6 + pmaddwd m%3, [pw_6_m16] ; t4 = 6 * x2 - 16 * x6 + paddd m%5, [%9] + paddd m%1, [%9] + SUMSUB_BA d, %6, %5 ; t5 = t1 + t3, t8 = t1 - t3 + SUMSUB_BA d, %3, %1 ; t6 = t2 + t4, t7 = t2 - t4 + + pmaddwd m%7, m%2, [pw_16_9] + pmaddwd m%8, m%4, [pw_15_4] + paddd m%7, m%8 ; 16 * x1 + 15 * x3 + 9 * x5 + 4 * x7 + SUMSUB_BA d, %7, %6 ; out0 = t5 + odd, out7 = t5 - odd +%if %11 + paddd m%6, [pd_1] +%endif + psrad m%7, %10 + psrad m%6, %10 + packssdw m%7, m%6 + + pmaddwd m%8, m%2, [pw_15_m16] + pmaddwd m%6, m%4, [pw_m4_m9] + paddd m%8, m%6 ; 15 * x1 - 4 * x3 - 16 * x5 - 9 * x7 + SUMSUB_BA d, %8, %3 ; out1 = t6 + odd, out6 = t6 - odd +%if %11 + paddd m%3, [pd_1] +%endif + psrad m%8, %10 + psrad m%3, %10 + packssdw m%8, m%3 + + pmaddwd m%3, m%2, [pw_9_4] + pmaddwd m%6, m%4, [pw_m16_15] + paddd m%3, m%6 ; 9 * x1 - 16 * x3 + 4 * x5 + 15 * x7 + SUMSUB_BA d, %3, %1 ; out2 = t7 + odd, out5 = t7 - odd +%if %11 + paddd m%1, [pd_1] +%endif + psrad m%3, %10 + psrad m%1, %10 + packssdw m%3, m%1 + + pmaddwd m%2, [pw_4_15] + pmaddwd m%4, [pw_m9_m16] + paddd m%2, m%4 ; 4 * x1 - 9 * x3 + 15 * x5 - 16 * x7 + SUMSUB_BA d, %2, %5 ; out3 = t8 + odd, out4 = t8 - odd +%if %11 + paddd m%5, [pd_1] +%endif + psrad m%2, %10 + psrad m%5, %10 + packssdw m%2, m%5 +%endmacro + +;----------------------------------------------------------------------------- +; 1-D 4-point inverse transform on the dword lanes of one register. +; %1 = (x0,x2) pairs, %2 = (x1,x3) pairs, %3-%4 = temporaries, +; %5 = rounding constant, %6 = shift +; out (dwords): %4 = out0, %1 = out1, %2 = out2, %3 = out3 +;----------------------------------------------------------------------------- +%macro VC1_IDCT4_1D 6 + pmaddwd m%3, m%1, [pw_17] ; t1 = 17 * (x0 + x2) + pmaddwd m%1, [pw_17_m17] ; t2 = 17 * (x0 - x2) + pmaddwd m%4, m%2, [pw_22_10] ; t3 = 22 * x1 + 10 * x3 + pmaddwd m%2, [pw_m10_22] ; t4 = 22 * x3 - 10 * x1 + paddd m%3, [%5] + paddd m%1, [%5] + SUMSUB_BA d, %4, %3 ; out0 = t1 + t3, out3 = t1 - t3 + SUMSUB_BA d, %2, %1 ; out2 = t2 + t4, out1 = t2 - t4 + psrad m%4, %6 + psrad m%1, %6 + psrad m%2, %6 + psrad m%3, %6 +%endmacro + +; Add the two 4-pixel rows held as words in m%1 (low qword to [%4], high +; qword to [%5]) to dest with saturation. %2, %3 = temporaries, %6 = zero +%macro ADD_ROWS_4 6 + movd m%2, [%4] + movd m%3, [%5] + punpckldq m%2, m%3 + punpcklbw m%2, m%6 + paddw m%2, m%1 + packuswb m%2, m%2 + movd [%4], m%2 + psrlq m%2, 32 + movd [%5], m%2 +%endmacro + +; Add the 8-pixel row held as words in m%1 to [%3]. %2 = temporary, %4 = zero +%macro ADD_ROW_8 4 + movq m%2, [%3] + punpcklbw m%2, m%4 + paddw m%2, m%1 + packuswb m%2, m%2 + movq [%3], m%2 +%endmacro + +INIT_XMM sse2 +; void ff_vc1_inv_trans_4x4_sse2(uint8_t *dest, ptrdiff_t linesize, int16_t *block) +cglobal vc1_inv_trans_4x4, 3, 4, 5, dest, linesize, block, linesize3 + movq m0, [blockq+ 0] + movhps m0, [blockq+16] ; rows 0, 1 + movq m2, [blockq+32] + movhps m2, [blockq+48] ; rows 2, 3 + pshuflw m0, m0, q3120 ; x0 x2 x1 x3 per row + pshufhw m0, m0, q3120 + pshuflw m2, m2, q3120 + pshufhw m2, m2, q3120 + mova m1, m0 + shufps m0, m2, q2020 ; (x0,x2) pairs, one row per lane + shufps m1, m2, q3131 ; (x1,x3) pairs + VC1_IDCT4_1D 0, 1, 2, 3, pd_4, 3 ; column 0: m3, 1: m0, 2: m1, 3: m2 + packssdw m3, m0 ; columns 0 and 1, one row per word + packssdw m1, m2 ; columns 2 and 3 + pshuflw m3, m3, q3120 ; row0 row2 row1 row3 per column + pshufhw m3, m3, q3120 + pshuflw m1, m1, q3120 + pshufhw m1, m1, q3120 + mova m0, m3 + shufps m3, m1, q2020 ; (row0,row2) pairs, one column per lane + shufps m0, m1, q3131 ; (row1,row3) pairs + VC1_IDCT4_1D 3, 0, 1, 2, pd_64, 7 ; row 0: m2, 1: m3, 2: m0, 3: m1 + packssdw m2, m3 ; rows 0, 1 + packssdw m0, m1 ; rows 2, 3 + pxor m4, m4 + lea linesize3q, [linesizeq*3] + ADD_ROWS_4 2, 1, 3, destq, destq+linesizeq, 4 + ADD_ROWS_4 0, 1, 3, destq+linesizeq*2, destq+linesize3q, 4 + RET + +; void ff_vc1_inv_trans_8x4_sse2(uint8_t *dest, ptrdiff_t linesize, int16_t *block) +cglobal vc1_inv_trans_8x4, 3, 4, 8, dest, linesize, block, linesize3 + mova m0, [blockq+ 0] + mova m1, [blockq+16] + mova m2, [blockq+32] + mova m3, [blockq+48] + pshufd m4, m0, q1032 ; (x0,x4) (x1,x5) (x2,x6) (x3,x7) per row + punpcklwd m0, m4 + pshufd m4, m1, q1032 + punpcklwd m1, m4 + pshufd m4, m2, q1032 + punpcklwd m2, m4 + pshufd m4, m3, q1032 + punpcklwd m3, m4 + TRANSPOSE4x4D 0, 1, 2, 3, 4 ; one row per lane + VC1_IDCT8_1D 0, 1, 2, 3, 4, 5, 6, 7, pd_4, 3, 0 + ; columns 0|7: m6, 1|6: m7, 2|5: m2, 3|4: m1, one row per word + pshuflw m6, m6, q3120 ; row0 row2 row1 row3 per column + pshufhw m6, m6, q3120 + pshuflw m7, m7, q3120 + pshufhw m7, m7, q3120 + pshuflw m2, m2, q3120 + pshufhw m2, m2, q3120 + pshuflw m1, m1, q3120 + pshufhw m1, m1, q3120 + punpckldq m0, m6, m7 ; (row0,row2) (row1,row3) pairs, columns 0 1 + punpckhdq m7, m6 ; columns 6 7 + punpckldq m3, m2, m1 ; columns 2 3 + punpckhdq m1, m2 ; columns 4 5 + punpcklqdq m2, m0, m3 ; (row0,row2) pairs, columns 0-3 + punpckhqdq m0, m3 ; (row1,row3) pairs, columns 0-3 + punpcklqdq m3, m1, m7 ; (row0,row2) pairs, columns 4-7 + punpckhqdq m1, m7 ; (row1,row3) pairs, columns 4-7 + VC1_IDCT4_1D 2, 0, 4, 5, pd_64, 7 ; row 0: m5, 1: m2, 2: m0, 3: m4 + VC1_IDCT4_1D 3, 1, 6, 7, pd_64, 7 ; row 0: m7, 1: m3, 2: m1, 3: m6 + packssdw m5, m7 + packssdw m2, m3 + packssdw m0, m1 + packssdw m4, m6 + pxor m1, m1 + lea linesize3q, [linesizeq*3] + ADD_ROW_8 5, 3, destq, 1 + ADD_ROW_8 2, 3, destq+linesizeq, 1 + ADD_ROW_8 0, 3, destq+linesizeq*2, 1 + ADD_ROW_8 4, 3, destq+linesize3q, 1 + RET + +; void ff_vc1_inv_trans_4x8_sse2(uint8_t *dest, ptrdiff_t linesize, int16_t *block) +cglobal vc1_inv_trans_4x8, 3, 5, 8, dest, linesize, block, linesize3, dest4 + movq m0, [blockq+ 0] + movhps m0, [blockq+ 16] ; rows 0, 1 + movq m1, [blockq+ 32] + movhps m1, [blockq+ 48] ; rows 2, 3 + movq m2, [blockq+ 64] + movhps m2, [blockq+ 80] ; rows 4, 5 + movq m3, [blockq+ 96] + movhps m3, [blockq+112] ; rows 6, 7 + pshuflw m0, m0, q3120 ; x0 x2 x1 x3 per row + pshufhw m0, m0, q3120 + pshuflw m1, m1, q3120 + pshufhw m1, m1, q3120 + pshuflw m2, m2, q3120 + pshufhw m2, m2, q3120 + pshuflw m3, m3, q3120 + pshufhw m3, m3, q3120 + mova m4, m0 + shufps m0, m1, q2020 ; (x0,x2) pairs, rows 0-3 + shufps m4, m1, q3131 ; (x1,x3) pairs, rows 0-3 + mova m5, m2 + shufps m2, m3, q2020 ; (x0,x2) pairs, rows 4-7 + shufps m5, m3, q3131 ; (x1,x3) pairs, rows 4-7 + VC1_IDCT4_1D 0, 4, 1, 3, pd_4, 3 ; column 0: m3, 1: m0, 2: m4, 3: m1 (rows 0-3) + VC1_IDCT4_1D 2, 5, 6, 7, pd_4, 3 ; column 0: m7, 1: m2, 2: m5, 3: m6 (rows 4-7) + packssdw m3, m7 ; column 0, one row per word + packssdw m0, m2 ; column 1 + packssdw m4, m5 ; column 2 + packssdw m1, m6 ; column 3 + pshufd m2, m3, q1032 ; (row0,row4) (row1,row5) (row2,row6) (row3,row7) + punpcklwd m3, m2 + pshufd m2, m0, q1032 + punpcklwd m0, m2 + pshufd m2, m4, q1032 + punpcklwd m4, m2 + pshufd m2, m1, q1032 + punpcklwd m1, m2 + TRANSPOSE4x4D 3, 0, 4, 1, 2 ; one column per lane + VC1_IDCT8_1D 3, 0, 4, 1, 2, 5, 6, 7, pd_64, 7, 1 + ; rows 0|7: m6, 1|6: m7, 2|5: m4, 3|4: m0 + pxor m1, m1 + lea linesize3q, [linesizeq*3] + lea dest4q, [destq+linesizeq*4] + ADD_ROWS_4 6, 2, 3, destq, dest4q+linesize3q, 1 + ADD_ROWS_4 7, 2, 3, destq+linesizeq, dest4q+linesizeq*2, 1 + ADD_ROWS_4 4, 2, 3, destq+linesizeq*2, dest4q+linesizeq, 1 + ADD_ROWS_4 0, 2, 3, destq+linesize3q, dest4q, 1 + RET + +%if ARCH_X86_64 +; void ff_vc1_inv_trans_8x8_sse2(int16_t block[64]) +cglobal vc1_inv_trans_8x8, 1, 1, 12, block + mova m0, [blockq+ 0] + mova m1, [blockq+ 16] + mova m2, [blockq+ 32] + mova m3, [blockq+ 48] + mova m4, [blockq+ 64] + mova m5, [blockq+ 80] + mova m6, [blockq+ 96] + mova m7, [blockq+112] + ; first pass down the columns; (row0,row4) (row1,row5) (row2,row6) + ; (row3,row7) pairs, columns 0-3 in m8-m11 and columns 4-7 in m0-m3 + punpcklwd m8, m0, m4 + punpckhwd m0, m4 + punpcklwd m9, m1, m5 + punpckhwd m1, m5 + punpcklwd m10, m2, m6 + punpckhwd m2, m6 + punpcklwd m11, m3, m7 + punpckhwd m3, m7 + VC1_IDCT8_1D 8, 9, 10, 11, 4, 5, 6, 7, pd_4, 3, 0 + ; 0|7: m6, 1|6: m7, 2|5: m10, 3|4: m9 (columns 0-3) + VC1_IDCT8_1D 0, 1, 2, 3, 4, 5, 8, 11, pd_4, 3, 0 + ; 0|7: m8, 1|6: m11, 2|5: m2, 3|4: m1 (columns 4-7) + punpcklqdq m0, m6, m8 + punpckhqdq m6, m8 + punpcklqdq m3, m7, m11 + punpckhqdq m7, m11 + punpcklqdq m4, m10, m2 + punpckhqdq m10, m2 + punpcklqdq m5, m9, m1 + punpckhqdq m9, m1 + TRANSPOSE8x8W 0, 3, 4, 5, 9, 10, 7, 6, 1 + ; second pass down the columns of the transposed intermediate + punpcklwd m1, m0, m9 + punpckhwd m0, m9 + punpcklwd m2, m3, m10 + punpckhwd m3, m10 + punpcklwd m8, m4, m7 + punpckhwd m4, m7 + punpcklwd m11, m5, m6 + punpckhwd m5, m6 + VC1_IDCT8_1D 1, 2, 8, 11, 9, 10, 7, 6, pd_64, 7, 1 + ; 0|7: m7, 1|6: m6, 2|5: m8, 3|4: m2 (columns 0-3) + VC1_IDCT8_1D 0, 3, 4, 5, 1, 11, 9, 10, pd_64, 7, 1 + ; 0|7: m9, 1|6: m10, 2|5: m4, 3|4: m3 (columns 4-7) + punpcklqdq m0, m7, m9 + mova [blockq+ 0], m0 + punpckhqdq m7, m9 + mova [blockq+112], m7 + punpcklqdq m1, m6, m10 + mova [blockq+ 16], m1 + punpckhqdq m6, m10 + mova [blockq+ 96], m6 + punpcklqdq m5, m8, m4 + mova [blockq+ 32], m5 + punpckhqdq m8, m4 + mova [blockq+ 80], m8 + punpcklqdq m11, m2, m3 + mova [blockq+ 48], m11 + punpckhqdq m2, m3 + mova [blockq+ 64], m2 + RET +%endif -- 2.52.0 >From 5a133e56b3cca68cf0238f803df7231d90a38468 Mon Sep 17 00:00:00 2001 From: Marcos Ashton Iglesias <[email protected]> Date: Thu, 10 Sep 2026 23:51:59 +0100 Subject: [PATCH 2/2] 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's in-place calls serialize on the same block. 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) --- libavcodec/x86/vc1dsp_init.c | 5 +++ libavcodec/x86/vc1dsp_inv_trans.asm | 51 +++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) 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 5f78e9db0f..86ca37efe6 100644 --- a/libavcodec/x86/vc1dsp_inv_trans.asm +++ b/libavcodec/x86/vc1dsp_inv_trans.asm @@ -452,4 +452,55 @@ cglobal vc1_inv_trans_8x8, 1, 1, 12, block punpckhqdq m2, m3 mova [blockq+ 64], m2 RET +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 -- 2.52.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
