This is an automated email from the git hooks/post-receive script.
Git pushed a commit to branch master
in repository ffmpeg.
The following commit(s) were added to refs/heads/master by this push:
new 17e6ed9dc0 avfilter/vf_colordetectdsp: rewrite C implementations as
macros
17e6ed9dc0 is described below
commit 17e6ed9dc0106fbf837bda5d675fae22360e6c3e
Author: Niklas Haas <[email protected]>
AuthorDate: Wed Sep 2 12:04:03 2026 +0200
Commit: Niklas Haas <[email protected]>
CommitDate: Tue Sep 15 13:12:45 2026 +0000
avfilter/vf_colordetectdsp: rewrite C implementations as macros
In the process, also add the range assumption and cast to the detect_alpha
intermediates, which seems to help codegen:
checkasm:
- CPU: AMD Ryzen 9 9950X3D 16-Core Processor (00B40F40)
- Timing source: x86 (rdtsc)
- Bench duration: 100000 µs per function (442374016 cycles)
- Random seed: 2809724650
Benchmark results: (old)
name cycles (vs ref)
detect_alpha_8_full_c: 7582.7
detect_alpha_8_full_off_c: 7587.4
detect_alpha_8_limited_c: 13306.7
detect_alpha_16_full_c: 3482.5
detect_alpha_16_full_off_c: 3480.4
detect_alpha_16_limited_c: 8055.1
detect_range_8_c: 1271.4
detect_range_16_c: 1213.0
Benchmark results: (new)
name cycles (vs ref)
detect_alpha_8_full_c: 4716.6
detect_alpha_8_full_off_c: 4715.4
detect_alpha_8_limited_c: 7943.2
detect_alpha_16_full_c: 2920.2
detect_alpha_16_full_off_c: 2918.9
detect_alpha_16_limited_c: 9952.0
detect_range_8_c: 1253.1
detect_range_16_c: 1194.8
The ~20% slowdown for detect_alpha_16_limited_c is because the previous
version of the code short-circuited this condition, which is faster when
the compiler is not able to vectorize the loop body and falls back to a pure
scalar loop.
However, I don't think optimizing around this is necessary as it's a pure
compiler optimization question. In particular, it actually _prevents_ better
compilers from being able to vectorize this in the future. (As an example,
doing the same short-circuiting for 8-bit would be a 2x regression on my
end)
People running into performance issues should just use the SIMD versions.
Sponsored-by: nxtedition AB
Signed-off-by: Niklas Haas <[email protected]>
---
libavfilter/vf_colordetectdsp.h | 216 ++++++++++++++++------------------------
1 file changed, 84 insertions(+), 132 deletions(-)
diff --git a/libavfilter/vf_colordetectdsp.h b/libavfilter/vf_colordetectdsp.h
index ef81559a6d..bec072e67d 100644
--- a/libavfilter/vf_colordetectdsp.h
+++ b/libavfilter/vf_colordetectdsp.h
@@ -54,146 +54,98 @@ void
ff_color_detect_dsp_init_aarch64(FFColorDetectDSPContext *dsp, int depth,
void ff_color_detect_dsp_init_x86(FFColorDetectDSPContext *dsp, int depth,
int offset, enum AVColorRange color_range);
-static inline int ff_detect_range_impl_c(const uint8_t *data, ptrdiff_t stride,
- ptrdiff_t width, ptrdiff_t height,
- uint8_t mpeg_min, uint8_t mpeg_max)
-{
- while (height--) {
- uint8_t cond = 0;
- for (int x = 0; x < width; x++) {
- const uint8_t val = data[x];
- cond |= val < mpeg_min || val > mpeg_max;
- }
- if (cond)
- return 1;
- data += stride;
- }
-
- return 0;
-}
-
-static inline int ff_detect_range_c(const uint8_t *data, ptrdiff_t stride,
- ptrdiff_t width, ptrdiff_t height,
- int mpeg_min, int mpeg_max)
-{
- av_assume(mpeg_min >= 0 && mpeg_min <= UINT8_MAX);
- av_assume(mpeg_max >= 0 && mpeg_max <= UINT8_MAX);
- return ff_detect_range_impl_c(data, stride, width, height, mpeg_min,
mpeg_max);
+#define DECL_DETECT_RANGE_IMPL(TYPE, NAME)
\
+static inline int NAME(const uint8_t* data, ptrdiff_t stride,
\
+ ptrdiff_t width, ptrdiff_t height,
\
+ int mpeg_min, int mpeg_max)
\
+{
\
+ const TYPE min = mpeg_min;
\
+ const TYPE max = mpeg_max;
\
+ av_assume(min == mpeg_min);
\
+ av_assume(max == mpeg_max);
\
+
\
+ while (height--) {
\
+ const TYPE *row = (const TYPE *) data;
\
+ uint8_t cond = 0;
\
+ for (int x = 0; x < width; x++) {
\
+ const TYPE val = row[x];
\
+ cond |= val < min || val > max;
\
+ }
\
+ if (cond)
\
+ return 1;
\
+ data += stride;
\
+ }
\
+
\
+ return 0;
\
}
-static inline int ff_detect_range16_impl_c(const uint8_t *data, ptrdiff_t
stride,
- ptrdiff_t width, ptrdiff_t height,
- uint16_t mpeg_min, uint16_t mpeg_max)
-{
- while (height--) {
- const uint16_t *data16 = (const uint16_t *) data;
- uint8_t cond = 0;
- for (int x = 0; x < width; x++) {
- const uint16_t val = data16[x];
- cond |= val < mpeg_min || val > mpeg_max;
- }
- if (cond)
- return 1;
- data += stride;
- }
+DECL_DETECT_RANGE_IMPL(uint8_t, ff_detect_range_c)
+DECL_DETECT_RANGE_IMPL(uint16_t, ff_detect_range16_c)
- return 0;
+#define DECL_DETECT_ALPHA_FULL_IMPL(TYPE, INTER, NAME)
\
+static inline int NAME(const uint8_t* color, ptrdiff_t color_stride,
\
+ const uint8_t* alpha, ptrdiff_t alpha_stride,
\
+ ptrdiff_t width, ptrdiff_t height, int alpha_max,
\
+ int mpeg_range, int offset)
\
+{
\
+ const TYPE max = alpha_max;
\
+ const INTER off = offset;
\
+ av_assume(max == alpha_max);
\
+ av_assume(off == offset);
\
+ (void) mpeg_range;
\
+
\
+ uint8_t transparent = 0;
\
+ while (height--) {
\
+ const TYPE *col = (const TYPE *) color;
\
+ const TYPE *alp = (const TYPE *) alpha;
\
+ uint8_t straight = 0;
\
+ for (int x = 0; x < width; x++) {
\
+ straight |= col[x] > alp[x] + off;
\
+ transparent |= alp[x] != max;
\
+ }
\
+ if (straight)
\
+ return FF_ALPHA_STRAIGHT;
\
+ color += color_stride;
\
+ alpha += alpha_stride;
\
+ }
\
+ return transparent ? FF_ALPHA_TRANSPARENT : 0;
\
}
-static inline int ff_detect_range16_c(const uint8_t *data, ptrdiff_t stride,
- ptrdiff_t width, ptrdiff_t height,
- int mpeg_min, int mpeg_max)
-{
- av_assume(mpeg_min >= 0 && mpeg_min <= UINT16_MAX);
- av_assume(mpeg_max >= 0 && mpeg_max <= UINT16_MAX);
- return ff_detect_range16_impl_c(data, stride, width, height, mpeg_min,
mpeg_max);
-}
+DECL_DETECT_ALPHA_FULL_IMPL(uint8_t, uint16_t, ff_detect_alpha_full_c)
+DECL_DETECT_ALPHA_FULL_IMPL(uint16_t, uint32_t, ff_detect_alpha16_full_c)
-static inline int
-ff_detect_alpha_full_c(const uint8_t *color, ptrdiff_t color_stride,
- const uint8_t *alpha, ptrdiff_t alpha_stride,
- ptrdiff_t width, ptrdiff_t height,
- int alpha_max, int mpeg_range, int offset)
-{
- uint8_t transparent = 0;
- while (height--) {
- uint8_t straight = 0;
- for (int x = 0; x < width; x++) {
- straight |= color[x] > alpha[x] + offset;
- transparent |= alpha[x] != alpha_max;
- }
- if (straight)
- return FF_ALPHA_STRAIGHT;
- color += color_stride;
- alpha += alpha_stride;
- }
- return transparent ? FF_ALPHA_TRANSPARENT : 0;
+#define DECL_DETECT_ALPHA_LIMITED_IMPL(TYPE, INTER, NAME)
\
+static inline int NAME(const uint8_t* color, ptrdiff_t color_stride,
\
+ const uint8_t* alpha, ptrdiff_t alpha_stride,
\
+ ptrdiff_t width, ptrdiff_t height, int alpha_max,
\
+ int mpeg_range, int offset)
\
+{
\
+ const TYPE max = alpha_max;
\
+ const INTER off = offset;
\
+ const INTER range = mpeg_range;
\
+ av_assume(max == alpha_max);
\
+ av_assume(off == offset);
\
+ av_assume(range == mpeg_range);
\
+
\
+ uint8_t transparent = 0;
\
+ while (height--) {
\
+ const TYPE *col = (const TYPE *) color;
\
+ const TYPE *alp = (const TYPE *) alpha;
\
+ uint8_t straight = 0;
\
+ for (int x = 0; x < width; x++) {
\
+ straight |= (INTER) max * col[x] - off > range * alp[x];
\
+ transparent |= alp[x] != max;
\
+ }
\
+ if (straight)
\
+ return FF_ALPHA_STRAIGHT;
\
+ color += color_stride;
\
+ alpha += alpha_stride;
\
+ }
\
+ return transparent ? FF_ALPHA_TRANSPARENT : 0;
\
}
-static inline int
-ff_detect_alpha_limited_c(const uint8_t *color, ptrdiff_t color_stride,
- const uint8_t *alpha, ptrdiff_t alpha_stride,
- ptrdiff_t width, ptrdiff_t height,
- int alpha_max, int mpeg_range, int offset)
-{
- uint8_t transparent = 0;
- while (height--) {
- uint8_t straight = 0;
- for (int x = 0; x < width; x++) {
- straight |= alpha_max * color[x] - offset > mpeg_range * alpha[x];
- transparent |= alpha[x] != alpha_max;
- }
- if (straight)
- return FF_ALPHA_STRAIGHT;
- color += color_stride;
- alpha += alpha_stride;
- }
- return transparent ? FF_ALPHA_TRANSPARENT : 0;
-}
-
-static inline int
-ff_detect_alpha16_full_c(const uint8_t *color, ptrdiff_t color_stride,
- const uint8_t *alpha, ptrdiff_t alpha_stride,
- ptrdiff_t width, ptrdiff_t height,
- int alpha_max, int mpeg_range, int offset)
-{
- uint8_t transparent = 0;
- while (height--) {
- const uint16_t *color16 = (const uint16_t *) color;
- const uint16_t *alpha16 = (const uint16_t *) alpha;
- uint8_t straight = 0;
- for (int x = 0; x < width; x++) {
- straight |= color16[x] > alpha16[x] + offset;
- transparent |= alpha16[x] != alpha_max;
- }
- if (straight)
- return FF_ALPHA_STRAIGHT;
- color += color_stride;
- alpha += alpha_stride;
- }
- return transparent ? FF_ALPHA_TRANSPARENT : 0;
-}
-
-static inline int
-ff_detect_alpha16_limited_c(const uint8_t *color, ptrdiff_t color_stride,
- const uint8_t *alpha, ptrdiff_t alpha_stride,
- ptrdiff_t width, ptrdiff_t height,
- int alpha_max, int mpeg_range, int offset)
-{
- uint8_t transparent = 0;
- while (height--) {
- const uint16_t *color16 = (const uint16_t *) color;
- const uint16_t *alpha16 = (const uint16_t *) alpha;
- for (int x = 0; x < width; x++) {
- if ((int64_t) alpha_max * color16[x] - offset > (int64_t)
mpeg_range * alpha16[x])
- return FF_ALPHA_STRAIGHT;
- transparent |= alpha16[x] != alpha_max;
- }
- color += color_stride;
- alpha += alpha_stride;
- }
- return transparent ? FF_ALPHA_TRANSPARENT : 0;
-}
+DECL_DETECT_ALPHA_LIMITED_IMPL(uint8_t, int32_t, ff_detect_alpha_limited_c)
+DECL_DETECT_ALPHA_LIMITED_IMPL(uint16_t, int64_t, ff_detect_alpha16_limited_c)
static av_cold inline void
ff_color_detect_dsp_init(FFColorDetectDSPContext *dsp, int depth, int offset,
--
To stop receiving notification emails like this one, please contact
[email protected].
_______________________________________________
ffmpeg-cvslog mailing list -- [email protected]
To unsubscribe send an email to [email protected]