This is an automated email from the git hooks/post-receive script. Git pushed a commit to branch master in repository ffmpeg.
commit 972c0cf91f4ff906a74b36639578443ee308d650 Author: Niklas Haas <[email protected]> AuthorDate: Mon Jun 1 17:17:35 2026 +0200 Commit: Niklas Haas <[email protected]> CommitDate: Wed Jun 3 21:39:55 2026 +0000 swscale: add new SwsContext.backends option This allows constraining the set of available backends. This serves as a better replacement for the "unstable" flag, which is a bit ambiguous. Allows users to, for example, opt into the memcpy or x86 backend, while excluding e.g. the upcoming JIT backends. Signed-off-by: Niklas Haas <[email protected]> --- doc/APIchanges | 3 +++ doc/scaler.texi | 41 +++++++++++++++++++++++++++++++++++++++++ libswscale/aarch64/ops.c | 1 + libswscale/graph.c | 12 ++++++++++-- libswscale/ops_backend.c | 1 + libswscale/ops_dispatch.c | 5 ++++- libswscale/ops_dispatch.h | 1 + libswscale/ops_memcpy.c | 1 + libswscale/options.c | 13 +++++++++++++ libswscale/swscale.h | 39 +++++++++++++++++++++++++++++++++++++-- libswscale/swscale_internal.h | 2 ++ libswscale/utils.c | 12 ++++++++++++ libswscale/version.h | 2 +- libswscale/vulkan/ops.c | 2 ++ libswscale/x86/ops.c | 1 + 15 files changed, 130 insertions(+), 6 deletions(-) diff --git a/doc/APIchanges b/doc/APIchanges index 58a9b483a6..2fab69f261 100644 --- a/doc/APIchanges +++ b/doc/APIchanges @@ -2,6 +2,9 @@ The last version increases of all libraries were on 2025-03-28 API changes, most recent first: +2026-06-xx - xxxxxxxxxx - lsws 9.8.100 - swscale.h + Add enum SwsBackend and SwsContext.backends + 2026-06-xx - xxxxxxxxxxx - lavu 60.32.100 - hwcontext_vulkan.h Add AVVulkanDeviceContext.queue_flags. diff --git a/doc/scaler.texi b/doc/scaler.texi index aecc3ad248..a66c8217f8 100644 --- a/doc/scaler.texi +++ b/doc/scaler.texi @@ -191,6 +191,47 @@ No blending @end table +@item sws_backends +Set the allowed swscale backends. This is a flags option, so multiple backends +may be combined. + +@table @samp +@item auto +Automatic selection. Equal to either @samp{stable} or @samp{all} depending on +whether or not the @samp{unstable} flag is set. This is the default value. + +@item stable +All stable backends. + +@item unstable +All unstable backends. + +@item all +All available backends. + +@item legacy +Legacy swscale code. + +@item c +Template-based reference code. + +@item memcpy +Fast path using libc @code{memcpy}. + +@item x86 +x86 SIMD kernels. + +@item aarch64 +AArch64 NEON kernels. + +@item spirv +Vulkan SPIR-V backend. + +@item glsl +Vulkan GLSL backend. + +@end table + @end table @c man end SCALER OPTIONS diff --git a/libswscale/aarch64/ops.c b/libswscale/aarch64/ops.c index 753aef51ae..4598a8db6b 100644 --- a/libswscale/aarch64/ops.c +++ b/libswscale/aarch64/ops.c @@ -254,6 +254,7 @@ error: /*********************************************************************/ const SwsOpBackend backend_aarch64 = { .name = "aarch64", + .flags = SWS_BACKEND_AARCH64, .compile = aarch64_compile, .hw_format = AV_PIX_FMT_NONE, }; diff --git a/libswscale/graph.c b/libswscale/graph.c index 2ee1bd84a2..37c11f9dd5 100644 --- a/libswscale/graph.c +++ b/libswscale/graph.c @@ -548,6 +548,9 @@ static int add_legacy_sws_pass(SwsGraph *graph, const SwsFormat *src, { int ret, warned = 0; SwsContext *const ctx = graph->ctx; + const SwsBackend backend = ff_sws_enabled_backends(ctx); + if (!(backend & SWS_BACKEND_LEGACY)) + return AVERROR(ENOTSUP); if (src->hw_format != AV_PIX_FMT_NONE || dst->hw_format != AV_PIX_FMT_NONE) return AVERROR(ENOTSUP); @@ -626,8 +629,12 @@ static int add_convert_pass(SwsGraph *graph, const SwsFormat *src, SwsContext *ctx = graph->ctx; int ret = AVERROR(ENOTSUP); - /* Mark the entire new ops infrastructure as experimental for now */ - if (!(ctx->flags & SWS_UNSTABLE)) + /* Preemptively skip the ops list generation if the backend was + * constrained to the legacy implementation only. This would + * normally also fail in ff_sws_compile_pass() with the same + * error, but this way saves a bit of unnecessary overhead */ + const SwsBackend backends = ff_sws_enabled_backends(ctx); + if (backends == SWS_BACKEND_LEGACY) goto fail; SwsOpList *ops; @@ -908,6 +915,7 @@ static int opts_equal(const SwsContext *c1, const SwsContext *c2) c1->intent == c2->intent && c1->scaler == c2->scaler && c1->scaler_sub == c2->scaler_sub && + c1->backends == c2->backends && !memcmp(c1->scaler_params, c2->scaler_params, sizeof(c1->scaler_params)); } diff --git a/libswscale/ops_backend.c b/libswscale/ops_backend.c index 07919539e5..254814ee37 100644 --- a/libswscale/ops_backend.c +++ b/libswscale/ops_backend.c @@ -111,6 +111,7 @@ static int compile(SwsContext *ctx, SwsOpList *ops, SwsCompiledOp *out) const SwsOpBackend backend_c = { .name = "c", + .flags = SWS_BACKEND_C, .compile = compile, .hw_format = AV_PIX_FMT_NONE, }; diff --git a/libswscale/ops_dispatch.c b/libswscale/ops_dispatch.c index 5745a2aff2..cad52f83a0 100644 --- a/libswscale/ops_dispatch.c +++ b/libswscale/ops_dispatch.c @@ -28,6 +28,7 @@ #include "ops.h" #include "ops_internal.h" #include "ops_dispatch.h" +#include "swscale_internal.h" typedef struct SwsOpPass { SwsCompiledOp comp; @@ -96,10 +97,12 @@ int ff_sws_ops_compile(SwsContext *ctx, const SwsOpBackend *backend, if (backend) return compile_backend(ctx, backend, ops, out); + const SwsBackend enabled = ff_sws_enabled_backends(ctx); for (int n = 0; ff_sws_op_backends[n]; n++) { const SwsOpBackend *backend = ff_sws_op_backends[n]; if (ops->src.hw_format != backend->hw_format || - ops->dst.hw_format != backend->hw_format) + ops->dst.hw_format != backend->hw_format || + !(enabled & backend->flags)) continue; if (compile_backend(ctx, backend, ops, out) < 0) continue; diff --git a/libswscale/ops_dispatch.h b/libswscale/ops_dispatch.h index be771da9a9..1678cc4bf2 100644 --- a/libswscale/ops_dispatch.h +++ b/libswscale/ops_dispatch.h @@ -129,6 +129,7 @@ void ff_sws_compiled_op_unref(SwsCompiledOp *comp); typedef struct SwsOpBackend { const char *name; /* Descriptive name for this backend */ + SwsBackend flags; /* Set of SWS_BACKEND_* */ /** * Compile an operation list to an implementation chain. May modify `ops` diff --git a/libswscale/ops_memcpy.c b/libswscale/ops_memcpy.c index 7fcd230d7b..769de96747 100644 --- a/libswscale/ops_memcpy.c +++ b/libswscale/ops_memcpy.c @@ -143,6 +143,7 @@ static int compile(SwsContext *ctx, SwsOpList *ops, SwsCompiledOp *out) const SwsOpBackend backend_murder = { .name = "memcpy", + .flags = SWS_BACKEND_MEMCPY, .compile = compile, .hw_format = AV_PIX_FMT_NONE, }; diff --git a/libswscale/options.c b/libswscale/options.c index 8109f1d23a..960c6b91dc 100644 --- a/libswscale/options.c +++ b/libswscale/options.c @@ -106,6 +106,19 @@ static const AVOption swscale_options[] = { { "saturation", "saturation mapping", 0, AV_OPT_TYPE_CONST, { .i64 = SWS_INTENT_SATURATION }, .flags = VE, .unit = "intent" }, { "absolute_colorimetric", "absolute colorimetric clipping", 0, AV_OPT_TYPE_CONST, { .i64 = SWS_INTENT_ABSOLUTE_COLORIMETRIC }, .flags = VE, .unit = "intent" }, + { "sws_backends", "set allowed swscale backends", OFFSET(backends), AV_OPT_TYPE_FLAGS, { .i64 = 0 }, .flags = VE, .unit = "sws_backend", .max = UINT_MAX }, + { "auto", "automatic selection", 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, .flags = VE, .unit = "sws_backend" }, + { "stable", "All stable backends", 0, AV_OPT_TYPE_CONST, { .i64 = SWS_BACKEND_STABLE }, .flags = VE, .unit = "sws_backend" }, + { "unstable", "All unstable backends", 0, AV_OPT_TYPE_CONST, { .i64 = SWS_BACKEND_UNSTABLE }, .flags = VE, .unit = "sws_backend" }, + { "all", "All available backends", 0, AV_OPT_TYPE_CONST, { .i64 = SWS_BACKEND_ALL }, .flags = VE, .unit = "sws_backend" }, + { "legacy", "legacy swscale code", 0, AV_OPT_TYPE_CONST, { .i64 = SWS_BACKEND_LEGACY }, .flags = VE, .unit = "sws_backend" }, + { "c", "template-based reference code", 0, AV_OPT_TYPE_CONST, { .i64 = SWS_BACKEND_C }, .flags = VE, .unit = "sws_backend" }, + { "memcpy", "fast path using libc memcpy", 0, AV_OPT_TYPE_CONST, { .i64 = SWS_BACKEND_MEMCPY }, .flags = VE, .unit = "sws_backend" }, + { "x86", "x86 SIMD kernels", 0, AV_OPT_TYPE_CONST, { .i64 = SWS_BACKEND_X86 }, .flags = VE, .unit = "sws_backend" }, + { "aarch64", "AArch64 NEON kernels", 0, AV_OPT_TYPE_CONST, { .i64 = SWS_BACKEND_AARCH64 }, .flags = VE, .unit = "sws_backend" }, + { "spirv", "Vulkan SPIR-V backend", 0, AV_OPT_TYPE_CONST, { .i64 = SWS_BACKEND_SPIRV }, .flags = VE, .unit = "sws_backend" }, + { "glsl", "Vulkan GLSL backend", 0, AV_OPT_TYPE_CONST, { .i64 = SWS_BACKEND_GLSL }, .flags = VE, .unit = "sws_backend" }, + { NULL } }; diff --git a/libswscale/swscale.h b/libswscale/swscale.h index fa0769aa23..8954f1a7d8 100644 --- a/libswscale/swscale.h +++ b/libswscale/swscale.h @@ -107,6 +107,29 @@ typedef enum SwsScaler { SWS_SCALE_MAX_ENUM = 0x7FFFFFFF, ///< force size to 32 bits, not a valid filter type } SwsScaler; +typedef enum SwsBackend { + /* Stable backends */ + SWS_BACKEND_LEGACY = (1 << 0), ///< Legacy bespoke format-specific code + SWS_BACKEND_STABLE = SWS_BACKEND_LEGACY, + + /* Unstable backends (auto-selected only if SWS_UNSTABLE is enabled) */ + SWS_BACKEND_C = (1 << 1), ///< Template-based C reference implementation + SWS_BACKEND_MEMCPY = (1 << 2), ///< Fast path using libc memcpy() / memset() + SWS_BACKEND_X86 = (1 << 3), ///< Chained x86 SIMD kernels + SWS_BACKEND_AARCH64 = (1 << 4), ///< Chained AArch64 NEON kernels + SWS_BACKEND_SPIRV = (1 << 5), ///< Vulkan SPIR-V backend + SWS_BACKEND_GLSL = (1 << 6), ///< Vulkan GLSL backend + SWS_BACKEND_UNSTABLE = SWS_BACKEND_C | + SWS_BACKEND_MEMCPY | + SWS_BACKEND_X86 | + SWS_BACKEND_AARCH64 | + SWS_BACKEND_SPIRV | + SWS_BACKEND_GLSL, + + SWS_BACKEND_ALL = SWS_BACKEND_STABLE | SWS_BACKEND_UNSTABLE, + SWS_BACKEND_MAX_ENUM = 0x7FFFFFFF, ///< force size to 32 bits, not a valid backend +} SwsBackend; + typedef enum SwsFlags { /** * Return an error on underspecified conversions. Without this flag, @@ -280,6 +303,16 @@ typedef struct SwsContext { */ SwsScaler scaler_sub; + /** + * Bitmask of SWS_BACKEND_*. If non-zero, this will restrict the available + * backends to the specified set. If left as zero, a default set of + * backends will be selected automatically (based on SWS_UNSTABLE). + * + * Note: This is only relevant for the new API (sws_scale_frame()). The + * stateful legacy API always implies SWS_BACKEND_LEGACY. + */ + SwsBackend backends; + /* Remember to add new fields to graph.c:opts_equal() */ } SwsContext; @@ -299,7 +332,8 @@ void sws_free_context(SwsContext **ctx); ***************************/ /** - * Test if a given (software) pixel format is supported. + * Test if a given (software) pixel format is supported by any backend, + * excluding unstable backends. * * @param output If 0, test if compatible with the source/input frame; * otherwise, with the destination/output frame. @@ -310,7 +344,8 @@ void sws_free_context(SwsContext **ctx); int sws_test_format(enum AVPixelFormat format, int output); /** - * Test if a given hardware pixel format is supported. + * Test if a given hardware pixel format is supported by any backend, + * excluding unstable backends. * * @param format The hardware format to check, or AV_PIX_FMT_NONE. * diff --git a/libswscale/swscale_internal.h b/libswscale/swscale_internal.h index f50b769f1f..9a822cb8e4 100644 --- a/libswscale/swscale_internal.h +++ b/libswscale/swscale_internal.h @@ -81,6 +81,8 @@ static inline SwsInternal *sws_internal(const SwsContext *sws) return (SwsInternal *) sws; } +SwsBackend ff_sws_enabled_backends(const SwsContext *ctx); + typedef struct Range { unsigned int start; unsigned int len; diff --git a/libswscale/utils.c b/libswscale/utils.c index 41c1cc5bb6..6ecba2c0b3 100644 --- a/libswscale/utils.c +++ b/libswscale/utils.c @@ -68,6 +68,18 @@ #include "vulkan/ops.h" #endif +SwsBackend ff_sws_enabled_backends(const SwsContext *ctx) +{ + if (ctx->backends) + return ctx->backends; + + SwsBackend fallback = SWS_BACKEND_STABLE; + if (ctx->flags & SWS_UNSTABLE) + fallback |= SWS_BACKEND_UNSTABLE; + + return fallback; +} + /** * Allocate and return an SwsContext without performing initialization. */ diff --git a/libswscale/version.h b/libswscale/version.h index 4c6af261e6..c0610fec1e 100644 --- a/libswscale/version.h +++ b/libswscale/version.h @@ -28,7 +28,7 @@ #include "version_major.h" -#define LIBSWSCALE_VERSION_MINOR 7 +#define LIBSWSCALE_VERSION_MINOR 8 #define LIBSWSCALE_VERSION_MICRO 100 #define LIBSWSCALE_VERSION_INT AV_VERSION_INT(LIBSWSCALE_VERSION_MAJOR, \ diff --git a/libswscale/vulkan/ops.c b/libswscale/vulkan/ops.c index c944e120c5..5f289baf12 100644 --- a/libswscale/vulkan/ops.c +++ b/libswscale/vulkan/ops.c @@ -1689,6 +1689,7 @@ static int compile_spirv(SwsContext *sws, SwsOpList *ops, SwsCompiledOp *out) const SwsOpBackend backend_spirv = { .name = "spirv", + .flags = SWS_BACKEND_SPIRV, .compile = compile_spirv, .hw_format = AV_PIX_FMT_VULKAN, }; @@ -1702,6 +1703,7 @@ static int compile_glsl(SwsContext *sws, SwsOpList *ops, SwsCompiledOp *out) const SwsOpBackend backend_glsl = { .name = "glsl", + .flags = SWS_BACKEND_GLSL, .compile = compile_glsl, .hw_format = AV_PIX_FMT_VULKAN, }; diff --git a/libswscale/x86/ops.c b/libswscale/x86/ops.c index 20369652cc..c8dde4d5d4 100644 --- a/libswscale/x86/ops.c +++ b/libswscale/x86/ops.c @@ -1054,6 +1054,7 @@ static int compile(SwsContext *ctx, SwsOpList *ops, SwsCompiledOp *out) const SwsOpBackend backend_x86 = { .name = "x86", + .flags = SWS_BACKEND_X86, .compile = compile, .hw_format = AV_PIX_FMT_NONE, }; _______________________________________________ ffmpeg-cvslog mailing list -- [email protected] To unsubscribe send an email to [email protected]
