PR #22422 opened by Niklas Haas (haasn)
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/22422
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/22422.patch

A grab bag of trivial, easily reviewable cosmetic/minor changes.


>From 2b669745f5aab36f28cdb28b4a4b1640931d1386 Mon Sep 17 00:00:00 2001
From: Niklas Haas <[email protected]>
Date: Thu, 12 Feb 2026 10:44:19 +0100
Subject: [PATCH 01/13] swscale/ops: use SwsCompFlags typedef instead of plain
 int

This improves the debugging experience. These are all internal structs so
there is no need to worry about ABI stability as a result of adding flags.

Signed-off-by: Niklas Haas <[email protected]>
---
 libswscale/ops.c | 14 +++++++-------
 libswscale/ops.h |  8 ++++----
 2 files changed, 11 insertions(+), 11 deletions(-)

diff --git a/libswscale/ops.c b/libswscale/ops.c
index 9961f4f791..f8447f284c 100644
--- a/libswscale/ops.c
+++ b/libswscale/ops.c
@@ -213,11 +213,11 @@ void ff_sws_apply_op_q(const SwsOp *op, AVRational x[4])
 }
 
 /* merge_comp_flags() forms a monoid with flags_identity as the null element */
-static const unsigned flags_identity = SWS_COMP_ZERO | SWS_COMP_EXACT;
-static unsigned merge_comp_flags(unsigned a, unsigned b)
+static const SwsCompFlags flags_identity = SWS_COMP_ZERO | SWS_COMP_EXACT;
+static SwsCompFlags merge_comp_flags(SwsCompFlags a, SwsCompFlags b)
 {
-    const unsigned flags_or  = SWS_COMP_GARBAGE;
-    const unsigned flags_and = SWS_COMP_ZERO | SWS_COMP_EXACT;
+    const SwsCompFlags flags_or  = SWS_COMP_GARBAGE;
+    const SwsCompFlags flags_and = SWS_COMP_ZERO | SWS_COMP_EXACT;
     return ((a & b) & flags_and) | ((a | b) & flags_or);
 }
 
@@ -320,7 +320,7 @@ void ff_sws_op_list_update_comps(SwsOpList *ops)
             }
             break;
         case SWS_OP_PACK: {
-            unsigned flags = flags_identity;
+            SwsCompFlags flags = flags_identity;
             for (int i = 0; i < 4; i++) {
                 if (op->pack.pattern[i])
                     flags = merge_comp_flags(flags, prev.flags[i]);
@@ -356,7 +356,7 @@ void ff_sws_op_list_update_comps(SwsOpList *ops)
             break;
         case SWS_OP_LINEAR:
             for (int i = 0; i < 4; i++) {
-                unsigned flags = flags_identity;
+                SwsCompFlags flags = flags_identity;
                 AVRational min = Q(0), max = Q(0);
                 for (int j = 0; j < 4; j++) {
                     const AVRational k = op->lin.m[i][j];
@@ -681,7 +681,7 @@ static const char *describe_lin_mask(uint32_t mask)
     return "ERR";
 }
 
-static char describe_comp_flags(unsigned flags)
+static char describe_comp_flags(SwsCompFlags flags)
 {
     if (flags & SWS_COMP_GARBAGE)
         return 'X';
diff --git a/libswscale/ops.h b/libswscale/ops.h
index 64a4a6dd61..8868d88bed 100644
--- a/libswscale/ops.h
+++ b/libswscale/ops.h
@@ -69,12 +69,12 @@ typedef enum SwsOpType {
     SWS_OP_TYPE_NB,
 } SwsOpType;
 
-enum SwsCompFlags {
+typedef enum SwsCompFlags {
     SWS_COMP_GARBAGE = 1 << 0, /* contents are undefined / garbage data */
     SWS_COMP_EXACT   = 1 << 1, /* value is an exact integer */
     SWS_COMP_ZERO    = 1 << 2, /* known to be a constant zero */
     SWS_COMP_SWAPPED = 1 << 3, /* byte order is swapped */
-};
+} SwsCompFlags;
 
 typedef union SwsConst {
     /* Generic constant value */
@@ -87,8 +87,8 @@ static_assert(sizeof(SwsConst) == sizeof(AVRational) * 4,
               "First field of SwsConst should span the entire union");
 
 typedef struct SwsComps {
-    unsigned flags[4]; /* knowledge about (output) component contents */
-    bool unused[4];    /* which input components are definitely unused */
+    SwsCompFlags flags[4]; /* knowledge about (output) component contents */
+    bool unused[4]; /* which input components are definitely unused */
 
     /* Keeps track of the known possible value range, or {0, 0} for undefined
      * or (unknown range) floating point inputs */
-- 
2.52.0


>From 6aea0cc60b2b59ee24abef0bcec341689204b49e Mon Sep 17 00:00:00 2001
From: Niklas Haas <[email protected]>
Date: Mon, 16 Feb 2026 11:09:11 +0100
Subject: [PATCH 02/13] swscale/ops: add ff_sws_op_type_name

Sponsored-by: Sovereign Tech Fund
Signed-off-by: Niklas Haas <[email protected]>
---
 libswscale/ops.c | 26 ++++++++++++++++++++++++++
 libswscale/ops.h |  2 ++
 2 files changed, 28 insertions(+)

diff --git a/libswscale/ops.c b/libswscale/ops.c
index f8447f284c..07c2080e97 100644
--- a/libswscale/ops.c
+++ b/libswscale/ops.c
@@ -92,6 +92,32 @@ bool ff_sws_pixel_type_is_int(SwsPixelType type)
     return false;
 }
 
+const char *ff_sws_op_type_name(SwsOpType op)
+{
+    switch (op) {
+    case SWS_OP_READ:        return "SWS_OP_READ";
+    case SWS_OP_WRITE:       return "SWS_OP_WRITE";
+    case SWS_OP_SWAP_BYTES:  return "SWS_OP_SWAP_BYTES";
+    case SWS_OP_SWIZZLE:     return "SWS_OP_SWIZZLE";
+    case SWS_OP_UNPACK:      return "SWS_OP_UNPACK";
+    case SWS_OP_PACK:        return "SWS_OP_PACK";
+    case SWS_OP_LSHIFT:      return "SWS_OP_LSHIFT";
+    case SWS_OP_RSHIFT:      return "SWS_OP_RSHIFT";
+    case SWS_OP_CLEAR:       return "SWS_OP_CLEAR";
+    case SWS_OP_CONVERT:     return "SWS_OP_CONVERT";
+    case SWS_OP_MIN:         return "SWS_OP_MIN";
+    case SWS_OP_MAX:         return "SWS_OP_MAX";
+    case SWS_OP_SCALE:       return "SWS_OP_SCALE";
+    case SWS_OP_LINEAR:      return "SWS_OP_LINEAR";
+    case SWS_OP_DITHER:      return "SWS_OP_DITHER";
+    case SWS_OP_INVALID:     return "SWS_OP_INVALID";
+    case SWS_OP_TYPE_NB: break;
+    }
+
+    av_unreachable("Invalid operation type!");
+    return "ERR";
+}
+
 /* biased towards `a` */
 static AVRational av_min_q(AVRational a, AVRational b)
 {
diff --git a/libswscale/ops.h b/libswscale/ops.h
index 8868d88bed..37e8f06331 100644
--- a/libswscale/ops.h
+++ b/libswscale/ops.h
@@ -69,6 +69,8 @@ typedef enum SwsOpType {
     SWS_OP_TYPE_NB,
 } SwsOpType;
 
+const char *ff_sws_op_type_name(SwsOpType op);
+
 typedef enum SwsCompFlags {
     SWS_COMP_GARBAGE = 1 << 0, /* contents are undefined / garbage data */
     SWS_COMP_EXACT   = 1 << 1, /* value is an exact integer */
-- 
2.52.0


>From 16e7a8253609bf6febb781cf29479051dd368913 Mon Sep 17 00:00:00 2001
From: Niklas Haas <[email protected]>
Date: Mon, 16 Feb 2026 12:04:09 +0100
Subject: [PATCH 03/13] swscale/ops: simplify ff_sws_op_list_print

Using the new ff_sws_op_type_name() helper.

Sponsored-by: Sovereign Tech Fund
Signed-off-by: Niklas Haas <[email protected]>
---
 libswscale/ops.c | 38 ++++++++++++++++----------------------
 1 file changed, 16 insertions(+), 22 deletions(-)

diff --git a/libswscale/ops.c b/libswscale/ops.c
index 07c2080e97..9bea2f0b4f 100644
--- a/libswscale/ops.c
+++ b/libswscale/ops.c
@@ -760,8 +760,9 @@ void ff_sws_op_list_print(void *log, int lev, int lev_extra,
     }
 
     for (int i = 0; i < ops->num_ops; i++) {
-        const SwsOp *op = &ops->ops[i];
+        const SwsOp *op   = &ops->ops[i];
         const SwsOp *next = i + 1 < ops->num_ops ? &ops->ops[i + 1] : op;
+        const char *name  = ff_sws_op_type_name(op->op);
         char buf[32];
 
         av_log(log, lev, "  [%3s %c%c%c%c -> %c%c%c%c] ",
@@ -777,68 +778,62 @@ void ff_sws_op_list_print(void *log, int lev, int 
lev_extra,
 
         switch (op->op) {
         case SWS_OP_INVALID:
-            av_log(log, lev, "SWS_OP_INVALID\n");
+        case SWS_OP_SWAP_BYTES:
+            av_log(log, lev, "%s\n", name);
             break;
         case SWS_OP_READ:
         case SWS_OP_WRITE:
-            av_log(log, lev, "%-20s: %d elem(s) %s >> %d%s\n",
-                   op->op == SWS_OP_READ ? "SWS_OP_READ"
-                                         : "SWS_OP_WRITE",
+            av_log(log, lev, "%-20s: %d elem(s) %s >> %d%s\n", name,
                    op->rw.elems,  op->rw.packed ? "packed" : "planar",
                    op->rw.frac,
                    describe_order(op->op == SWS_OP_READ ? ops->order_src
                                                         : ops->order_dst,
                                   op->rw.packed ? 1 : op->rw.elems, buf));
             break;
-        case SWS_OP_SWAP_BYTES:
-            av_log(log, lev, "SWS_OP_SWAP_BYTES\n");
-            break;
         case SWS_OP_LSHIFT:
-            av_log(log, lev, "%-20s: << %u\n", "SWS_OP_LSHIFT", op->c.u);
+            av_log(log, lev, "%-20s: << %u\n", name, op->c.u);
             break;
         case SWS_OP_RSHIFT:
-            av_log(log, lev, "%-20s: >> %u\n", "SWS_OP_RSHIFT", op->c.u);
+            av_log(log, lev, "%-20s: >> %u\n", name, op->c.u);
             break;
         case SWS_OP_PACK:
         case SWS_OP_UNPACK:
-            av_log(log, lev, "%-20s: {%d %d %d %d}\n",
-                   op->op == SWS_OP_PACK ? "SWS_OP_PACK"
-                                         : "SWS_OP_UNPACK",
+            av_log(log, lev, "%-20s: {%d %d %d %d}\n", name,
                    op->pack.pattern[0], op->pack.pattern[1],
                    op->pack.pattern[2], op->pack.pattern[3]);
             break;
         case SWS_OP_CLEAR:
-            av_log(log, lev, "%-20s: {%s %s %s %s}\n", "SWS_OP_CLEAR",
+            av_log(log, lev, "%-20s: {%s %s %s %s}\n", name,
                    op->c.q4[0].den ? PRINTQ(op->c.q4[0]) : "_",
                    op->c.q4[1].den ? PRINTQ(op->c.q4[1]) : "_",
                    op->c.q4[2].den ? PRINTQ(op->c.q4[2]) : "_",
                    op->c.q4[3].den ? PRINTQ(op->c.q4[3]) : "_");
             break;
         case SWS_OP_SWIZZLE:
-            av_log(log, lev, "%-20s: %d%d%d%d\n", "SWS_OP_SWIZZLE",
+            av_log(log, lev, "%-20s: %d%d%d%d\n", name,
                    op->swizzle.x, op->swizzle.y, op->swizzle.z, op->swizzle.w);
             break;
         case SWS_OP_CONVERT:
-            av_log(log, lev, "%-20s: %s -> %s%s\n", "SWS_OP_CONVERT",
+            av_log(log, lev, "%-20s: %s -> %s%s\n", name,
                    ff_sws_pixel_type_name(op->type),
                    ff_sws_pixel_type_name(op->convert.to),
                    op->convert.expand ? " (expand)" : "");
             break;
         case SWS_OP_DITHER:
-            av_log(log, lev, "%-20s: %dx%d matrix + {%d %d %d %d}\n", 
"SWS_OP_DITHER",
+            av_log(log, lev, "%-20s: %dx%d matrix + {%d %d %d %d}\n", name,
                     1 << op->dither.size_log2, 1 << op->dither.size_log2,
                     op->dither.y_offset[0], op->dither.y_offset[1],
                     op->dither.y_offset[2], op->dither.y_offset[3]);
             break;
         case SWS_OP_MIN:
-            av_log(log, lev, "%-20s: x <= {%s %s %s %s}\n", "SWS_OP_MIN",
+            av_log(log, lev, "%-20s: x <= {%s %s %s %s}\n", name,
                     op->c.q4[0].den ? PRINTQ(op->c.q4[0]) : "_",
                     op->c.q4[1].den ? PRINTQ(op->c.q4[1]) : "_",
                     op->c.q4[2].den ? PRINTQ(op->c.q4[2]) : "_",
                     op->c.q4[3].den ? PRINTQ(op->c.q4[3]) : "_");
             break;
         case SWS_OP_MAX:
-            av_log(log, lev, "%-20s: {%s %s %s %s} <= x\n", "SWS_OP_MAX",
+            av_log(log, lev, "%-20s: {%s %s %s %s} <= x\n", name,
                     op->c.q4[0].den ? PRINTQ(op->c.q4[0]) : "_",
                     op->c.q4[1].den ? PRINTQ(op->c.q4[1]) : "_",
                     op->c.q4[2].den ? PRINTQ(op->c.q4[2]) : "_",
@@ -849,15 +844,14 @@ void ff_sws_op_list_print(void *log, int lev, int 
lev_extra,
                                         "[%s %s %s %s %s] "
                                         "[%s %s %s %s %s] "
                                         "[%s %s %s %s %s]]\n",
-                   "SWS_OP_LINEAR", describe_lin_mask(op->lin.mask),
+                   name, describe_lin_mask(op->lin.mask),
                    PRINTQ(op->lin.m[0][0]), PRINTQ(op->lin.m[0][1]), 
PRINTQ(op->lin.m[0][2]), PRINTQ(op->lin.m[0][3]), PRINTQ(op->lin.m[0][4]),
                    PRINTQ(op->lin.m[1][0]), PRINTQ(op->lin.m[1][1]), 
PRINTQ(op->lin.m[1][2]), PRINTQ(op->lin.m[1][3]), PRINTQ(op->lin.m[1][4]),
                    PRINTQ(op->lin.m[2][0]), PRINTQ(op->lin.m[2][1]), 
PRINTQ(op->lin.m[2][2]), PRINTQ(op->lin.m[2][3]), PRINTQ(op->lin.m[2][4]),
                    PRINTQ(op->lin.m[3][0]), PRINTQ(op->lin.m[3][1]), 
PRINTQ(op->lin.m[3][2]), PRINTQ(op->lin.m[3][3]), PRINTQ(op->lin.m[3][4]));
             break;
         case SWS_OP_SCALE:
-            av_log(log, lev, "%-20s: * %s\n", "SWS_OP_SCALE",
-                   PRINTQ(op->c.q));
+            av_log(log, lev, "%-20s: * %s\n", name, PRINTQ(op->c.q));
             break;
         case SWS_OP_TYPE_NB:
             break;
-- 
2.52.0


>From 1372223da0eb23c7c47685611d941bc8b7452b4e Mon Sep 17 00:00:00 2001
From: Niklas Haas <[email protected]>
Date: Thu, 26 Feb 2026 15:05:09 +0100
Subject: [PATCH 04/13] swscale/vulkan/ops: log op name in generated shader

I think this just makes for a marginally nicer debugging experience.

Sponsored-by: Sovereign Tech Fund
Signed-off-by: Niklas Haas <[email protected]>
---
 libswscale/vulkan/ops.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/libswscale/vulkan/ops.c b/libswscale/vulkan/ops.c
index b52f5d9d3d..b423683120 100644
--- a/libswscale/vulkan/ops.c
+++ b/libswscale/vulkan/ops.c
@@ -234,6 +234,8 @@ static int add_ops_glsl(VulkanPriv *p, FFVulkanOpsCtx *s,
         const char *type_s = op->type == SWS_PIXEL_F32 ? "float" :
                              op->type == SWS_PIXEL_U32 ? "uint32_t" :
                              op->type == SWS_PIXEL_U16 ? "uint16_t" : 
"uint8_t";
+        av_bprintf(&shd->src, "    // %s\n", ff_sws_op_type_name(op->op));
+
         switch (op->op) {
         case SWS_OP_READ: {
             if (op->rw.packed) {
-- 
2.52.0


>From a8e62ecf65d541d2b719dfd29dead2fdd549bcd1 Mon Sep 17 00:00:00 2001
From: Niklas Haas <[email protected]>
Date: Fri, 6 Mar 2026 18:05:14 +0100
Subject: [PATCH 05/13] swscale/vulkan/ops: fix undefined behavior on
 SWS_OP_CLEAR

op->rw.frac dereferences nonsense on clear ops.

Sponsored-by: Sovereign Tech Fund
Signed-off-by: Niklas Haas <[email protected]>
---
 libswscale/vulkan/ops.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/libswscale/vulkan/ops.c b/libswscale/vulkan/ops.c
index b423683120..db59e123ef 100644
--- a/libswscale/vulkan/ops.c
+++ b/libswscale/vulkan/ops.c
@@ -182,8 +182,7 @@ static int add_ops_glsl(VulkanPriv *p, FFVulkanOpsCtx *s,
     for (int n = 0; n < ops->num_ops; n++) {
         const SwsOp *op = &ops->ops[n];
         /* Set initial type */
-        if (op->op == SWS_OP_READ || op->op == SWS_OP_WRITE ||
-            op->op == SWS_OP_CLEAR) {
+        if (op->op == SWS_OP_READ || op->op == SWS_OP_WRITE) {
             if (op->rw.frac)
                 return AVERROR(ENOTSUP);
         }
-- 
2.52.0


>From 461098ef38454cca99002462224ed21f073c5825 Mon Sep 17 00:00:00 2001
From: Niklas Haas <[email protected]>
Date: Fri, 6 Mar 2026 18:07:12 +0100
Subject: [PATCH 06/13] swscale/vulkan/ops: move buffer desc setting to helper
 function

And call it on the read/write ops directly, rather than this awkward loop.

Sponsored-by: Sovereign Tech Fund
Signed-off-by: Niklas Haas <[email protected]>
---
 libswscale/vulkan/ops.c | 57 +++++++++++++++++++----------------------
 1 file changed, 27 insertions(+), 30 deletions(-)

diff --git a/libswscale/vulkan/ops.c b/libswscale/vulkan/ops.c
index db59e123ef..9c9b91ed98 100644
--- a/libswscale/vulkan/ops.c
+++ b/libswscale/vulkan/ops.c
@@ -157,6 +157,28 @@ static void free_fn(void *priv)
     av_free(priv);
 }
 
+static void add_desc_read_write(FFVulkanDescriptorSetBinding *out_desc,
+                                enum FFVkShaderRepFormat *out_rep,
+                                const SwsOp *op)
+{
+    const char *img_type = op->type == SWS_PIXEL_F32 ? "rgba32f"  :
+                           op->type == SWS_PIXEL_U32 ? "rgba32ui" :
+                           op->type == SWS_PIXEL_U16 ? "rgba16ui" :
+                                                       "rgba8ui";
+
+    *out_desc = (FFVulkanDescriptorSetBinding) {
+        .name = op->op == SWS_OP_WRITE ? "dst_img" : "src_img",
+        .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
+        .mem_layout = img_type,
+        .mem_quali = op->op == SWS_OP_WRITE ? "writeonly" : "readonly",
+        .dimensions = 2,
+        .elems = op->rw.packed ? 1 : op->rw.elems,
+        .stages = VK_SHADER_STAGE_COMPUTE_BIT,
+    };
+
+    *out_rep = op->type == SWS_PIXEL_F32 ? FF_VK_REP_FLOAT : FF_VK_REP_UINT;
+}
+
 #if CONFIG_LIBSHADERC || CONFIG_LIBGLSLANG
 static int add_ops_glsl(VulkanPriv *p, FFVulkanOpsCtx *s,
                         SwsOpList *ops, FFVulkanShader *shd)
@@ -179,36 +201,11 @@ static int add_ops_glsl(VulkanPriv *p, FFVulkanOpsCtx *s,
     int nb_desc = 0;
     FFVulkanDescriptorSetBinding buf_desc[8];
 
-    for (int n = 0; n < ops->num_ops; n++) {
-        const SwsOp *op = &ops->ops[n];
-        /* Set initial type */
-        if (op->op == SWS_OP_READ || op->op == SWS_OP_WRITE) {
-            if (op->rw.frac)
-                return AVERROR(ENOTSUP);
-        }
-        if (op->op == SWS_OP_READ || op->op == SWS_OP_WRITE) {
-            const char *img_type = op->type == SWS_PIXEL_F32 ? "rgba32f"  :
-                                   op->type == SWS_PIXEL_U32 ? "rgba32ui" :
-                                   op->type == SWS_PIXEL_U16 ? "rgba16ui" :
-                                                               "rgba8ui";
-            buf_desc[nb_desc++] = (FFVulkanDescriptorSetBinding) {
-                .name = op->op == SWS_OP_WRITE ? "dst_img" : "src_img",
-                .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
-                .mem_layout = img_type,
-                .mem_quali = op->op == SWS_OP_WRITE ? "writeonly" : "readonly",
-                .dimensions = 2,
-                .elems = (op->rw.packed ? 1 : op->rw.elems),
-                .stages = VK_SHADER_STAGE_COMPUTE_BIT,
-            };
-            if (op->op == SWS_OP_READ)
-                p->src_rep = op->type == SWS_PIXEL_F32 ? FF_VK_REP_FLOAT :
-                             FF_VK_REP_UINT;
-            else
-                p->dst_rep = op->type == SWS_PIXEL_F32 ? FF_VK_REP_FLOAT :
-                             FF_VK_REP_UINT;
-        }
-    }
-
+    const SwsOp *read  = ff_sws_op_list_input(ops);
+    const SwsOp *write = ff_sws_op_list_output(ops);
+    if (read)
+        add_desc_read_write(&buf_desc[nb_desc++], &p->src_rep, read);
+    add_desc_read_write(&buf_desc[nb_desc++], &p->src_rep, write);
     ff_vk_shader_add_descriptor_set(&s->vkctx, shd, buf_desc, nb_desc, 0, 0);
 
     GLSLC(0, void main()                                                      
);
-- 
2.52.0


>From 3f3ef8b24dfb000f49be9bc50425b1a1f11580a8 Mon Sep 17 00:00:00 2001
From: Niklas Haas <[email protected]>
Date: Mon, 2 Mar 2026 00:30:18 +0100
Subject: [PATCH 07/13] swscale/ops_dispatch: avoid redundant
 ff_sws_op_list_update_comps()

This is already called by compile_backend(), and nothing else in this file
depends on accurate values.

Sponsored-by: Sovereign Tech Fund
Signed-off-by: Niklas Haas <[email protected]>
---
 libswscale/ops_dispatch.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/libswscale/ops_dispatch.c b/libswscale/ops_dispatch.c
index 67ce225b82..64abea27f3 100644
--- a/libswscale/ops_dispatch.c
+++ b/libswscale/ops_dispatch.c
@@ -387,8 +387,6 @@ int ff_sws_compile_pass(SwsGraph *graph, SwsOpList *ops, 
int flags,
         ret = ff_sws_op_list_optimize(ops);
         if (ret < 0)
             return ret;
-    } else {
-        ff_sws_op_list_update_comps(ops);
     }
 
     return compile(graph, ops, dst, input, output);
-- 
2.52.0


>From c99c66c2911ea0ee66d4470c1e608e5d843ef64c Mon Sep 17 00:00:00 2001
From: Niklas Haas <[email protected]>
Date: Thu, 5 Mar 2026 18:30:02 +0100
Subject: [PATCH 08/13] swscale/ops_dispatch: print op list on successful
 compile

Instead of once at the start of add_convert_pass(). This makes much
more sense in light of the fact that we want to start e.g. splitting
passes apart.

Sponsored-by: Sovereign Tech Fund
Signed-off-by: Niklas Haas <[email protected]>
---
 libswscale/graph.c        | 4 +---
 libswscale/ops_dispatch.c | 2 ++
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/libswscale/graph.c b/libswscale/graph.c
index 8e8fb01f95..0901e8d984 100644
--- a/libswscale/graph.c
+++ b/libswscale/graph.c
@@ -598,10 +598,8 @@ static int add_convert_pass(SwsGraph *graph, const 
SwsFormat *src,
 
     av_log(ctx, AV_LOG_DEBUG, "Unoptimized operation list:\n");
     ff_sws_op_list_print(ctx, AV_LOG_DEBUG, AV_LOG_TRACE, ops);
-    av_log(ctx, AV_LOG_DEBUG, "Optimized operation list:\n");
-    ff_sws_op_list_optimize(ops);
-    ff_sws_op_list_print(ctx, AV_LOG_VERBOSE, AV_LOG_TRACE, ops);
 
+    ff_sws_op_list_optimize(ops);
     ret = ff_sws_compile_pass(graph, ops, 0, dst, input, output);
     if (ret < 0)
         goto fail;
diff --git a/libswscale/ops_dispatch.c b/libswscale/ops_dispatch.c
index 64abea27f3..0a6911f9b5 100644
--- a/libswscale/ops_dispatch.c
+++ b/libswscale/ops_dispatch.c
@@ -85,6 +85,8 @@ int ff_sws_ops_compile(SwsContext *ctx, const SwsOpList *ops, 
SwsCompiledOp *out
                "block size = %d, over-read = %d, over-write = %d, cpu flags = 
0x%x\n",
                backend->name, out->block_size, out->over_read, out->over_write,
                out->cpu_flags);
+
+        ff_sws_op_list_print(ctx, AV_LOG_VERBOSE, AV_LOG_TRACE, ops);
         return 0;
     }
 
-- 
2.52.0


>From 55d22400988dd7973c1ce9f04f03fd9bd1ad8d97 Mon Sep 17 00:00:00 2001
From: Niklas Haas <[email protected]>
Date: Thu, 26 Feb 2026 15:29:45 +0100
Subject: [PATCH 09/13] swscale/graph: pass SWS_OP_FLAG_OPTIMIZE

Instead of optimizing it with an explicit call. May enable more optimizations
in the future.

Signed-off-by: Niklas Haas <[email protected]>
---
 libswscale/graph.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/libswscale/graph.c b/libswscale/graph.c
index 0901e8d984..65cc920588 100644
--- a/libswscale/graph.c
+++ b/libswscale/graph.c
@@ -599,8 +599,7 @@ static int add_convert_pass(SwsGraph *graph, const 
SwsFormat *src,
     av_log(ctx, AV_LOG_DEBUG, "Unoptimized operation list:\n");
     ff_sws_op_list_print(ctx, AV_LOG_DEBUG, AV_LOG_TRACE, ops);
 
-    ff_sws_op_list_optimize(ops);
-    ret = ff_sws_compile_pass(graph, ops, 0, dst, input, output);
+    ret = ff_sws_compile_pass(graph, ops, SWS_OP_FLAG_OPTIMIZE, dst, input, 
output);
     if (ret < 0)
         goto fail;
 
-- 
2.52.0


>From af92e27fc45fc076fa6184778bc175761f6fe688 Mon Sep 17 00:00:00 2001
From: Niklas Haas <[email protected]>
Date: Wed, 4 Mar 2026 15:53:33 +0100
Subject: [PATCH 10/13] tests/checkasm/sw_ops: fix exec.slice_h assignment

This should match the number of lines.

Sponsored-by: Sovereign Tech Fund
Signed-off-by: Niklas Haas <[email protected]>
---
 tests/checkasm/sw_ops.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/tests/checkasm/sw_ops.c b/tests/checkasm/sw_ops.c
index 6615f63354..aea183b820 100644
--- a/tests/checkasm/sw_ops.c
+++ b/tests/checkasm/sw_ops.c
@@ -30,9 +30,9 @@
 #include "checkasm.h"
 
 enum {
-    LINES  = 2,
-    NB_PLANES = 4,
-    PIXELS = 64,
+    NB_PLANES   = 4,
+    PIXELS      = 64,
+    LINES       = 16,
 };
 
 enum {
@@ -174,7 +174,7 @@ static void check_ops(const char *report, const unsigned 
ranges[NB_PLANES],
 
     SwsOpExec exec = {0};
     exec.width = PIXELS;
-    exec.height = exec.slice_h = 1;
+    exec.height = exec.slice_h = LINES;
     for (int i = 0; i < NB_PLANES; i++) {
         exec.in_stride[i]  = sizeof(src0[i][0]);
         exec.out_stride[i] = sizeof(dst0[i][0]);
-- 
2.52.0


>From 8a2bf903db39470bc5dc9db7ea931aa68e0d5d4c Mon Sep 17 00:00:00 2001
From: Niklas Haas <[email protected]>
Date: Sun, 22 Feb 2026 19:30:34 +0100
Subject: [PATCH 11/13] swscale: restructure sws_scale_frame() slightly

Results in IMHO slightly more readable code flow, and will be useful in an
upcoming commit (that adds logic to ref individual planes).

Signed-off-by: Niklas Haas <[email protected]>
---
 libswscale/swscale.c | 35 ++++++++++++++---------------------
 1 file changed, 14 insertions(+), 21 deletions(-)

diff --git a/libswscale/swscale.c b/libswscale/swscale.c
index 94d9102f97..c7d8ef309d 100644
--- a/libswscale/swscale.c
+++ b/libswscale/swscale.c
@@ -1368,28 +1368,21 @@ int sws_scale_frame(SwsContext *sws, AVFrame *dst, 
const AVFrame *src)
     if (!src->data[0])
         return 0;
 
-    if (c->graph[FIELD_TOP]->noop &&
-        (!c->graph[FIELD_BOTTOM] || c->graph[FIELD_BOTTOM]->noop) &&
-        src->buf[0] && !dst->buf[0] && !dst->data[0])
-    {
-        /* Lightweight refcopy */
-        ret = frame_ref(dst, src);
-        if (ret < 0)
-            return ret;
-    } else {
-        if (!dst->data[0]) {
-            ret = av_frame_get_buffer(dst, 0);
-            if (ret < 0)
-                return ret;
-        }
+    const SwsGraph *top = c->graph[FIELD_TOP];
+    const SwsGraph *bot = c->graph[FIELD_BOTTOM];
+    if (dst->data[0]) /* user-provided buffers */
+        goto process_frame;
 
-        for (int field = 0; field < 2; field++) {
-            SwsGraph *graph = c->graph[field];
-            ff_sws_graph_run(graph, dst, src);
-            if (!graph->dst.interlaced)
-                break;
-        }
-    }
+    if (src->buf[0] && top->noop && (!bot || bot->noop))
+        return frame_ref(dst, src);
+
+    ret = av_frame_get_buffer(dst, 0);
+    if (ret < 0)
+        return ret;
+
+process_frame:
+    for (int field = 0; field < (bot ? 2 : 1); field++)
+        ff_sws_graph_run(c->graph[field], dst, src);
 
     return 0;
 }
-- 
2.52.0


>From d35cda4e0df6d5c05024a8c0a7fe37ab1f590e0a Mon Sep 17 00:00:00 2001
From: Niklas Haas <[email protected]>
Date: Fri, 6 Mar 2026 18:47:48 +0100
Subject: [PATCH 12/13] swscale: add sanity clear on AVFrame *dst

Before allocating/referencing buffers, make sure these fields are in a
defined state.

Signed-off-by: Niklas Haas <[email protected]>
---
 libswscale/swscale.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/libswscale/swscale.c b/libswscale/swscale.c
index c7d8ef309d..911d10390c 100644
--- a/libswscale/swscale.c
+++ b/libswscale/swscale.c
@@ -1373,6 +1373,12 @@ int sws_scale_frame(SwsContext *sws, AVFrame *dst, const 
AVFrame *src)
     if (dst->data[0]) /* user-provided buffers */
         goto process_frame;
 
+    /* Sanity */
+    memset(dst->buf, 0, sizeof(dst->buf));
+    memset(dst->data, 0, sizeof(dst->data));
+    memset(dst->linesize, 0, sizeof(dst->linesize));
+    dst->extended_data = dst->data;
+
     if (src->buf[0] && top->noop && (!bot || bot->noop))
         return frame_ref(dst, src);
 
-- 
2.52.0


>From 92ccfab959648124bf594ba9cc063091ce9eeaa8 Mon Sep 17 00:00:00 2001
From: Niklas Haas <[email protected]>
Date: Fri, 6 Mar 2026 18:48:57 +0100
Subject: [PATCH 13/13] swscale: don't pointlessly loop over NULL buffers

This array is defined as contiguous.

Signed-off-by: Niklas Haas <[email protected]>
---
 libswscale/swscale.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libswscale/swscale.c b/libswscale/swscale.c
index 911d10390c..b3387fff6f 100644
--- a/libswscale/swscale.c
+++ b/libswscale/swscale.c
@@ -1327,7 +1327,7 @@ static int frame_ref(AVFrame *dst, const AVFrame *src)
     /* ref the buffers */
     for (int i = 0; i < FF_ARRAY_ELEMS(src->buf); i++) {
         if (!src->buf[i])
-            continue;
+            break;
         dst->buf[i] = av_buffer_ref(src->buf[i]);
         if (!dst->buf[i])
             return AVERROR(ENOMEM);
-- 
2.52.0

_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to