PR #24350 opened by mkver URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24350 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24350.patch
>From d03996739ccf845324cd3ab1a25a36e04abad4d8 Mon Sep 17 00:00:00 2001 From: Andreas Rheinhardt <[email protected]> Date: Tue, 1 Sep 2026 16:06:57 +0200 Subject: [PATCH 1/2] avfilter/vf_colordetectdsp: Don't duplicate C functions They are currently inlined into the x86 assembly functions as fallback. Signed-off-by: Andreas Rheinhardt <[email protected]> --- libavfilter/Makefile | 2 +- libavfilter/vf_colordetectdsp.h | 166 +++++--------------------------- 2 files changed, 26 insertions(+), 142 deletions(-) diff --git a/libavfilter/Makefile b/libavfilter/Makefile index ceea328e67..9365e6d996 100644 --- a/libavfilter/Makefile +++ b/libavfilter/Makefile @@ -239,7 +239,7 @@ OBJS-$(CONFIG_COLORBALANCE_FILTER) += vf_colorbalance.o OBJS-$(CONFIG_COLORCHANNELMIXER_FILTER) += vf_colorchannelmixer.o OBJS-$(CONFIG_COLORCONTRAST_FILTER) += vf_colorcontrast.o OBJS-$(CONFIG_COLORCORRECT_FILTER) += vf_colorcorrect.o -OBJS-$(CONFIG_COLORDETECT_FILTER) += vf_colordetect.o +OBJS-$(CONFIG_COLORDETECT_FILTER) += vf_colordetect.o vf_colordetectdsp.o OBJS-$(CONFIG_COLORIZE_FILTER) += vf_colorize.o OBJS-$(CONFIG_COLORKEY_FILTER) += vf_colorkey.o OBJS-$(CONFIG_COLORKEY_OPENCL_FILTER) += vf_colorkey_opencl.o opencl.o \ diff --git a/libavfilter/vf_colordetectdsp.h b/libavfilter/vf_colordetectdsp.h index ef81559a6d..662308020a 100644 --- a/libavfilter/vf_colordetectdsp.h +++ b/libavfilter/vf_colordetectdsp.h @@ -25,7 +25,7 @@ #include "config.h" #include "libavutil/attributes.h" -#include "libavutil/avassert.h" +#include "libavutil/attributes_internal.h" #include "libavutil/pixfmt.h" enum FFAlphaDetect { @@ -49,151 +49,35 @@ typedef struct FFColorDetectDSPContext { int alpha_max, int mpeg_range, int offset); } FFColorDetectDSPContext; +FF_VISIBILITY_PUSH_HIDDEN void ff_color_detect_dsp_init_aarch64(FFColorDetectDSPContext *dsp, int depth, enum AVColorRange color_range); 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); -} - -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; - } - - return 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); -} - -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; -} - -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; -} +int ff_detect_range_c(const uint8_t *data, ptrdiff_t stride, + ptrdiff_t width, ptrdiff_t height, + int mpeg_min, int mpeg_max); +int ff_detect_range16_c(const uint8_t *data, ptrdiff_t stride, + ptrdiff_t width, ptrdiff_t height, + int mpeg_min, int mpeg_max); +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); +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); +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); +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); +FF_VISIBILITY_POP_HIDDEN static av_cold inline void ff_color_detect_dsp_init(FFColorDetectDSPContext *dsp, int depth, int offset, -- 2.52.0 >From 0bfc2d71677aea2f68561ed05e0734e17fddc0ac Mon Sep 17 00:00:00 2001 From: Andreas Rheinhardt <[email protected]> Date: Tue, 1 Sep 2026 22:29:24 +0200 Subject: [PATCH 2/2] avfilter/vf_colordetect: Add width parameter to init This allows to only use certain functions using wide registers if there is enough work to do and if one can even read a whole register wide without overreading. Signed-off-by: Andreas Rheinhardt <[email protected]> --- libavfilter/vf_colordetect.c | 2 +- libavfilter/vf_colordetectdsp.h | 6 ++-- libavfilter/x86/vf_colordetect_init.c | 48 ++++++++++++--------------- tests/checkasm/vf_colordetect.c | 6 ++-- 4 files changed, 30 insertions(+), 32 deletions(-) diff --git a/libavfilter/vf_colordetect.c b/libavfilter/vf_colordetect.c index f98905b6c6..13a5e9084a 100644 --- a/libavfilter/vf_colordetect.c +++ b/libavfilter/vf_colordetect.c @@ -163,7 +163,7 @@ static int config_input(AVFilterLink *inlink) atomic_init(&s->detected_alpha, FF_ALPHA_NONE); } - ff_color_detect_dsp_init(&s->dsp, depth, s->offset, inlink->color_range); + ff_color_detect_dsp_init(&s->dsp, depth, s->offset, inlink->w, inlink->color_range); return 0; } diff --git a/libavfilter/vf_colordetectdsp.h b/libavfilter/vf_colordetectdsp.h index 662308020a..6befb2afd9 100644 --- a/libavfilter/vf_colordetectdsp.h +++ b/libavfilter/vf_colordetectdsp.h @@ -53,7 +53,7 @@ FF_VISIBILITY_PUSH_HIDDEN void ff_color_detect_dsp_init_aarch64(FFColorDetectDSPContext *dsp, int depth, enum AVColorRange color_range); void ff_color_detect_dsp_init_x86(FFColorDetectDSPContext *dsp, int depth, - int offset, enum AVColorRange color_range); + int offset, int width, enum AVColorRange color_range); int ff_detect_range_c(const uint8_t *data, ptrdiff_t stride, ptrdiff_t width, ptrdiff_t height, @@ -81,7 +81,7 @@ FF_VISIBILITY_POP_HIDDEN static av_cold inline void ff_color_detect_dsp_init(FFColorDetectDSPContext *dsp, int depth, int offset, - enum AVColorRange color_range) + int width, enum AVColorRange color_range) { dsp->detect_range = depth > 8 ? ff_detect_range16_c : ff_detect_range_c; if (color_range == AVCOL_RANGE_JPEG) { @@ -93,7 +93,7 @@ ff_color_detect_dsp_init(FFColorDetectDSPContext *dsp, int depth, int offset, #if ARCH_AARCH64 ff_color_detect_dsp_init_aarch64(dsp, depth, color_range); #elif ARCH_X86 && HAVE_X86ASM - ff_color_detect_dsp_init_x86(dsp, depth, offset, color_range); + ff_color_detect_dsp_init_x86(dsp, depth, offset, width, color_range); #endif } diff --git a/libavfilter/x86/vf_colordetect_init.c b/libavfilter/x86/vf_colordetect_init.c index 7c39892700..afd6a6c524 100644 --- a/libavfilter/x86/vf_colordetect_init.c +++ b/libavfilter/x86/vf_colordetect_init.c @@ -22,7 +22,7 @@ #include "libavutil/x86/cpu.h" #include "libavfilter/vf_colordetectdsp.h" -#define DETECT_RANGE_FUNC(FUNC_NAME, ASM_FUNC_NAME, C_FUNC_NAME, SHIFT, MMSIZE) \ +#define DETECT_RANGE_FUNC(FUNC_NAME, ASM_FUNC_NAME, SHIFT, MMSIZE) \ int ASM_FUNC_NAME(const uint8_t *src, ptrdiff_t stride, \ ptrdiff_t width, ptrdiff_t height, int min, int max); \ \ @@ -32,8 +32,6 @@ static int FUNC_NAME(const uint8_t *src, ptrdiff_t stride, ptrdiff_t total = width << SHIFT; \ ptrdiff_t bytes = total & ~(MMSIZE - 1); \ int ret; \ - if (!bytes) \ - return C_FUNC_NAME(src, stride, width, height, min, max); \ \ ret = ASM_FUNC_NAME(src, stride, bytes, height, min, max); \ if (ret || bytes == total) \ @@ -43,7 +41,7 @@ static int FUNC_NAME(const uint8_t *src, ptrdiff_t stride, height, min, max); \ } -#define DETECT_ALPHA_FUNC(FUNC_NAME, ASM_FUNC_NAME, C_FUNC_NAME, SHIFT, MMSIZE) \ +#define DETECT_ALPHA_FUNC(FUNC_NAME, ASM_FUNC_NAME, SHIFT, MMSIZE) \ int ASM_FUNC_NAME(const uint8_t *color, ptrdiff_t color_stride, \ const uint8_t *alpha, ptrdiff_t alpha_stride, \ ptrdiff_t width, ptrdiff_t height, int p, int q, int k); \ @@ -55,9 +53,6 @@ static int FUNC_NAME(const uint8_t *color, ptrdiff_t color_stride, ptrdiff_t total = width << SHIFT; \ ptrdiff_t bytes = total & ~(MMSIZE - 1); \ int ret; \ - if (!bytes) \ - return C_FUNC_NAME(color, color_stride, alpha, alpha_stride, \ - width, height, p, q, k); \ \ ret = ASM_FUNC_NAME(color, color_stride, alpha, alpha_stride, \ bytes, height, p, q, k); \ @@ -70,32 +65,33 @@ static int FUNC_NAME(const uint8_t *color, ptrdiff_t color_stride, } #if HAVE_AVX512ICL_EXTERNAL -DETECT_RANGE_FUNC(detect_range_avx512icl, ff_detect_rangeb_avx512icl, ff_detect_range_c, 0, 64) -DETECT_RANGE_FUNC(detect_range16_avx512icl, ff_detect_rangew_avx512icl, ff_detect_range16_c, 1, 64) -DETECT_ALPHA_FUNC(detect_alpha_full_avx512icl, ff_detect_alphab_full_avx512icl, ff_detect_alpha_full_c, 0, 64) -DETECT_ALPHA_FUNC(detect_alpha16_full_avx512icl, ff_detect_alphaw_full_avx512icl, ff_detect_alpha16_full_c, 1, 64) -DETECT_ALPHA_FUNC(detect_alpha_full_off_avx512icl, ff_detect_alphab_full_off_avx512icl, ff_detect_alpha_full_c, 0, 64) -DETECT_ALPHA_FUNC(detect_alpha16_full_off_avx512icl, ff_detect_alphaw_full_off_avx512icl, ff_detect_alpha16_full_c, 1, 64) -DETECT_ALPHA_FUNC(detect_alpha_limited_avx512icl, ff_detect_alphab_limited_avx512icl, ff_detect_alpha_limited_c, 0, 64) -DETECT_ALPHA_FUNC(detect_alpha16_limited_avx512icl, ff_detect_alphaw_limited_avx512icl, ff_detect_alpha16_limited_c, 1, 64) +DETECT_RANGE_FUNC(detect_range_avx512icl, ff_detect_rangeb_avx512icl, 0, 64) +DETECT_RANGE_FUNC(detect_range16_avx512icl, ff_detect_rangew_avx512icl, 1, 64) +DETECT_ALPHA_FUNC(detect_alpha_full_avx512icl, ff_detect_alphab_full_avx512icl, 0, 64) +DETECT_ALPHA_FUNC(detect_alpha16_full_avx512icl, ff_detect_alphaw_full_avx512icl, 1, 64) +DETECT_ALPHA_FUNC(detect_alpha_full_off_avx512icl, ff_detect_alphab_full_off_avx512icl, 0, 64) +DETECT_ALPHA_FUNC(detect_alpha16_full_off_avx512icl, ff_detect_alphaw_full_off_avx512icl, 1, 64) +DETECT_ALPHA_FUNC(detect_alpha_limited_avx512icl, ff_detect_alphab_limited_avx512icl, 0, 64) +DETECT_ALPHA_FUNC(detect_alpha16_limited_avx512icl, ff_detect_alphaw_limited_avx512icl, 1, 64) #endif #if HAVE_AVX2_EXTERNAL -DETECT_RANGE_FUNC(detect_range_avx2, ff_detect_rangeb_avx2, ff_detect_range_c, 0, 32) -DETECT_RANGE_FUNC(detect_range16_avx2, ff_detect_rangew_avx2, ff_detect_range16_c, 1, 32) -DETECT_ALPHA_FUNC(detect_alpha_full_avx2, ff_detect_alphab_full_avx2, ff_detect_alpha_full_c, 0, 32) -DETECT_ALPHA_FUNC(detect_alpha16_full_avx2, ff_detect_alphaw_full_avx2, ff_detect_alpha16_full_c, 1, 32) -DETECT_ALPHA_FUNC(detect_alpha_full_off_avx2, ff_detect_alphab_full_off_avx2, ff_detect_alpha_full_c, 0, 32) -DETECT_ALPHA_FUNC(detect_alpha16_full_off_avx2, ff_detect_alphaw_full_off_avx2, ff_detect_alpha16_full_c, 1, 32) -DETECT_ALPHA_FUNC(detect_alpha_limited_avx2, ff_detect_alphab_limited_avx2, ff_detect_alpha_limited_c, 0, 32) -DETECT_ALPHA_FUNC(detect_alpha16_limited_avx2, ff_detect_alphaw_limited_avx2, ff_detect_alpha16_limited_c, 1, 32) +DETECT_RANGE_FUNC(detect_range_avx2, ff_detect_rangeb_avx2, 0, 32) +DETECT_RANGE_FUNC(detect_range16_avx2, ff_detect_rangew_avx2, 1, 32) +DETECT_ALPHA_FUNC(detect_alpha_full_avx2, ff_detect_alphab_full_avx2, 0, 32) +DETECT_ALPHA_FUNC(detect_alpha16_full_avx2, ff_detect_alphaw_full_avx2, 1, 32) +DETECT_ALPHA_FUNC(detect_alpha_full_off_avx2, ff_detect_alphab_full_off_avx2, 0, 32) +DETECT_ALPHA_FUNC(detect_alpha16_full_off_avx2, ff_detect_alphaw_full_off_avx2, 1, 32) +DETECT_ALPHA_FUNC(detect_alpha_limited_avx2, ff_detect_alphab_limited_avx2, 0, 32) +DETECT_ALPHA_FUNC(detect_alpha16_limited_avx2, ff_detect_alphaw_limited_avx2, 1, 32) #endif av_cold void ff_color_detect_dsp_init_x86(FFColorDetectDSPContext *dsp, int depth, - int offset, enum AVColorRange color_range) + int offset, int width, enum AVColorRange color_range) { + unsigned width_in_bytes = width * (depth > 8 ? 2 : 1); int cpu_flags = av_get_cpu_flags(); #if HAVE_AVX2_EXTERNAL - if (EXTERNAL_AVX2_FAST(cpu_flags)) { + if (width_in_bytes >= 32 && EXTERNAL_AVX2_FAST(cpu_flags)) { dsp->detect_range = depth > 8 ? detect_range16_avx2 : detect_range_avx2; if (color_range != AVCOL_RANGE_JPEG) { dsp->detect_alpha = depth > 8 ? detect_alpha16_limited_avx2 : detect_alpha_limited_avx2; @@ -107,7 +103,7 @@ av_cold void ff_color_detect_dsp_init_x86(FFColorDetectDSPContext *dsp, int dept } #endif #if HAVE_AVX512ICL_EXTERNAL - if (EXTERNAL_AVX512ICL(cpu_flags)) { + if (width_in_bytes >= 64 && EXTERNAL_AVX512ICL(cpu_flags)) { dsp->detect_range = depth > 8 ? detect_range16_avx512icl : detect_range_avx512icl; if (color_range != AVCOL_RANGE_JPEG) { dsp->detect_alpha = depth > 8 ? detect_alpha16_limited_avx512icl : detect_alpha_limited_avx512icl; diff --git a/tests/checkasm/vf_colordetect.c b/tests/checkasm/vf_colordetect.c index b033b1731f..d201daa9cd 100644 --- a/tests/checkasm/vf_colordetect.c +++ b/tests/checkasm/vf_colordetect.c @@ -32,7 +32,6 @@ static void check_range_detect(int depth) const int mpeg_max = 235 << (depth - 8); FFColorDetectDSPContext dsp = {0}; - ff_color_detect_dsp_init(&dsp, depth, 0, AVCOL_RANGE_UNSPECIFIED); declare_func(int, const uint8_t *, ptrdiff_t, ptrdiff_t, ptrdiff_t, int, int); @@ -54,6 +53,8 @@ static void check_range_detect(int depth) if (depth > 8) w /= 2; + ff_color_detect_dsp_init(&dsp, depth, 0, w, AVCOL_RANGE_UNSPECIFIED); + if (check_func(dsp.detect_range, "detect_range_%d", depth)) { /* Test increasing height, to ensure we hit the placed 0 eventually */ for (int h = 1; h <= HEIGHT; h++) { @@ -85,7 +86,6 @@ static void check_alpha_detect(int depth, enum AVColorRange range, int offset) } FFColorDetectDSPContext dsp = {0}; - ff_color_detect_dsp_init(&dsp, depth, offset, range); declare_func(int, const uint8_t *, ptrdiff_t, const uint8_t *, ptrdiff_t, ptrdiff_t, ptrdiff_t, int p, int q, int k); @@ -124,6 +124,8 @@ static void check_alpha_detect(int depth, enum AVColorRange range, int offset) if (depth > 8) w /= 2; + ff_color_detect_dsp_init(&dsp, depth, offset, w, range); + const char *name; if (range == AVCOL_RANGE_JPEG) name = offset ? "full_off" : "full"; -- 2.52.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
