Commit af25036ac0 for ffmpeg
commit af25036ac09146b5187adfc247a643b3f993545c
Author: Devin Heitmueller <dheitmueller@ltnglobal.com>
Date: Wed Sep 16 15:59:03 2026 -0400
avcodec/bitpacked: add AVX-512ICL unpacking
Use a masked exact-width load and VBMI byte permutations to expand each
40-byte group, then compact the planar Y, U, and V outputs. Handle an
eight-pixel prefix separately so the hot loop can use the negative-width
output-offset pattern from v210.
The AVX-512ICL feature tier is required for vpermb. CPUs with baseline
AVX-512 but without VBMI continue to use AVX2. Reuse one result register for
all three output planes so the function also assembles for 32-bit x86.
The implementation passed 300 consecutive checkasm seeds and assembled
as ELF, Windows COFF, and Mach-O in both 32- and 64-bit modes.
Benchmark command:
./tests/checkasm/checkasm --bench --test=bitpackeddec \
--duration=1000000 60300
Intel Xeon E-2356G, GCC 8.5, NASM 2.15.03:
bitpacked_unpack_yuv422p10_c: 13502.8
bitpacked_unpack_yuv422p10_ssse3: 3436.6 ( 3.93x)
bitpacked_unpack_yuv422p10_avx2: 2222.8 ( 6.07x)
bitpacked_unpack_yuv422p10_avx512icl: 1131.5 (11.93x)
diff --git a/libavcodec/x86/bitpacked.asm b/libavcodec/x86/bitpacked.asm
index db15a2f91f..deccdcd557 100644
--- a/libavcodec/x86/bitpacked.asm
+++ b/libavcodec/x86/bitpacked.asm
@@ -21,8 +21,27 @@
%include "libavutil/x86/x86util.asm"
-SECTION_RODATA 32
+SECTION_RODATA 64
+unpack_shuf_avx512icl:
+ db 1, 0, 2, 1, 3, 2, 4, 3, 6, 5, 7, 6, 8, 7, 9, 8
+ db 11,10, 12,11, 13,12, 14,13, 16,15, 17,16, 18,17, 19,18
+ db 21,20, 22,21, 23,22, 24,23, 26,25, 27,26, 28,27, 29,28
+ db 31,30, 32,31, 33,32, 34,33, 36,35, 37,36, 38,37, 39,38
+y_shuf_avx512icl:
+ db 2, 3, 6, 7, 10,11, 14,15, 18,19, 22,23, 26,27, 30,31
+ db 34,35, 38,39, 42,43, 46,47, 50,51, 54,55, 58,59, 62,63
+ times 32 db 0
+u_shuf_avx512icl:
+ db 0, 1, 8, 9, 16,17, 24,25, 32,33, 40,41, 48,49, 56,57
+ times 48 db 0
+v_shuf_avx512icl:
+ db 4, 5, 12,13, 20,21, 28,29, 36,37, 44,45, 52,53, 60,61
+ times 48 db 0
+input_mask_avx512icl: dq 0x000000ffffffffff
+tail_mask_avx512icl: dq 0x00000000000fffff
+
+ALIGN 32
unpack_shuf_avx2:
db 1,0, 2,1, 3,2, 4,3, 6,5, 7,6, 8,7, 9,8
db 5,4, 6,5, 7,6, 8,7, 10,9, 11,10, 12,11, 13,12
@@ -184,3 +203,63 @@ cglobal bitpacked_unpack_yuv422p10, 5, 5, 8, src, y, u, v, w
.ret:
RET
%endif
+
+%if HAVE_AVX512ICL_EXTERNAL
+INIT_ZMM avx512icl
+cglobal bitpacked_unpack_yuv422p10, 5, 5, 7, src, y, u, v, w
+ mova m2, [unpack_shuf_avx512icl]
+ VBROADCASTI128 m3, [unpack_mult]
+ mova m4, [y_shuf_avx512icl]
+ mova m5, [u_shuf_avx512icl]
+ mova m6, [v_shuf_avx512icl]
+ kmovq k1, [input_mask_avx512icl]
+ kmovq k2, [tail_mask_avx512icl]
+
+ test wd, 8
+ jz .setup
+ vmovdqu8 m0{k2}{z}, [srcq]
+ vpermb m0, m2, m0
+ pmullw m0, m3
+ psrlw m0, 6
+
+ vpermb m1, m4, m0
+ movu [yq], xm1
+ vpermb m1, m5, m0
+ movq [uq], xm1
+ vpermb m1, m6, m0
+ movq [vq], xm1
+
+ add srcq, 20
+ add yq, 16
+ add uq, 8
+ add vq, 8
+ sub wd, 8
+ jz .ret
+
+.setup:
+ movsxdifnidn wq, wd
+ lea yq, [yq+2*wq]
+ add uq, wq
+ add vq, wq
+ neg wq
+
+.loop:
+ vmovdqu8 m0{k1}{z}, [srcq]
+ vpermb m0, m2, m0
+ pmullw m0, m3
+ psrlw m0, 6
+
+ vpermb m1, m4, m0
+ movu [yq+2*wq], ym1
+ vpermb m1, m5, m0
+ movu [uq+wq], xm1
+ vpermb m1, m6, m0
+ movu [vq+wq], xm1
+
+ add srcq, 40
+ add wq, 16
+ jl .loop
+
+.ret:
+ RET
+%endif
diff --git a/libavcodec/x86/bitpacked_init.c b/libavcodec/x86/bitpacked_init.c
index 01fce4ba16..4c5295befb 100644
--- a/libavcodec/x86/bitpacked_init.c
+++ b/libavcodec/x86/bitpacked_init.c
@@ -32,6 +32,11 @@ void ff_bitpacked_unpack_yuv422p10_avx2(const uint8_t *src,
uint16_t *y, uint16_t *u, uint16_t *v,
int width);
#endif
+#if HAVE_AVX512ICL_EXTERNAL
+void ff_bitpacked_unpack_yuv422p10_avx512icl(const uint8_t *src,
+ uint16_t *y, uint16_t *u,
+ uint16_t *v, int width);
+#endif
av_cold void ff_bitpacked_init_x86(struct BitpackedContext *s)
{
@@ -44,4 +49,9 @@ av_cold void ff_bitpacked_init_x86(struct BitpackedContext *s)
if (EXTERNAL_AVX2(cpu_flags))
s->unpack_yuv422p10 = ff_bitpacked_unpack_yuv422p10_avx2;
#endif
+
+#if HAVE_AVX512ICL_EXTERNAL
+ if (EXTERNAL_AVX512ICL(cpu_flags))
+ s->unpack_yuv422p10 = ff_bitpacked_unpack_yuv422p10_avx512icl;
+#endif
}