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");
}