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]

Reply via email to