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]
