PR #25387 opened by Niklas Haas (haasn)
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25387
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25387.patch

Also includes a handful of fixes revealed by these new tests.

Ticks off one rung on the ladder to [swscale 
stabilization](https://code.ffmpeg.org/FFmpeg/FFmpeg/issues/22264)


>From 21dd01f223b359088026f111cf17abec45a4fe02 Mon Sep 17 00:00:00 2001
From: Niklas Haas <[email protected]>
Date: Fri, 23 Oct 2026 13:39:52 +0200
Subject: [PATCH 1/7] Squashed 'tests/checkasm/ext/' changes from
 dc9930dd0b..3bbd9e31ed

3bbd9e31ed Allow adding attributes to BUF_RECT() buffers
61fd704965 Avoid compiling empty translation units
fc6b9f911b utils: limit statusline to terminal width
a2f3c11121 utils: distinguish between known and unknown terminal width
d7d0c463b8 utils: move statusline clear/print logic to helper functions

git-subtree-dir: tests/checkasm/ext
git-subtree-split: 3bbd9e31edb37fb9ea8d933c6cad0b70303c5615
---
 docs/writing-tests.md    |  3 +++
 include/checkasm/utils.h |  8 ++++++-
 src/perf/linux.c         | 12 +++++-----
 src/perf/macos_kperf.c   |  3 +--
 src/riscv/cpu.c          |  3 ++-
 src/utils.c              | 50 +++++++++++++++++++++++++---------------
 tests/generic.c          |  6 ++++-
 7 files changed, 55 insertions(+), 30 deletions(-)

diff --git a/docs/writing-tests.md b/docs/writing-tests.md
index 62daedd348a..9e953d0cb3c 100644
--- a/docs/writing-tests.md
+++ b/docs/writing-tests.md
@@ -75,6 +75,9 @@ CHECKASM_ALIGN(uint8_t buf[1024]);
 // For 2D buffers with automatic padding and stride calculation
 // - Defines `dst` as a pointer to a 64x32 area, and `dst_stride` (in bytes)
 BUF_RECT(uint8_t, dst, 64, 32);
+
+// Large buffers can be made static to avoid overflowing the stack
+static BUF_RECT(uint16_t, frame, 3840, 2160);
 @endcode
 
 **Important:** Apply CHECKASM_ALIGN() to each buffer individually:
diff --git a/include/checkasm/utils.h b/include/checkasm/utils.h
index 518b4e84e23..58b3200ad84 100644
--- a/include/checkasm/utils.h
+++ b/include/checkasm/utils.h
@@ -670,6 +670,10 @@ CHECKASM_API int checkasm_check_impl_float_ulp(const char 
*file, int line,
  * - name_buf_h: Total buffer height in lines (with padding)
  * - name: Pointer to start of usable region
  *
+ * @note This macro can be prefixed with additional attributes, e.g. `static`,
+ * to affect the storage class of the actual array. The other variables are
+ * always local, so this must still be used inside a function.
+ *
  * @code
  * BUF_RECT(uint8_t, src, 64, 32);
  * BUF_RECT(uint8_t, dst, 64, 32);
@@ -678,12 +682,14 @@ CHECKASM_API int checkasm_check_impl_float_ulp(const char 
*file, int line,
  * CLEAR_BUF_RECT(dst);
  * // ...
  * checkasm_call_new(dst, dst_stride, src, src_stride, 64, 32);
+ *
+ * static BUF_RECT(uint8_t, big, 4096, 2160); // not allocated on the stack
  * @endcode
  */
 #define BUF_RECT(type, name, w, h)                                             
          \
+    CHECKASM_ALIGN(type name##_buf[((h) + 32) * (CHECKASM_ROUND(w, 64) + 64) + 
64]);     \
     DECL_CHECK_FUNC(*checkasm_check_impl_##name##_type, type)                  
          \
         = checkasm_check_impl_##type;                                          
          \
-    CHECKASM_ALIGN(type name##_buf[((h) + 32) * (CHECKASM_ROUND(w, 64) + 64) + 
64]);     \
     const int name##_buf_w = CHECKASM_ROUND(w, 64) + 64;                       
          \
     const int name##_buf_h = (h) + 32;                                         
          \
     ptrdiff_t name##_stride = sizeof(type) * name##_buf_w;                     
          \
diff --git a/src/perf/linux.c b/src/perf/linux.c
index 70c972cc806..de1f686e788 100644
--- a/src/perf/linux.c
+++ b/src/perf/linux.c
@@ -28,11 +28,13 @@
 
 #include "checkasm_config.h"
 
-#if HAVE_LINUX_PERF
+#ifndef _GNU_SOURCE
+  #define _GNU_SOURCE
+#endif
 
-  #ifndef _GNU_SOURCE
-    #define _GNU_SOURCE
-  #endif
+#include "internal.h"
+
+#if HAVE_LINUX_PERF
 
   #include <linux/perf_event.h>
   #include <sys/ioctl.h>
@@ -43,8 +45,6 @@
     #include <pthread.h>
   #endif
 
-  #include "internal.h"
-
 static int perf_sysfd = -1;
 
 /* The pinned CPU index, or -1 unless the thread is pinned to one CPU */
diff --git a/src/perf/macos_kperf.c b/src/perf/macos_kperf.c
index 93f845f918b..02665259a1c 100644
--- a/src/perf/macos_kperf.c
+++ b/src/perf/macos_kperf.c
@@ -28,14 +28,13 @@
 
 #include "checkasm_config.h"
 
+#include "internal.h"
 #include "perf_internal.h"
 
 #if HAVE_MACOS_KPERF
 
   #include <dlfcn.h>
 
-  #include "internal.h"
-
   #define CFGWORD_EL0A64EN_MASK       (0x20000)
   #define CPMU_CORE_CYCLE             0x02
   #define KPC_CLASS_FIXED_MASK        (1 << 0)
diff --git a/src/riscv/cpu.c b/src/riscv/cpu.c
index 4f3121086c6..6f5176dd638 100644
--- a/src/riscv/cpu.c
+++ b/src/riscv/cpu.c
@@ -27,6 +27,8 @@
 
 #include "checkasm_config.h"
 
+#include "internal.h"
+
 #if ARCH_RISCV
 
   #ifndef _GNU_SOURCE
@@ -34,7 +36,6 @@
   #endif
 
   #include "cpu.h"
-  #include "internal.h"
 
   #include <inttypes.h>
   #include <limits.h>
diff --git a/src/utils.c b/src/utils.c
index 03c2e711869..7c51383d1a7 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -468,6 +468,27 @@ DEF_CHECKASM_INIT_MASK(16, uint16_t)
 static int use_printf_color[2];
 static char statusline[256];
 static int statusline_visible;
+static int get_terminal_width(void);
+
+static void statusline_clear(void)
+{
+    if (!statusline_visible)
+        return;
+    fprintf(stderr, "\r\033[K"); /* clear line */
+    statusline_visible = 0;
+}
+
+static void statusline_show(void)
+{
+    if (!statusline[0])
+        return;
+    const int term_w = get_terminal_width();
+    int len = (int) strlen(statusline);
+    if (term_w && len > term_w)
+        len = term_w;
+    fprintf(stderr, "%.*s", len, statusline);
+    statusline_visible = 1;
+}
 
 /* Print colored text to stderr if the terminal supports it */
 int checkasm_vfprintf(FILE *const f, const int color, const char *const fmt, 
va_list arg)
@@ -477,10 +498,8 @@ int checkasm_vfprintf(FILE *const f, const int color, 
const char *const fmt, va_
     if (!use_color || !fmt_len)
         return vfprintf(f, fmt, arg);
 
-    if (f == stderr && statusline_visible) {
-        fprintf(f, "\r\033[K"); /* clear line */
-        statusline_visible = 0;
-    }
+    if (f == stderr)
+        statusline_clear();
 
     if (color >= 0)
         fprintf(f, "\x1b[0;%dm", color);
@@ -490,10 +509,8 @@ int checkasm_vfprintf(FILE *const f, const int color, 
const char *const fmt, va_
     if (color >= 0)
         fprintf(f, "\x1b[0m");
 
-    if (f == stderr && statusline[0] && fmt[fmt_len - 1] == '\n') {
-        fprintf(f, "%s", statusline);
-        statusline_visible = 1;
-    }
+    if (f == stderr && fmt[fmt_len - 1] == '\n')
+        statusline_show();
 
     return ret;
 }
@@ -508,15 +525,9 @@ void checkasm_statusline(const char *status)
 
     snprintf(statusline, sizeof(statusline), "%s", status);
 
-    if (statusline_visible) {
-        fprintf(stderr, "\r\033[K");
-        statusline_visible = 0;
-    }
-
-    if (statusline[0]) {
-        fprintf(stderr, "%s", statusline);
-        statusline_visible = 1;
-    }
+    /* refresh statusline */
+    statusline_clear();
+    statusline_show();
 }
 
 static COLD int should_use_color(FILE *const f)
@@ -564,7 +575,7 @@ static int get_terminal_width(void)
     if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) != -1)
         return w.ws_col;
 #endif
-    return 80;
+    return 0;
 }
 
 void checkasm_json(CheckasmJson *json, const char *key, const char *const fmt, 
...)
@@ -799,7 +810,8 @@ static int check_err(const char *const file, const int 
line, const char *const n
 #define DEF_CHECKASM_CHECK_BODY(compare, type, fmt, fmtw)                      
          \
     do {                                                                       
          \
         const int overhead   = 5 + 3 + 3;                                      
          \
-        const int term_width = get_terminal_width() - overhead;                
          \
+        const int term_w_raw = get_terminal_width();                           
          \
+        const int term_width = (term_w_raw ? term_w_raw : 80) - overhead;      
          \
         const int aligned_w  = (w + align_w - 1) & ~(align_w - 1);             
          \
         stride1 /= sizeof(type);                                               
          \
         stride2 /= sizeof(type);                                               
          \
diff --git a/tests/generic.c b/tests/generic.c
index 407a288c0d2..a8ed85a028f 100644
--- a/tests/generic.c
+++ b/tests/generic.c
@@ -38,7 +38,11 @@ void selftest_test_copy(copy_func fun, const char *name, 
const int min_width)
 {
 #define WIDTH 256
     BUF_RECT(uint8_t, c_dst, WIDTH, 1);
-    BUF_RECT(uint8_t, a_dst, WIDTH, 1);
+    static BUF_RECT(uint8_t, a_dst, WIDTH, 1);
+
+    /* Only compiles if a_dst_buf has static storage duration */
+    static const uint8_t *const a_dst_static = a_dst_buf;
+    (void) a_dst_static;
 
     CHECKASM_ALIGN(uint8_t src[WIDTH]);
     INITIALIZE_BUF(src);
-- 
2.54.0


>From 0462685409f59ad3866a231925a70986cd3c37b8 Mon Sep 17 00:00:00 2001
From: Michael Niedermayer <[email protected]>
Date: Fri, 2 Oct 2026 03:25:33 +0200
Subject: [PATCH 2/7] swscale/graph: do not copy past the last line in
 run_copy()

Use ff_copyPlane() with the width of the line. It still copies equal
positive linesizes as one block, but ends it with the last line.

Found during triage of the security report edlOwd4qVGBw.

Fixes: out of array read
Fixes: out of array write
Fixes: negative size memcpy()
Fixes: xvstjaVdxtut
Regression since: bf738412e8
Replicated through API

---

This also fixes copying negative linesizes.

Signed-off-by: Niklas Haas <[email protected]>
---
 libswscale/graph.c | 11 +++--------
 1 file changed, 3 insertions(+), 8 deletions(-)

diff --git a/libswscale/graph.c b/libswscale/graph.c
index a980af1ee14..cc8e5cf7a23 100644
--- a/libswscale/graph.c
+++ b/libswscale/graph.c
@@ -298,15 +298,10 @@ static void run_copy(const SwsFrame *out, const SwsFrame 
*in, int y, int h,
 
         if (in_data[i] == out_data[i]) {
             av_assert0(in->linesize[i] == out->linesize[i]);
-        } else if (in->linesize[i] == out->linesize[i]) {
-            memcpy(out_data[i], in_data[i], lines * out->linesize[i]);
         } else {
-            const int linesize = FFMIN(out->linesize[i], in->linesize[i]);
-            for (int j = 0; j < lines; j++) {
-                memcpy(out_data[i], in_data[i], linesize);
-                in_data[i]  += in->linesize[i];
-                out_data[i] += out->linesize[i];
-            }
+            ff_copyPlane(in_data[i], in->linesize[i], 0, lines,
+                         av_image_get_linesize(out->format, out->width, i),
+                         out_data[i], out->linesize[i]);
         }
     }
 }
-- 
2.54.0


>From 5e8dfc3089d1acc98252dee6903b67148efb8b08 Mon Sep 17 00:00:00 2001
From: Michael Niedermayer <[email protected]>
Date: Fri, 2 Oct 2026 06:01:09 +0200
Subject: [PATCH 3/7] swscale/ops_memcpy: do not clear or copy past the last
 line

Found during triage of the security report edlOwd4qVGBw.

Fixes: out of array read
Fixes: out of array write
Fixes: negative size memset() / memcpy()
Fixes: orU7yZg5HmsB
Regression since: a151b426f9
Replicated through API
Replicated through UnModified FFmpeg
Signed-off-by: Niklas Haas <[email protected]>
---
 libswscale/ops_memcpy.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/libswscale/ops_memcpy.c b/libswscale/ops_memcpy.c
index 52ba64b0c37..735006ab188 100644
--- a/libswscale/ops_memcpy.c
+++ b/libswscale/ops_memcpy.c
@@ -49,9 +49,11 @@ static void process(const SwsOpExec *exec, const void *priv,
         uint8_t *out = exec->out[i];
         const int idx = p->index[i];
         const int bytes = x_end * exec->block_size_out[i];
-        const int use_loop = exec->out_stride[i] > bytes + SWS_MAX_PADDING;
+        const int use_loop = exec->out_stride[i] < 0 ||
+                             exec->out_stride[i] > bytes + SWS_MAX_PADDING;
+        const size_t span = (size_t) (lines - 1) * exec->out_stride[i] + bytes;
         if (idx < 0 && !use_loop) {
-            memset(out, p->clear_value[i], exec->out_stride[i] * lines);
+            memset(out, p->clear_value[i], span);
         } else if (idx < 0) {
             for (int y = y_start; y < y_end; y++) {
                 memset(out, p->clear_value[i], bytes);
@@ -61,7 +63,7 @@ static void process(const SwsOpExec *exec, const void *priv,
             av_assert1(exec->out_stride[i] == exec->in_stride[idx]);
             continue; /* plane was already ref'd */
         } else if (exec->out_stride[i] == exec->in_stride[idx] && !use_loop) {
-            memcpy(out, exec->in[idx], exec->out_stride[i] * lines);
+            memcpy(out, exec->in[idx], span);
         } else {
             const uint8_t *in = exec->in[idx];
             for (int y = y_start; y < y_end; y++) {
-- 
2.54.0


>From d39a02f73241ce463084387e2d47716a440ee173 Mon Sep 17 00:00:00 2001
From: Niklas Haas <[email protected]>
Date: Thu, 22 Oct 2026 20:33:07 +0200
Subject: [PATCH 4/7] swscale/tests/swscale: allow testing negative linesizes

A negative -align_src / -align_dst value now allocates the respective
buffers vertically flipped, with negative linesizes.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Signed-off-by: Niklas Haas <[email protected]>
---
 libswscale/tests/swscale.c | 33 ++++++++++++++++++++++++++++-----
 1 file changed, 28 insertions(+), 5 deletions(-)

diff --git a/libswscale/tests/swscale.c b/libswscale/tests/swscale.c
index 70ea5de2e18..dfb25eb924f 100644
--- a/libswscale/tests/swscale.c
+++ b/libswscale/tests/swscale.c
@@ -235,6 +235,25 @@ static void unref_buffers(AVFrame *frame)
     memset(frame->linesize, 0, sizeof(frame->linesize));
 }
 
+/* A negative alignment allocates a vertically flipped (negative stride) frame 
*/
+static int get_buffer(AVFrame *frame, int align)
+{
+    const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(frame->format);
+    int ret = av_frame_get_buffer(frame, FFABS(align));
+    if (ret < 0 || align >= 0)
+        return ret;
+
+    for (int p = 0; p < av_pix_fmt_count_planes(frame->format); p++) {
+        const int is_chroma = p == 1 || p == 2;
+        const int h = is_chroma ? AV_CEIL_RSHIFT(frame->height, 
desc->log2_chroma_h)
+                                : frame->height;
+        frame->data[p] += (h - 1) * frame->linesize[p];
+        frame->linesize[p] = -frame->linesize[p];
+    }
+
+    return 0;
+}
+
 static int checked_sws_scale_frame(SwsContext *c, AVFrame *dst, const AVFrame 
*src)
 {
     int ret = sws_scale_frame(c, dst, src);
@@ -267,7 +286,7 @@ static int scale_new(AVFrame *dst, const AVFrame *src,
     for (int i = 0; ret >= 0 && i < opts->iters; i++) {
         unref_buffers(dst);
         if (opts->align_dst) {
-            ret = av_frame_get_buffer(dst, opts->align_dst);
+            ret = get_buffer(dst, opts->align_dst);
             if (ret < 0)
                 return ret;
         }
@@ -306,7 +325,7 @@ static int scale_legacy(AVFrame *dst, const AVFrame *src,
     dst->width  = sws_legacy->dst_w;
     dst->height = sws_legacy->dst_h;
     dst->format = sws_legacy->dst_format;
-    ret = av_frame_get_buffer(dst, opts->align_dst);
+    ret = get_buffer(dst, opts->align_dst);
     if (ret < 0)
         goto error;
 
@@ -596,7 +615,7 @@ static int run_test(enum AVPixelFormat src_fmt, enum 
AVPixelFormat dst_fmt,
         if (ret < 0)
             goto error;
         if (opts->align_src) {
-            ret = av_frame_get_buffer(src, opts->align_src);
+            ret = get_buffer(src, opts->align_src);
             if (ret < 0) {
                 av_frame_free(&src);
                 goto error;
@@ -968,8 +987,10 @@ static int parse_options(int argc, char **argv, struct 
options *opts, FILE **fp)
                     "       Test with a specified scaler algorithm for chroma 
planes\n"
                     "   -align_src <alignment>\n"
                     "       If nonzero, allocate source buffers with a custom 
stride alignment\n"
+                    "       If negative, the buffers are also vertically 
flipped (negative stride)\n"
                     "   -align_dst <alignment>\n"
                     "       If nonzero, allocate destination buffers with a 
custom stride alignment\n"
+                    "       If negative, the buffers are also vertically 
flipped (negative stride)\n"
                     "   -api <new or legacy>\n"
                     "       Use selected swscale API for the main conversion 
(default: new)\n"
                     "   -hw <device>\n"
@@ -1062,13 +1083,15 @@ static int parse_options(int argc, char **argv, struct 
options *opts, FILE **fp)
             }
         } else if (!strcmp(argv[i], "-align_src")) {
             opts->align_src = atoi(argv[i + 1]);
-            if (opts->align_src < 0 || (opts->align_src & (opts->align_src - 
1))) {
+            const int align = FFABS(opts->align_src);
+            if (align & (align - 1)) {
                 fprintf(stderr, "invalid alignment %s\n", argv[i + 1]);
                 return -1;
             }
         } else if (!strcmp(argv[i], "-align_dst")) {
             opts->align_dst = atoi(argv[i + 1]);
-            if (opts->align_dst < 0 || (opts->align_dst & (opts->align_dst - 
1))) {
+            const int align = FFABS(opts->align_dst);
+            if (align & (align - 1)) {
                 fprintf(stderr, "invalid alignment %s\n", argv[i + 1]);
                 return -1;
             }
-- 
2.54.0


>From bf29d5b0fa2daa67041112f9d0015eca6fe847fc Mon Sep 17 00:00:00 2001
From: Niklas Haas <[email protected]>
Date: Thu, 22 Oct 2026 20:42:01 +0200
Subject: [PATCH 5/7] swscale/x86/ops_int: fix over-write in SSE4 WRITE_NIBBLE

Without AVX2, a block only holds 8 bytes worth of nibbles, but the full
XMM register was stored, clobbering 8 bytes past the end of the block.
This corrupted the previous line for negative linesizes.

Signed-off-by: Niklas Haas <[email protected]>
---
 libswscale/x86/ops_int.asm | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/libswscale/x86/ops_int.asm b/libswscale/x86/ops_int.asm
index 6f49ffeafea..692a3627ac6 100644
--- a/libswscale/x86/ops_int.asm
+++ b/libswscale/x86/ops_int.asm
@@ -134,9 +134,12 @@ assert COMPS == 1
 %if cpuflag(avx2)
         vpermq mx, mx, q3120
 IF V2,  vpermq mx2, mx2, q3120
-%endif
         movu [out0q], xmx
 IF V2,  movu [out0q + (mmsize >> 1)], xmx2
+%else
+        movq [out0q], mx
+IF V2,  movq [out0q + (mmsize >> 1)], mx2
+%endif
         add out0q, BLOCK_WIDTH >> 1
         RET
 %endmacro
-- 
2.54.0


>From a016bb02ab1d799f99422da013cf3623b0d2dc33 Mon Sep 17 00:00:00 2001
From: Niklas Haas <[email protected]>
Date: Thu, 22 Oct 2026 21:05:07 +0200
Subject: [PATCH 6/7] swscale/x86/ops_int: fix over-read in SSE4 READ_BIT

A block only covers 2 bytes of input, but movd loaded 4.

Signed-off-by: Niklas Haas <[email protected]>
---
 libswscale/x86/ops_int.asm | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libswscale/x86/ops_int.asm b/libswscale/x86/ops_int.asm
index 692a3627ac6..22540d4ce7e 100644
--- a/libswscale/x86/ops_int.asm
+++ b/libswscale/x86/ops_int.asm
@@ -150,8 +150,8 @@ assert COMPS == 1
         vpbroadcastd mx,  [in0q]
 IF V2,  vpbroadcastd mx2, [in0q + 4]
 %else
-        movd mx, [in0q]
-IF V2,  movd mx2, [in0q + 2]
+        pinsrw mx, [in0q], 0
+IF V2,  pinsrw mx2, [in0q + 2], 0
 %endif
         mova m8, [bits_shuf]
         VBROADCASTI128 m9,  [bits_mask]
-- 
2.54.0


>From 929e9c6a85b8c60e6244cb9a1a5b83d8c5201a03 Mon Sep 17 00:00:00 2001
From: Niklas Haas <[email protected]>
Date: Thu, 22 Oct 2026 20:43:58 +0200
Subject: [PATCH 7/7] checkasm/sw_ops: check for undeclared over-write

Use checkasm's own BUF_RECT() and padded buffer checking to get this
for almost free. The one major issue is that check_*_padded() assumes the
padding is a power of two alignment, which is not an assumption made by
libswscale.

Fix this by explicitly copying over the declared number of over-write bytes
from the reference buffer, before doing the check.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Signed-off-by: Niklas Haas <[email protected]>
---
 tests/checkasm/sw_ops.c | 54 ++++++++++++++++++++++++++---------------
 1 file changed, 34 insertions(+), 20 deletions(-)

diff --git a/tests/checkasm/sw_ops.c b/tests/checkasm/sw_ops.c
index 39f05dd03ad..0d17d8bd7df 100644
--- a/tests/checkasm/sw_ops.c
+++ b/tests/checkasm/sw_ops.c
@@ -158,8 +158,9 @@ static void check_compiled(const Test *test,
 
     static DECLARE_ALIGNED_64(char, src0)[NB_PLANES][LINES][PIXELS * 
sizeof(uint32_t[4])];
     static DECLARE_ALIGNED_64(char, src1)[NB_PLANES][LINES][PIXELS * 
sizeof(uint32_t[4])];
-    static DECLARE_ALIGNED_64(char, dst0)[NB_PLANES][LINES][PIXELS * 
sizeof(uint32_t[4])];
-    static DECLARE_ALIGNED_64(char, dst1)[NB_PLANES][LINES][PIXELS * 
sizeof(uint32_t[4])];
+    /* All output planes are stacked vertically in a single padded buffer */
+    static BUF_RECT(uint8_t, dst0, PIXELS * sizeof(uint32_t[4]), NB_PLANES * 
LINES);
+    static BUF_RECT(uint8_t, dst1, PIXELS * sizeof(uint32_t[4]), NB_PLANES * 
LINES);
 
     av_assert0(PIXELS % comp_new->block_size == 0);
     for (int p = 0; p < NB_PLANES; p++) {
@@ -186,8 +187,8 @@ static void check_compiled(const Test *test,
     }
 
     memcpy(src1, src0, sizeof(src0));
-    memset(dst0, 0, sizeof(dst0));
-    memset(dst1, 0, sizeof(dst1));
+    CLEAR_BUF_RECT(dst0);
+    CLEAR_BUF_RECT(dst1);
 
     const int read_size  = PIXELS * test->pixel_bits_in  >> 3;
     const int write_size = PIXELS * test->pixel_bits_out >> 3;
@@ -197,7 +198,7 @@ static void check_compiled(const Test *test,
     exec.height = exec.slice_h = LINES;
     for (int i = 0; i < NB_PLANES; i++) {
         exec.in_stride[i]  = sizeof(src0[i][0]);
-        exec.out_stride[i] = sizeof(dst0[i][0]);
+        exec.out_stride[i] = dst0_stride;
         exec.in_bump[i]  = exec.in_stride[i]  - read_size;
         exec.out_bump[i] = exec.out_stride[i] - write_size;
     }
@@ -228,7 +229,7 @@ static void check_compiled(const Test *test,
 
     for (int i = 0; i < NB_PLANES; i++) {
         exec.in[i]  = (void *) src0[i];
-        exec.out[i] = (void *) dst0[i];
+        exec.out[i] = dst0 + i * LINES * dst0_stride;
         exec.block_size_in[i]  = comp_ref->block_size * test->pixel_bits_in  
>> 3;
         exec.block_size_out[i] = comp_ref->block_size * test->pixel_bits_out 
>> 3;
     }
@@ -236,7 +237,7 @@ static void check_compiled(const Test *test,
 
     for (int i = 0; i < NB_PLANES; i++) {
         exec.in[i]  = (void *) src1[i];
-        exec.out[i] = (void *) dst1[i];
+        exec.out[i] = dst1 + i * LINES * dst1_stride;
         exec.block_size_in[i]  = comp_new->block_size * test->pixel_bits_in  
>> 3;
         exec.block_size_out[i] = comp_new->block_size * test->pixel_bits_out 
>> 3;
     }
@@ -246,28 +247,41 @@ static void check_compiled(const Test *test,
         if (!SWS_COMP_TEST(test->planes_out, i))
             continue;
 
+        /* checkasm_check_padded() assumes a power of two alignment, but our
+         * overwrite may be an arbitrary number of bytes. Smooth out the
+         * difference by manually copying over the padding from the reference
+         * to the output buffer, and extending the checked padding past it. */
+        const int elem_size = ff_sws_pixel_type_size(test->type_out);
+        const int over_write = comp_new->over_write[i];
+        const int padding = (over_write + elem_size - 1) / elem_size + 8;
+        const int w = write_size / elem_size;
+        const uint8_t *out_ref = dst0 + i * LINES * dst0_stride;
+        uint8_t *out_new = exec.out[i];
+        for (int y = 0; y < LINES; y++) {
+            memcpy(&out_new[y * dst1_stride + write_size],
+                   &out_ref[y * dst0_stride + write_size], over_write);
+        }
+
         const char *desc = FMT("%s[%d]", test->name, i);
-        const int stride = sizeof(dst0[i][0]);
         switch (test->type_out) {
         case SWS_PIXEL_U8:
-            checkasm_check(uint8_t, (void *) dst0[i], stride,
-                                    (void *) dst1[i], stride,
-                                    write_size, LINES, desc);
+            checkasm_check_padded(uint8_t, out_ref, dst0_stride, out_new, 
dst1_stride,
+                                  w, LINES, desc, 1, 0, padding);
             break;
         case SWS_PIXEL_U16:
-            checkasm_check(uint16_t, (void *) dst0[i], stride,
-                                     (void *) dst1[i], stride,
-                                     write_size >> 1, LINES, desc);
+            checkasm_check_padded(uint16_t, (void *) out_ref, dst0_stride,
+                                            (void *) out_new, dst1_stride,
+                                            w, LINES, desc, 1, 0, padding);
             break;
         case SWS_PIXEL_U32:
-            checkasm_check(uint32_t, (void *) dst0[i], stride,
-                                     (void *) dst1[i], stride,
-                                     write_size >> 2, LINES, desc);
+            checkasm_check_padded(uint32_t, (void *) out_ref, dst0_stride,
+                                            (void *) out_new, dst1_stride,
+                                            w, LINES, desc, 1, 0, padding);
             break;
         case SWS_PIXEL_F32:
-            checkasm_check(float_ulp, (void *) dst0[i], stride,
-                                      (void *) dst1[i], stride,
-                                      write_size >> 2, LINES, desc, 0);
+            checkasm_check_padded(float_ulp, (void *) out_ref, dst0_stride,
+                                             (void *) out_new, dst1_stride,
+                                             w, LINES, desc, 0, 1, 0, padding);
             break;
         }
     }
-- 
2.54.0

_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to