PR #22803 opened by mkver URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/22803 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/22803.patch
>From 3f105293ed23a55ba15f53c26aeee128fbbe0ae5 Mon Sep 17 00:00:00 2001 From: Andreas Rheinhardt <[email protected]> Date: Sun, 12 Apr 2026 22:34:12 +0200 Subject: [PATCH 1/4] tests/checkasm/vp3dsp: Add test for put_no_rnd_pixels_l2 Signed-off-by: Andreas Rheinhardt <[email protected]> --- tests/checkasm/vp3dsp.c | 60 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 54 insertions(+), 6 deletions(-) diff --git a/tests/checkasm/vp3dsp.c b/tests/checkasm/vp3dsp.c index a269581898..acdd1e57e8 100644 --- a/tests/checkasm/vp3dsp.c +++ b/tests/checkasm/vp3dsp.c @@ -47,8 +47,52 @@ enum { buf0[k] = buf1[k] = rnd(); \ } while (0) +static void vp3_check_put_no_rnd_pixels_l2(const VP3DSPContext *const vp3dsp) +{ + enum { + HEIGHT = 8, ///< only used height, so only tested height + WIDTH = 8, + BUF_SIZE = MAX_STRIDE * (HEIGHT - 1) + WIDTH, + SRC_BUF_SIZE = BUF_SIZE + (WIDTH - 1), ///< WIDTH-1 to use misaligned input + }; + declare_func_emms(AV_CPU_FLAG_MMX, void, uint8_t *dst, + const uint8_t *a, const uint8_t *b, + ptrdiff_t stride, int h); -static void vp3_check_loop_filter(void) + if (!check_func(vp3dsp->put_no_rnd_pixels_l2, "put_no_rnd_pixels_l2")) + return; + + DECLARE_ALIGNED(8, uint8_t, dstbuf_new)[BUF_SIZE]; + DECLARE_ALIGNED(8, uint8_t, dstbuf_ref)[BUF_SIZE]; + DECLARE_ALIGNED(4, uint8_t, src0_buf)[SRC_BUF_SIZE]; + DECLARE_ALIGNED(4, uint8_t, src1_buf)[SRC_BUF_SIZE]; + + size_t src0_offset = rnd() % WIDTH, src1_offset = rnd() % WIDTH; + ptrdiff_t stride = (rnd() % (MAX_STRIDE / WIDTH) + 1) * WIDTH; + const uint8_t *src0 = src0_buf + src0_offset, *src1 = src1_buf + src1_offset; + uint8_t *dst_new = dstbuf_new, *dst_ref = dstbuf_ref; + const int h = HEIGHT; + + if (rnd() & 1) { + // Flip stride. + dst_new += (h - 1) * stride; + dst_ref += (h - 1) * stride; + src0 += (h - 1) * stride; + src1 += (h - 1) * stride; + stride = -stride; + } + + randomize_buffers(src0_buf, src1_buf, sizeof(src0_buf)); + randomize_buffers(dstbuf_new, dstbuf_ref, sizeof(dstbuf_new)); + call_ref(dst_ref, src0, src1, stride, h); + call_new(dst_new, src0, src1, stride, h); + if (memcmp(dstbuf_new, dstbuf_ref, sizeof(dstbuf_new))) + fail(); + bench_new(dst_new, src1, src1, stride, h); +} + + +static void vp3_check_loop_filter(const VP3DSPContext *const vp3dsp) { DECLARE_ALIGNED(8, uint8_t, hor_buf0)[HORIZONTAL_BUF_SIZE]; DECLARE_ALIGNED(8, uint8_t, hor_buf1)[HORIZONTAL_BUF_SIZE]; @@ -56,7 +100,6 @@ static void vp3_check_loop_filter(void) DECLARE_ALIGNED(8, uint8_t, ver_buf1)[VERTICAL_BUF_SIZE]; DECLARE_ALIGNED(16, int, bounding_values_array)[256 + 4]; int *const bounding_values = bounding_values_array + 127; - VP3DSPContext vp3dsp; static const struct { const char *name; size_t offset; @@ -73,14 +116,12 @@ static void vp3_check_loop_filter(void) }; declare_func(void, uint8_t *src, ptrdiff_t stride, int *bounding_values); - ff_vp3dsp_init(&vp3dsp); - int filter_limit = rnd() % 128; ff_vp3dsp_set_bounding_values(bounding_values_array, filter_limit); for (size_t i = 0; i < FF_ARRAY_ELEMS(tests); ++i) { - void (*loop_filter)(uint8_t *, ptrdiff_t, int*) = *(void(**)(uint8_t *, ptrdiff_t, int*))((char*)&vp3dsp + tests[i].offset); + void (*loop_filter)(uint8_t *, ptrdiff_t, int*) = *(void(**)(uint8_t *, ptrdiff_t, int*))((const char*)vp3dsp + tests[i].offset); if (check_func(loop_filter, "%s", tests[i].name)) { uint8_t *buf0 = tests[i].horizontal ? hor_buf0 : ver_buf0; @@ -112,6 +153,13 @@ static void vp3_check_loop_filter(void) void checkasm_check_vp3dsp(void) { - vp3_check_loop_filter(); + VP3DSPContext vp3dsp; + + ff_vp3dsp_init(&vp3dsp); + + vp3_check_put_no_rnd_pixels_l2(&vp3dsp); + report("put_no_rnd_pixels_l2"); + + vp3_check_loop_filter(&vp3dsp); report("loop_filter"); } -- 2.52.0 >From 1006e32dded9301769cb9c317e7ecfabaa596e3f Mon Sep 17 00:00:00 2001 From: Andreas Rheinhardt <[email protected]> Date: Sun, 12 Apr 2026 22:39:04 +0200 Subject: [PATCH 2/4] avcodec/x86/vp3dsp: Port ff_put_vp_no_rnd_pixels8_l2_mmx to SSE2 This allows to use pavgb to reduce the amount of instruction used to calculate the average. It also avoids a load. Old benchmarks: put_no_rnd_pixels_l2_c: 13.3 ( 1.00x) put_no_rnd_pixels_l2_mmx: 11.6 ( 1.15x) New benchmarks: put_no_rnd_pixels_l2_c: 13.5 ( 1.00x) put_no_rnd_pixels_l2_sse2: 9.3 ( 1.45x) Signed-off-by: Andreas Rheinhardt <[email protected]> --- libavcodec/x86/vp3dsp.asm | 51 ++++++++++++++++-------------------- libavcodec/x86/vp3dsp_init.c | 12 ++++----- tests/checkasm/vp3dsp.c | 2 +- 3 files changed, 29 insertions(+), 36 deletions(-) diff --git a/libavcodec/x86/vp3dsp.asm b/libavcodec/x86/vp3dsp.asm index b79477288a..7b7a6879a0 100644 --- a/libavcodec/x86/vp3dsp.asm +++ b/libavcodec/x86/vp3dsp.asm @@ -34,7 +34,6 @@ vp3_idct_data: times 8 dw 64277 times 8 dw 12785 cextern pb_80 -cextern pb_FE cextern pw_4 cextern pw_8 @@ -155,40 +154,36 @@ cglobal vp3_h_loop_filter, 3, 4, 6 RET %macro PAVGB_NO_RND 0 - mova m4, m0 - mova m5, m2 - pand m4, m1 - pand m5, m3 - pxor m1, m0 - pxor m3, m2 - pand m1, m6 - pand m3, m6 - psrlq m1, 1 - psrlq m3, 1 - paddb m4, m1 - paddb m5, m3 + pxor m0, m4 + pxor m1, m4 + pxor m2, m4 + pxor m3, m4 + pavgb m0, m1 + pavgb m2, m3 + pxor m0, m4 + pxor m2, m4 %endmacro -INIT_MMX mmx -cglobal put_vp_no_rnd_pixels8_l2, 5, 6, 0, dst, src1, src2, stride, h, stride3 - mova m6, [pb_FE] +INIT_XMM sse2 +cglobal vp3_put_no_rnd_pixels8_l2, 5, 6, 5, dst, src1, src2, stride, h, stride3 lea stride3q,[strideq+strideq*2] + pcmpeqb m4, m4 .loop: - mova m0, [src1q] - mova m1, [src2q] - mova m2, [src1q+strideq] - mova m3, [src2q+strideq] + movq m0, [src1q] + movq m1, [src2q] + movq m2, [src1q+strideq] + movq m3, [src2q+strideq] PAVGB_NO_RND - mova [dstq], m4 - mova [dstq+strideq], m5 + movq [dstq], m0 + movq [dstq+strideq], m2 - mova m0, [src1q+strideq*2] - mova m1, [src2q+strideq*2] - mova m2, [src1q+stride3q] - mova m3, [src2q+stride3q] + movq m0, [src1q+strideq*2] + movq m1, [src2q+strideq*2] + movq m2, [src1q+stride3q] + movq m3, [src2q+stride3q] PAVGB_NO_RND - mova [dstq+strideq*2], m4 - mova [dstq+stride3q], m5 + movq [dstq+strideq*2], m0 + movq [dstq+stride3q], m2 lea src1q, [src1q+strideq*4] lea src2q, [src2q+strideq*4] diff --git a/libavcodec/x86/vp3dsp_init.c b/libavcodec/x86/vp3dsp_init.c index 42daf99981..4a416c6f9a 100644 --- a/libavcodec/x86/vp3dsp_init.c +++ b/libavcodec/x86/vp3dsp_init.c @@ -36,23 +36,21 @@ void ff_vp3_v_loop_filter_sse2(uint8_t *src, ptrdiff_t stride, void ff_vp3_h_loop_filter_sse2(uint8_t *src, ptrdiff_t stride, int *bounding_values); -void ff_put_vp_no_rnd_pixels8_l2_mmx(uint8_t *dst, const uint8_t *a, - const uint8_t *b, ptrdiff_t stride, - int h); +void ff_vp3_put_no_rnd_pixels8_l2_sse2(uint8_t *dst, const uint8_t *a, + const uint8_t *b, ptrdiff_t stride, + int h); av_cold void ff_vp3dsp_init_x86(VP3DSPContext *c) { int cpu_flags = av_get_cpu_flags(); - if (EXTERNAL_MMX(cpu_flags)) { - c->put_no_rnd_pixels_l2 = ff_put_vp_no_rnd_pixels8_l2_mmx; - } - if (EXTERNAL_MMXEXT(cpu_flags)) { c->idct_dc_add = ff_vp3_idct_dc_add_mmxext; } if (EXTERNAL_SSE2(cpu_flags)) { + c->put_no_rnd_pixels_l2 = ff_vp3_put_no_rnd_pixels8_l2_sse2; + c->idct_put = ff_vp3_idct_put_sse2; c->idct_add = ff_vp3_idct_add_sse2; diff --git a/tests/checkasm/vp3dsp.c b/tests/checkasm/vp3dsp.c index acdd1e57e8..abc0f2cf33 100644 --- a/tests/checkasm/vp3dsp.c +++ b/tests/checkasm/vp3dsp.c @@ -55,7 +55,7 @@ static void vp3_check_put_no_rnd_pixels_l2(const VP3DSPContext *const vp3dsp) BUF_SIZE = MAX_STRIDE * (HEIGHT - 1) + WIDTH, SRC_BUF_SIZE = BUF_SIZE + (WIDTH - 1), ///< WIDTH-1 to use misaligned input }; - declare_func_emms(AV_CPU_FLAG_MMX, void, uint8_t *dst, + declare_func(void, uint8_t *dst, const uint8_t *a, const uint8_t *b, ptrdiff_t stride, int h); -- 2.52.0 >From 0462beda143f05ffb10b2c51c321eff3dba98676 Mon Sep 17 00:00:00 2001 From: Andreas Rheinhardt <[email protected]> Date: Sun, 12 Apr 2026 23:26:56 +0200 Subject: [PATCH 3/4] tests/checkasm/vp3dsp: Add test for idct_dc_add Signed-off-by: Andreas Rheinhardt <[email protected]> --- tests/checkasm/vp3dsp.c | 51 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 45 insertions(+), 6 deletions(-) diff --git a/tests/checkasm/vp3dsp.c b/tests/checkasm/vp3dsp.c index abc0f2cf33..343ab3a44c 100644 --- a/tests/checkasm/vp3dsp.c +++ b/tests/checkasm/vp3dsp.c @@ -16,8 +16,8 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#include <assert.h> #include <stddef.h> +#include <string.h> #include "checkasm.h" #include "libavutil/intreadwrite.h" @@ -36,15 +36,14 @@ enum { #define randomize_buffers(buf0, buf1, size) \ do { \ - static_assert(sizeof(buf0[0]) == 1 && sizeof(buf1[0]) == 1, \ - "Pointer arithmetic needs to be adapted"); \ + char *b0 = (char*)buf0, *b1 = (char*)buf1; \ for (size_t k = 0; k < (size & ~3); k += 4) { \ uint32_t r = rnd(); \ - AV_WN32A(buf0 + k, r); \ - AV_WN32A(buf1 + k, r); \ + AV_WN32A(b0 + k, r); \ + AV_WN32A(b1 + k, r); \ } \ for (size_t k = size & ~3; k < size; ++k) \ - buf0[k] = buf1[k] = rnd(); \ + b0[k] = b1[k] = rnd(); \ } while (0) static void vp3_check_put_no_rnd_pixels_l2(const VP3DSPContext *const vp3dsp) @@ -91,6 +90,43 @@ static void vp3_check_put_no_rnd_pixels_l2(const VP3DSPContext *const vp3dsp) bench_new(dst_new, src1, src1, stride, h); } +static void vp3_check_idct_dc_add(const VP3DSPContext *const vp3dsp) +{ + enum { + NB_LINES = 8, + WIDTH = 8, + BUF_SIZE = MAX_STRIDE * (NB_LINES - 1) + WIDTH, + }; + + declare_func_emms(AV_CPU_FLAG_MMXEXT, void, uint8_t *dest, ptrdiff_t stride, int16_t *block); + + if (!check_func(vp3dsp->idct_dc_add, "idct_dc_add")) + return; + + DECLARE_ALIGNED(16, int16_t, block_new)[64]; + DECLARE_ALIGNED(16, int16_t, block_ref)[64]; + DECLARE_ALIGNED(8, uint8_t, dstbuf_new)[BUF_SIZE]; + DECLARE_ALIGNED(8, uint8_t, dstbuf_ref)[BUF_SIZE]; + + ptrdiff_t stride = (rnd() % (MAX_STRIDE / WIDTH) + 1) * WIDTH; + uint8_t *dst_new = dstbuf_new, *dst_ref = dstbuf_ref; + + if (rnd() & 1) { + // Flip stride. + dst_new += (NB_LINES - 1) * stride; + dst_ref += (NB_LINES - 1) * stride; + stride = -stride; + } + + randomize_buffers(dstbuf_new, dstbuf_ref, sizeof(dstbuf_ref)); + randomize_buffers(block_new, block_ref, sizeof(block_new)); + call_ref(dst_ref, stride, block_ref); + call_new(dst_new, stride, block_new); + if (memcmp(dstbuf_new, dstbuf_ref, sizeof(dstbuf_new)) || + memcmp(block_new, block_ref, sizeof(block_new))) + fail(); + bench_new(dst_new, stride, block_new); +} static void vp3_check_loop_filter(const VP3DSPContext *const vp3dsp) { @@ -160,6 +196,9 @@ void checkasm_check_vp3dsp(void) vp3_check_put_no_rnd_pixels_l2(&vp3dsp); report("put_no_rnd_pixels_l2"); + vp3_check_idct_dc_add(&vp3dsp); + report("idct_dc_add"); + vp3_check_loop_filter(&vp3dsp); report("loop_filter"); } -- 2.52.0 >From 043ba4e308905fb68bf19f8997aa5b57965f36d5 Mon Sep 17 00:00:00 2001 From: Andreas Rheinhardt <[email protected]> Date: Sun, 12 Apr 2026 23:50:52 +0200 Subject: [PATCH 4/4] avcodec/x86/vp3dsp: Port ff_vp3_idct_dc_add_mmxext to SSE2 This change should improve performance on Skylake and later Intel CPUs (which have only half the ports for saturated adds/subs for mmx register compared to xmm register): llvm-mca predicts a 25% performance improvement on Skylake. Signed-off-by: Andreas Rheinhardt <[email protected]> --- libavcodec/x86/vp3dsp.asm | 10 +++++----- libavcodec/x86/vp3dsp_init.c | 7 ++----- tests/checkasm/vp3dsp.c | 2 +- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/libavcodec/x86/vp3dsp.asm b/libavcodec/x86/vp3dsp.asm index 7b7a6879a0..3d8667238a 100644 --- a/libavcodec/x86/vp3dsp.asm +++ b/libavcodec/x86/vp3dsp.asm @@ -1,5 +1,5 @@ ;****************************************************************************** -;* MMX/SSE2-optimized functions for the VP3 decoder +;* SSE2-optimized functions for the VP3 decoder ;* Copyright (c) 2007 Aurelien Jacobs <[email protected]> ;* ;* This file is part of FFmpeg. @@ -21,7 +21,7 @@ %include "libavutil/x86/x86util.asm" -; MMX-optimized functions cribbed from the original VP3 source code. +; ASM-optimized functions cribbed from the original VP3 source code. SECTION_RODATA @@ -429,15 +429,15 @@ vp3_idct_funcs movq [r0+r2 ], m5 %endmacro -INIT_MMX mmxext -cglobal vp3_idct_dc_add, 3, 4 +INIT_XMM sse2 +cglobal vp3_idct_dc_add, 3, 4, 6 movsx r3, word [r2] mov word [r2], 0 lea r2, [r1*3] add r3, 15 sar r3, 5 movd m0, r3d - pshufw m0, m0, 0x0 + SPLATW m0, m0 pxor m1, m1 psubw m1, m0 packuswb m0, m0 diff --git a/libavcodec/x86/vp3dsp_init.c b/libavcodec/x86/vp3dsp_init.c index 4a416c6f9a..0ba4f00ed6 100644 --- a/libavcodec/x86/vp3dsp_init.c +++ b/libavcodec/x86/vp3dsp_init.c @@ -29,7 +29,7 @@ void ff_vp3_idct_put_sse2(uint8_t *dest, ptrdiff_t stride, int16_t *block); void ff_vp3_idct_add_sse2(uint8_t *dest, ptrdiff_t stride, int16_t *block); -void ff_vp3_idct_dc_add_mmxext(uint8_t *dest, ptrdiff_t stride, int16_t *block); +void ff_vp3_idct_dc_add_sse2(uint8_t *dest, ptrdiff_t stride, int16_t *block); void ff_vp3_v_loop_filter_sse2(uint8_t *src, ptrdiff_t stride, int *bounding_values); @@ -44,15 +44,12 @@ av_cold void ff_vp3dsp_init_x86(VP3DSPContext *c) { int cpu_flags = av_get_cpu_flags(); - if (EXTERNAL_MMXEXT(cpu_flags)) { - c->idct_dc_add = ff_vp3_idct_dc_add_mmxext; - } - if (EXTERNAL_SSE2(cpu_flags)) { c->put_no_rnd_pixels_l2 = ff_vp3_put_no_rnd_pixels8_l2_sse2; c->idct_put = ff_vp3_idct_put_sse2; c->idct_add = ff_vp3_idct_add_sse2; + c->idct_dc_add = ff_vp3_idct_dc_add_sse2; c->v_loop_filter = c->v_loop_filter_unaligned = ff_vp3_v_loop_filter_sse2; c->h_loop_filter = c->h_loop_filter_unaligned = ff_vp3_h_loop_filter_sse2; diff --git a/tests/checkasm/vp3dsp.c b/tests/checkasm/vp3dsp.c index 343ab3a44c..ada204c420 100644 --- a/tests/checkasm/vp3dsp.c +++ b/tests/checkasm/vp3dsp.c @@ -98,7 +98,7 @@ static void vp3_check_idct_dc_add(const VP3DSPContext *const vp3dsp) BUF_SIZE = MAX_STRIDE * (NB_LINES - 1) + WIDTH, }; - declare_func_emms(AV_CPU_FLAG_MMXEXT, void, uint8_t *dest, ptrdiff_t stride, int16_t *block); + declare_func(void, uint8_t *dest, ptrdiff_t stride, int16_t *block); if (!check_func(vp3dsp->idct_dc_add, "idct_dc_add")) return; -- 2.52.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
