Commit 1d3031535b for ffmpeg

commit 1d3031535b58e3e65c9865726a09668abbcb86a0
Author: DROOdotFOO <drew@axol.io>
Date:   Thu Jun 11 01:22:46 2026 +0200

    avfilter/x86/vf_threshold: handle non-multiple-of-mmsize widths

    ff_threshold{8,16}_{sse4,avx2} iterate in fixed 16-/32-byte chunks
    and over-read/-write past w when w is not a multiple of mmsize.
    Split the row at the largest mmsize multiple and run a C tail for
    the remainder. Strengthen the checkasm test: sweep widths 1..w-1,
    0xAA-sentinel output buffers, multi-row, distinct per-pointer
    linesizes, and add depth 10/12 coverage.

    Signed-off-by: DROOdotFOO <drew@axol.io>

diff --git a/libavfilter/x86/vf_threshold_init.c b/libavfilter/x86/vf_threshold_init.c
index 8e42296791..ce01414332 100644
--- a/libavfilter/x86/vf_threshold_init.c
+++ b/libavfilter/x86/vf_threshold_init.c
@@ -18,6 +18,8 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */

+#include <stdint.h>
+
 #include "libavutil/attributes.h"
 #include "libavutil/cpu.h"
 #include "libavutil/x86/cpu.h"
@@ -37,23 +39,92 @@ THRESHOLD_FUNC(8, avx2)
 THRESHOLD_FUNC(16, sse4)
 THRESHOLD_FUNC(16, avx2)

+static void threshold8_tail(const uint8_t *in, const uint8_t *threshold,
+                            const uint8_t *min, const uint8_t *max,
+                            uint8_t *out,
+                            ptrdiff_t ilinesize, ptrdiff_t tlinesize,
+                            ptrdiff_t flinesize, ptrdiff_t slinesize,
+                            ptrdiff_t olinesize,
+                            int start, int end, int h)
+{
+    for (int y = 0; y < h; y++) {
+        for (int x = start; x < end; x++)
+            out[x] = in[x] <= threshold[x] ? min[x] : max[x];
+        in        += ilinesize;
+        threshold += tlinesize;
+        min       += flinesize;
+        max       += slinesize;
+        out       += olinesize;
+    }
+}
+
+static void threshold16_tail(const uint8_t *iin, const uint8_t *tthreshold,
+                             const uint8_t *ffirst, const uint8_t *ssecond,
+                             uint8_t *oout,
+                             ptrdiff_t ilinesize, ptrdiff_t tlinesize,
+                             ptrdiff_t flinesize, ptrdiff_t slinesize,
+                             ptrdiff_t olinesize,
+                             int start, int end, int h)
+{
+    const uint16_t *in        = (const uint16_t *)iin;
+    const uint16_t *threshold = (const uint16_t *)tthreshold;
+    const uint16_t *min       = (const uint16_t *)ffirst;
+    const uint16_t *max       = (const uint16_t *)ssecond;
+    uint16_t       *out       = (uint16_t *)oout;
+
+    for (int y = 0; y < h; y++) {
+        for (int x = start; x < end; x++)
+            out[x] = in[x] <= threshold[x] ? min[x] : max[x];
+        in        += ilinesize / 2;
+        threshold += tlinesize / 2;
+        min       += flinesize / 2;
+        max       += slinesize / 2;
+        out       += olinesize / 2;
+    }
+}
+
+#define THRESHOLD_X86(depth, opt, vec_elements)                                              \
+static void threshold##depth##_##opt##_x86(const uint8_t *in, const uint8_t *threshold,      \
+                                           const uint8_t *min, const uint8_t *max,           \
+                                           uint8_t *out,                                     \
+                                           ptrdiff_t ilinesize, ptrdiff_t tlinesize,         \
+                                           ptrdiff_t flinesize, ptrdiff_t slinesize,         \
+                                           ptrdiff_t olinesize,                              \
+                                           int w, int h)                                     \
+{                                                                                            \
+    int aligned_w = w & ~((vec_elements) - 1);                                               \
+    if (aligned_w > 0)                                                                       \
+        ff_threshold##depth##_##opt(in, threshold, min, max, out,                            \
+                                    ilinesize, tlinesize, flinesize, slinesize, olinesize,   \
+                                    aligned_w, h);                                           \
+    if (aligned_w < w)                                                                       \
+        threshold##depth##_tail(in, threshold, min, max, out,                                \
+                                ilinesize, tlinesize, flinesize, slinesize, olinesize,       \
+                                aligned_w, w, h);                                            \
+}
+
+THRESHOLD_X86(8,  sse4, 16)
+THRESHOLD_X86(8,  avx2, 32)
+THRESHOLD_X86(16, sse4,  8)
+THRESHOLD_X86(16, avx2, 16)
+
 av_cold void ff_threshold_init_x86(ThresholdContext *s)
 {
     int cpu_flags = av_get_cpu_flags();

     if (s->depth == 8) {
         if (EXTERNAL_SSE4(cpu_flags)) {
-            s->threshold = ff_threshold8_sse4;
+            s->threshold = threshold8_sse4_x86;
         }
         if (EXTERNAL_AVX2_FAST(cpu_flags)) {
-            s->threshold = ff_threshold8_avx2;
+            s->threshold = threshold8_avx2_x86;
         }
     } else if (s->depth == 16) {
         if (EXTERNAL_SSE4(cpu_flags)) {
-            s->threshold = ff_threshold16_sse4;
+            s->threshold = threshold16_sse4_x86;
         }
         if (EXTERNAL_AVX2_FAST(cpu_flags)) {
-            s->threshold = ff_threshold16_avx2;
+            s->threshold = threshold16_avx2_x86;
         }
     }
 }
diff --git a/tests/checkasm/vf_threshold.c b/tests/checkasm/vf_threshold.c
index e6a425edfe..36fdda167c 100644
--- a/tests/checkasm/vf_threshold.c
+++ b/tests/checkasm/vf_threshold.c
@@ -22,8 +22,11 @@
 #include "libavutil/intreadwrite.h"
 #include "libavutil/mem_internal.h"

-#define WIDTH 256
-#define WIDTH_PADDED 256 + 32
+#define WIDTH        256
+#define HEIGHT       3
+#define WIDTH_PADDED (WIDTH + 32)
+#define LINESIZE_MAX (WIDTH_PADDED + 32)
+#define BUF_SIZE     (LINESIZE_MAX * HEIGHT)

 #define randomize_buffers(buf, size)     \
     do {                                 \
@@ -34,14 +37,15 @@
     } while (0)

 static void check_threshold(int depth){
-    LOCAL_ALIGNED_32(uint8_t, in       , [WIDTH_PADDED]);
-    LOCAL_ALIGNED_32(uint8_t, threshold, [WIDTH_PADDED]);
-    LOCAL_ALIGNED_32(uint8_t, min      , [WIDTH_PADDED]);
-    LOCAL_ALIGNED_32(uint8_t, max      , [WIDTH_PADDED]);
-    LOCAL_ALIGNED_32(uint8_t, out_ref  , [WIDTH_PADDED]);
-    LOCAL_ALIGNED_32(uint8_t, out_new  , [WIDTH_PADDED]);
+    LOCAL_ALIGNED_32(uint8_t, in       , [BUF_SIZE]);
+    LOCAL_ALIGNED_32(uint8_t, threshold, [BUF_SIZE]);
+    LOCAL_ALIGNED_32(uint8_t, min      , [BUF_SIZE]);
+    LOCAL_ALIGNED_32(uint8_t, max      , [BUF_SIZE]);
+    LOCAL_ALIGNED_32(uint8_t, out_ref  , [BUF_SIZE]);
+    LOCAL_ALIGNED_32(uint8_t, out_new  , [BUF_SIZE]);
     ptrdiff_t line_size = WIDTH_PADDED;
-    int w = WIDTH;
+    int step = depth > 8 ? 2 : 1;
+    int w = WIDTH / step;

     declare_func(void, const uint8_t *in, const uint8_t *threshold,
                  const uint8_t *min, const uint8_t *max, uint8_t *out,
@@ -53,26 +57,46 @@ static void check_threshold(int depth){
     s.depth = depth;
     ff_threshold_init(&s);

-    memset(in,     0, WIDTH_PADDED);
-    memset(threshold, 0, WIDTH_PADDED);
-    memset(min, 0, WIDTH_PADDED);
-    memset(max, 0, WIDTH_PADDED);
-    memset(out_ref, 0, WIDTH_PADDED);
-    memset(out_new, 0, WIDTH_PADDED);
-    randomize_buffers(in, WIDTH);
-    randomize_buffers(threshold, WIDTH);
-    randomize_buffers(min, WIDTH);
-    randomize_buffers(max, WIDTH);
-
-    if (depth == 16)
-        w /= 2;
+    memset(in,        0, BUF_SIZE);
+    memset(threshold, 0, BUF_SIZE);
+    memset(min,       0, BUF_SIZE);
+    memset(max,       0, BUF_SIZE);
+    randomize_buffers(in,        BUF_SIZE);
+    randomize_buffers(threshold, BUF_SIZE);
+    randomize_buffers(min,       BUF_SIZE);
+    randomize_buffers(max,       BUF_SIZE);

     if (check_func(s.threshold, "threshold%d", depth)) {
-        call_ref(in, threshold, min, max, out_ref, line_size, line_size, line_size, line_size, line_size, w, 1);
-        call_new(in, threshold, min, max, out_new, line_size, line_size, line_size, line_size, line_size, w, 1);
-        if (memcmp(out_ref, out_new, WIDTH))
+        for (int i = 1; i < w; i++) {
+            memset(out_ref, 0xAA, BUF_SIZE);
+            memset(out_new, 0xAA, BUF_SIZE);
+            call_ref(in, threshold, min, max, out_ref,
+                     line_size, line_size, line_size, line_size, line_size, i, 1);
+            call_new(in, threshold, min, max, out_new,
+                     line_size, line_size, line_size, line_size, line_size, i, 1);
+            if (memcmp(out_ref, out_new, BUF_SIZE))
+                fail();
+        }
+        memset(out_ref, 0xAA, BUF_SIZE);
+        memset(out_new, 0xAA, BUF_SIZE);
+        call_ref(in, threshold, min, max, out_ref,
+                 line_size, line_size, line_size, line_size, line_size, w, HEIGHT);
+        call_new(in, threshold, min, max, out_new,
+                 line_size, line_size, line_size, line_size, line_size, w, HEIGHT);
+        if (memcmp(out_ref, out_new, BUF_SIZE))
+            fail();
+        memset(out_ref, 0xAA, BUF_SIZE);
+        memset(out_new, 0xAA, BUF_SIZE);
+        call_ref(in, threshold, min, max, out_ref,
+                 line_size + 0,  line_size + 8,  line_size + 16,
+                 line_size + 24, line_size + 32, w, HEIGHT);
+        call_new(in, threshold, min, max, out_new,
+                 line_size + 0,  line_size + 8,  line_size + 16,
+                 line_size + 24, line_size + 32, w, HEIGHT);
+        if (memcmp(out_ref, out_new, BUF_SIZE))
             fail();
-        bench_new(in, threshold, min, max, out_new, line_size, line_size, line_size, line_size, line_size, w, 1);
+        bench_new(in, threshold, min, max, out_new,
+                  line_size, line_size, line_size, line_size, line_size, w, 1);
     }
 }

@@ -81,6 +105,12 @@ void checkasm_check_vf_threshold(void)
     check_threshold(8);
     report("threshold8");

+    check_threshold(10);
+    report("threshold10");
+
+    check_threshold(12);
+    report("threshold12");
+
     check_threshold(16);
     report("threshold16");
 }