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]

Reply via email to