Commit ff22978529 for ffmpeg
commit ff22978529e6219f65fbc5984cda2f0ee7ce5427
Author: DROOdotFOO <drew@axol.io>
Date: Thu Jun 11 01:23:38 2026 +0200
avfilter/aarch64: NEON threshold filter
depth==8 routes to threshold8_neon (16 bytes/chunk); depth > 8 to
threshold16_neon (8 shorts/chunk, covering 9/10/12/14/16). C is not
auto-vectorized: four independent input streams defeat clang's
vectorizer. Per chunk the NEON kernel is cmhs+bsl.
checkasm --bench, Apple M1 (clang), speedup vs C:
threshold8 15.0x
threshold10 8.1x
threshold12 8.2x
threshold16 8.2x
Signed-off-by: DROOdotFOO <drew@axol.io>
diff --git a/libavfilter/aarch64/Makefile b/libavfilter/aarch64/Makefile
index c7b7e18467..d09f7e4080 100644
--- a/libavfilter/aarch64/Makefile
+++ b/libavfilter/aarch64/Makefile
@@ -1,7 +1,9 @@
OBJS-$(CONFIG_BWDIF_FILTER) += aarch64/vf_bwdif_init_aarch64.o
OBJS-$(CONFIG_COLORDETECT_FILTER) += aarch64/vf_colordetect_init.o
OBJS-$(CONFIG_NLMEANS_FILTER) += aarch64/vf_nlmeans_init.o
+OBJS-$(CONFIG_THRESHOLD_FILTER) += aarch64/vf_threshold_init.o
NEON-OBJS-$(CONFIG_BWDIF_FILTER) += aarch64/vf_bwdif_neon.o
NEON-OBJS-$(CONFIG_COLORDETECT_FILTER) += aarch64/vf_colordetect_neon.o
NEON-OBJS-$(CONFIG_NLMEANS_FILTER) += aarch64/vf_nlmeans_neon.o
+NEON-OBJS-$(CONFIG_THRESHOLD_FILTER) += aarch64/vf_threshold_neon.o
diff --git a/libavfilter/aarch64/vf_threshold_init.c b/libavfilter/aarch64/vf_threshold_init.c
new file mode 100644
index 0000000000..9b14d644a9
--- /dev/null
+++ b/libavfilter/aarch64/vf_threshold_init.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2026 DROOdotFOO <drew@axol.io>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libavutil/attributes.h"
+#include "libavutil/aarch64/cpu.h"
+#include "libavfilter/threshold.h"
+
+void ff_threshold8_neon(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);
+
+void ff_threshold16_neon(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);
+
+av_cold void ff_threshold_init_aarch64(ThresholdContext *s)
+{
+ int cpu_flags = av_get_cpu_flags();
+
+ if (have_neon(cpu_flags)) {
+ if (s->depth == 8)
+ s->threshold = ff_threshold8_neon;
+ else
+ s->threshold = ff_threshold16_neon;
+ }
+}
diff --git a/libavfilter/aarch64/vf_threshold_neon.S b/libavfilter/aarch64/vf_threshold_neon.S
new file mode 100644
index 0000000000..415f3974b9
--- /dev/null
+++ b/libavfilter/aarch64/vf_threshold_neon.S
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2026 DROOdotFOO <drew@axol.io>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libavutil/aarch64/asm.S"
+
+// Apple packs ints to 4 bytes on the stack; AAPCS-64 pads to 8.
+#ifdef __APPLE__
+.set SP_INT, 4
+#else
+.set SP_INT, 8
+#endif
+
+.macro THRESHOLD bits, vecsz, shape, ldop, stop, step
+function ff_threshold\bits\()_neon, export=1
+ stp x19, x20, [sp, #-16]!
+ ldp x8, x9, [sp, #16] // slinesize, olinesize
+ ldr w10, [sp, #32] // w
+ ldr w11, [sp, #32+SP_INT] // h
+ cmp w11, #0
+ b.le 9f
+ cmp w10, #0
+ b.le 9f
+1:
+ mov x12, x0
+ mov x13, x1
+ mov x14, x2
+ mov x15, x3
+ mov x16, x4
+ mov w17, w10
+2:
+ cmp w17, #(2*\vecsz)
+ b.lt 3f
+ ld1 {v0.16b, v1.16b}, [x12], #32
+ ld1 {v2.16b, v3.16b}, [x13], #32
+ ld1 {v4.16b, v5.16b}, [x14], #32
+ ld1 {v6.16b, v7.16b}, [x15], #32
+ cmhs v16.\shape, v2.\shape, v0.\shape // thr >= in
+ cmhs v17.\shape, v3.\shape, v1.\shape
+ bsl v16.16b, v4.16b, v6.16b // mask ? min : max
+ bsl v17.16b, v5.16b, v7.16b
+ st1 {v16.16b, v17.16b}, [x16], #32
+ sub w17, w17, #(2*\vecsz)
+ b 2b
+3:
+ cmp w17, #\vecsz
+ b.lt 4f
+ ld1 {v0.16b}, [x12], #16
+ ld1 {v1.16b}, [x13], #16
+ ld1 {v2.16b}, [x14], #16
+ ld1 {v3.16b}, [x15], #16
+ cmhs v4.\shape, v1.\shape, v0.\shape // thr >= in
+ bsl v4.16b, v2.16b, v3.16b // mask ? min : max
+ st1 {v4.16b}, [x16], #16
+ sub w17, w17, #\vecsz
+4:
+ cbz w17, 6f
+5:
+ \ldop w19, [x12], #\step
+ \ldop w20, [x13], #\step
+ cmp w19, w20
+ \ldop w19, [x14], #\step
+ \ldop w20, [x15], #\step
+ csel w19, w19, w20, ls
+ \stop w19, [x16], #\step
+ subs w17, w17, #1
+ b.gt 5b
+6:
+ add x0, x0, x5
+ add x1, x1, x6
+ add x2, x2, x7
+ add x3, x3, x8
+ add x4, x4, x9
+ subs w11, w11, #1
+ b.gt 1b
+9:
+ ldp x19, x20, [sp], #16
+ ret
+endfunc
+.endm
+
+THRESHOLD 8, 16, 16b, ldrb, strb, 1
+THRESHOLD 16, 8, 8h, ldrh, strh, 2
diff --git a/libavfilter/threshold.h b/libavfilter/threshold.h
index 8b55ad6ba1..1efdc9d5e9 100644
--- a/libavfilter/threshold.h
+++ b/libavfilter/threshold.h
@@ -47,5 +47,6 @@ typedef struct ThresholdContext {
} ThresholdContext;
void ff_threshold_init_x86(ThresholdContext *s);
+void ff_threshold_init_aarch64(ThresholdContext *s);
#endif /* AVFILTER_THRESHOLD_H */
diff --git a/libavfilter/vf_threshold_init.h b/libavfilter/vf_threshold_init.h
index fb319c6cf8..87e2ef20f9 100644
--- a/libavfilter/vf_threshold_init.h
+++ b/libavfilter/vf_threshold_init.h
@@ -86,6 +86,8 @@ av_unused static void ff_threshold_init(ThresholdContext *s)
#if ARCH_X86 && HAVE_X86ASM
ff_threshold_init_x86(s);
+#elif ARCH_AARCH64
+ ff_threshold_init_aarch64(s);
#endif
}