This is an automated email from the git hooks/post-receive script.

Git pushed a commit to branch master
in repository ffmpeg.

commit cf2d40f65ddab61ec4dd274e10f76339fd7d213a
Author:     Niklas Haas <[email protected]>
AuthorDate: Sun Mar 29 19:32:45 2026 +0200
Commit:     Niklas Haas <[email protected]>
CommitDate: Thu Apr 16 23:23:36 2026 +0200

    swscale/ops: add explicit clear mask to SwsClearOp
    
    Instead of implicitly testing for NaN values. This is mostly a 
straightforward
    translation, but we need some slight extra boilerplate to ensure the mask
    is correctly updated when e.g. commuting past a swizzle.
    
    Signed-off-by: Niklas Haas <[email protected]>
---
 libswscale/format.c        | 10 ++++++++--
 libswscale/ops.c           |  6 +++---
 libswscale/ops.h           |  3 ++-
 libswscale/ops_chain.c     |  4 ++--
 libswscale/ops_memcpy.c    |  2 +-
 libswscale/ops_optimizer.c | 21 +++++++++++++--------
 libswscale/tests/sws_ops.c |  2 +-
 libswscale/vulkan/ops.c    |  8 +++++---
 libswscale/x86/ops.c       |  2 +-
 tests/checkasm/sw_ops.c    | 35 +++++++++++++++++++----------------
 10 files changed, 55 insertions(+), 38 deletions(-)

diff --git a/libswscale/format.c b/libswscale/format.c
index a26349585a..ad85f46cfa 100644
--- a/libswscale/format.c
+++ b/libswscale/format.c
@@ -931,10 +931,15 @@ static SwsClearOp fmt_clear(enum AVPixelFormat fmt)
     const bool has_alpha  = desc->flags & AV_PIX_FMT_FLAG_ALPHA;
 
     SwsClearOp c = {0};
-    if (!has_chroma)
+    if (!has_chroma) {
+        c.mask |= SWS_COMP(1) | SWS_COMP(2);
         c.value[1] = c.value[2] = Q0;
-    if (!has_alpha)
+    }
+
+    if (!has_alpha) {
+        c.mask |= SWS_COMP(3);
         c.value[3] = Q0;
+    }
 
     return c;
 }
@@ -1060,6 +1065,7 @@ int ff_sws_encode_pixfmt(SwsOpList *ops, enum 
AVPixelFormat fmt)
         RET(ff_sws_op_list_append(ops, &(SwsOp) {
             .op   = SWS_OP_CLEAR,
             .type = pixel_type,
+            .clear.mask = SWS_COMP(3),
             .clear.value[3] = Q0,
         }));
     }
diff --git a/libswscale/ops.c b/libswscale/ops.c
index e2b6da25a8..c91c39d29a 100644
--- a/libswscale/ops.c
+++ b/libswscale/ops.c
@@ -217,7 +217,7 @@ void ff_sws_apply_op_q(const SwsOp *op, AVRational x[4])
         return;
     case SWS_OP_CLEAR:
         for (int i = 0; i < 4; i++) {
-            if (op->clear.value[i].den)
+            if (SWS_COMP_TEST(op->clear.mask, i))
                 x[i] = op->clear.value[i];
         }
         return;
@@ -446,7 +446,7 @@ void ff_sws_op_list_update_comps(SwsOpList *ops)
         }
         case SWS_OP_CLEAR:
             for (int i = 0; i < 4; i++) {
-                if (op->clear.value[i].den) {
+                if (SWS_COMP_TEST(op->clear.mask, i)) {
                     op->comps.flags[i] = 0;
                     if (op->clear.value[i].num == 0)
                         op->comps.flags[i] |= SWS_COMP_ZERO;
@@ -565,7 +565,7 @@ void ff_sws_op_list_update_comps(SwsOpList *ops)
             break;
         case SWS_OP_CLEAR:
             for (int i = 0; i < 4; i++) {
-                if (!op->clear.value[i].den)
+                if (!SWS_COMP_TEST(op->clear.mask, i))
                     need_in[i] = need_out[i];
             }
             break;
diff --git a/libswscale/ops.h b/libswscale/ops.h
index fb5b9fab4e..4d908edba2 100644
--- a/libswscale/ops.h
+++ b/libswscale/ops.h
@@ -167,7 +167,8 @@ typedef struct SwsShiftOp {
 } SwsShiftOp;
 
 typedef struct SwsClearOp {
-    AVRational value[4]; /* value to set, or {0, 0} for no-op */
+    SwsCompMask mask;    /* mask of components to clear */
+    AVRational value[4]; /* value to set */
 } SwsClearOp;
 
 typedef struct SwsConvertOp {
diff --git a/libswscale/ops_chain.c b/libswscale/ops_chain.c
index 1730fdfe61..7072f8c437 100644
--- a/libswscale/ops_chain.c
+++ b/libswscale/ops_chain.c
@@ -117,7 +117,7 @@ static int op_match(const SwsOp *op, const SwsOpEntry 
*entry)
         for (int i = 0; i < 4; i++) {
             if (!SWS_OP_NEEDED(op, i))
                 continue;
-            if (entry->unused[i] != !!op->clear.value[i].den)
+            if (entry->unused[i] != SWS_COMP_TEST(op->clear.mask, i))
                 return 0;
         }
     }
@@ -149,7 +149,7 @@ static int op_match(const SwsOp *op, const SwsOpEntry 
*entry)
         return score;
     case SWS_OP_CLEAR:
         for (int i = 0; i < 4; i++) {
-            if (!op->clear.value[i].den || !SWS_OP_NEEDED(op, i))
+            if (!SWS_COMP_TEST(op->clear.mask, i) || !SWS_OP_NEEDED(op, i))
                 continue;
             if (av_cmp_q(op->clear.value[i], Q(entry->clear_value)))
                 return 0;
diff --git a/libswscale/ops_memcpy.c b/libswscale/ops_memcpy.c
index 1fec8b21c9..5ad12b87b6 100644
--- a/libswscale/ops_memcpy.c
+++ b/libswscale/ops_memcpy.c
@@ -99,7 +99,7 @@ static int compile(SwsContext *ctx, SwsOpList *ops, 
SwsCompiledOp *out)
 
         case SWS_OP_CLEAR:
             for (int i = 0; i < 4; i++) {
-                if (!op->clear.value[i].den)
+                if (!SWS_COMP_TEST(op->clear.mask, i))
                     continue;
                 if (op->clear.value[i].den != 1)
                     return AVERROR(ENOTSUP);
diff --git a/libswscale/ops_optimizer.c b/libswscale/ops_optimizer.c
index ec6581e9f7..8e0ceafa0b 100644
--- a/libswscale/ops_optimizer.c
+++ b/libswscale/ops_optimizer.c
@@ -53,11 +53,14 @@ static bool op_commute_clear(SwsOp *op, SwsOp *next)
     case SWS_OP_MAX:
     case SWS_OP_SCALE:
     case SWS_OP_READ:
-    case SWS_OP_SWIZZLE:
     case SWS_OP_FILTER_H:
     case SWS_OP_FILTER_V:
         ff_sws_apply_op_q(next, op->clear.value);
         return true;
+    case SWS_OP_SWIZZLE:
+        op->clear.mask = ff_sws_comp_mask_swizzle(op->clear.mask, 
next->swizzle);
+        ff_sws_apply_op_q(next, op->clear.value);
+        return true;
     case SWS_OP_SWAP_BYTES:
         switch (next->type) {
         case SWS_PIXEL_U16:
@@ -65,7 +68,7 @@ static bool op_commute_clear(SwsOp *op, SwsOp *next)
             return true;
         case SWS_PIXEL_U32:
             for (int i = 0; i < 4; i++) {
-                if (!op->clear.value[i].den)
+                if (!SWS_COMP_TEST(op->clear.mask, i))
                     continue;
                 uint32_t v = av_bswap32(op->clear.value[i].num);
                 if (v > INT_MAX)
@@ -277,6 +280,7 @@ static bool extract_constant_rows(SwsLinearOp *c, SwsComps 
prev,
                          (prev.flags[j] & SWS_COMP_ZERO); /* input is zero */
         }
         if (const_row && (c->mask & SWS_MASK_ROW(i))) {
+            clear.mask |= SWS_COMP(i);
             clear.value[i] = c->m[i][4];
             for (int j = 0; j < 5; j++)
                 c->m[i][j] = Q(i == j);
@@ -444,7 +448,7 @@ retry:
 
         case SWS_OP_CLEAR:
             for (int i = 0; i < 4; i++) {
-                if (!op->clear.value[i].den)
+                if (!SWS_COMP_TEST(op->clear.mask, i))
                     continue;
 
                 if ((prev->comps.flags[i] & SWS_COMP_ZERO) &&
@@ -452,11 +456,11 @@ retry:
                     op->clear.value[i].num == 0)
                 {
                     /* Redundant clear-to-zero of zero component */
-                    op->clear.value[i].den = 0;
+                    op->clear.mask ^= SWS_COMP(i);
                 } else if (!SWS_OP_NEEDED(op, i)) {
                     /* Unnecessary clear of unused component */
-                    op->clear.value[i] = (AVRational) {0, 0};
-                } else if (op->clear.value[i].den) {
+                    op->clear.mask ^= SWS_COMP(i);
+                } else {
                     noop = false;
                 }
             }
@@ -469,9 +473,10 @@ retry:
             /* Transitive clear */
             if (next->op == SWS_OP_CLEAR) {
                 for (int i = 0; i < 4; i++) {
-                    if (next->clear.value[i].den)
+                    if (SWS_COMP_TEST(next->clear.mask, i))
                         op->clear.value[i] = next->clear.value[i];
                 }
+                op->clear.mask |= next->clear.mask;
                 ff_sws_op_list_remove_at(ops, n + 1, 1);
                 goto retry;
             }
@@ -816,7 +821,7 @@ int ff_sws_solve_shuffle(const SwsOpList *const ops, 
uint8_t shuffle[],
 
         case SWS_OP_CLEAR:
             for (int i = 0; i < 4; i++) {
-                if (!op->clear.value[i].den)
+                if (!SWS_COMP_TEST(op->clear.mask, i))
                     continue;
                 if (op->clear.value[i].num != 0 || !clear_val)
                     return AVERROR(ENOTSUP);
diff --git a/libswscale/tests/sws_ops.c b/libswscale/tests/sws_ops.c
index 05378be18d..1256c73ec6 100644
--- a/libswscale/tests/sws_ops.c
+++ b/libswscale/tests/sws_ops.c
@@ -74,7 +74,7 @@ static int register_op(SwsContext *ctx, void *opaque, SwsOp 
*op)
         break;
     case SWS_OP_CLEAR:
         for (int i = 0; i < 4; i++)
-            op->clear.value[i] = (AVRational) { 0, !!op->clear.value[i].den };
+            op->clear.value[i] = (AVRational) { 0, 
SWS_COMP_TEST(op->clear.mask, i) };
         break;
     case SWS_OP_DITHER:
         /* Strip arbitrary offset */
diff --git a/libswscale/vulkan/ops.c b/libswscale/vulkan/ops.c
index 49a3d7827c..cf128b00c1 100644
--- a/libswscale/vulkan/ops.c
+++ b/libswscale/vulkan/ops.c
@@ -398,12 +398,14 @@ static void define_shader_consts(SwsOpList *ops, SPICtx 
*spi, SPIRVIDs *id)
             break;
         case SWS_OP_CLEAR:
             for (int i = 0; i < 4; i++) {
+                if (!SWS_COMP_TEST(op->clear.mask, i))
+                    continue;
                 AVRational cv = op->clear.value[i];
-                if (cv.den && op->type == SWS_PIXEL_F32) {
+                if (op->type == SWS_PIXEL_F32) {
                     float q = (float)cv.num/cv.den;
                     id->const_ids[id->nb_const_ids++] =
                         spi_OpConstantFloat(spi, f32_type, q);
-                } else if (op->clear.value[i].den) {
+                } else {
                     av_assert0(cv.den == 1);
                     id->const_ids[id->nb_const_ids++] =
                         spi_OpConstantUInt(spi, u32_type, cv.num);
@@ -1036,7 +1038,7 @@ static int add_ops_glsl(VulkanPriv *p, FFVulkanOpsCtx *s,
         }
         case SWS_OP_CLEAR: {
             for (int i = 0; i < 4; i++) {
-                if (!op->clear.value[i].den)
+                if (!SWS_COMP_TEST(op->clear.mask, i))
                     continue;
                 av_bprintf(&shd->src, "    %s.%c = %s"QSTR";\n", type_name,
                            "xyzw"[i], type_s, QTYPE(op->clear.value[i]));
diff --git a/libswscale/x86/ops.c b/libswscale/x86/ops.c
index a87fa56f53..5e95e80eac 100644
--- a/libswscale/x86/ops.c
+++ b/libswscale/x86/ops.c
@@ -953,7 +953,7 @@ static void normalize_clear(SwsOp *op)
     ff_sws_setup_clear(&(const SwsImplParams) { .op = op }, &res);
 
     for (int i = 0; i < 4; i++) {
-        if (!op->clear.value[i].den)
+        if (!SWS_COMP_TEST(op->clear.mask, i))
             continue;
         switch (ff_sws_pixel_type_size(op->type)) {
         case 1: c.u32 = 0x1010101U * res.priv.u8[i]; break;
diff --git a/tests/checkasm/sw_ops.c b/tests/checkasm/sw_ops.c
index dd993ffcfc..82415574f4 100644
--- a/tests/checkasm/sw_ops.c
+++ b/tests/checkasm/sw_ops.c
@@ -540,32 +540,34 @@ static void check_clear(void)
             const AVRational zero   = (AVRational) { 0, 1};
             const AVRational none = {0};
 
-            const SwsClearOp patterns[] = {
+            const AVRational patterns[][4] = {
                 /* Zero only */
-                {{   none,   none,   none,   zero }},
-                {{   zero,   none,   none,   none }},
+                {   none,   none,   none,   zero },
+                {   zero,   none,   none,   none },
                 /* Alpha only */
-                {{   none,   none,   none,  alpha }},
-                {{  alpha,   none,   none,   none }},
+                {   none,   none,   none,  alpha },
+                {  alpha,   none,   none,   none },
                 /* Chroma only */
-                {{ chroma, chroma,   none,   none }},
-                {{   none, chroma, chroma,   none }},
-                {{   none,   none, chroma, chroma }},
-                {{ chroma,   none, chroma,   none }},
-                {{   none, chroma,   none, chroma }},
+                { chroma, chroma,   none,   none },
+                {   none, chroma, chroma,   none },
+                {   none,   none, chroma, chroma },
+                { chroma,   none, chroma,   none },
+                {   none, chroma,   none, chroma },
                 /* Alpha+chroma */
-                {{ chroma, chroma,   none,  alpha }},
-                {{   none, chroma, chroma,  alpha }},
-                {{  alpha,   none, chroma, chroma }},
-                {{ chroma,   none, chroma,  alpha }},
-                {{  alpha, chroma,   none, chroma }},
+                { chroma, chroma,   none,  alpha },
+                {   none, chroma, chroma,  alpha },
+                {  alpha,   none, chroma, chroma },
+                { chroma,   none, chroma,  alpha },
+                {  alpha, chroma,   none, chroma },
             };
 
             for (int i = 0; i < FF_ARRAY_ELEMS(patterns); i++) {
+                SwsClearOp clear = { .mask = ff_sws_comp_mask_q4(patterns[i]) 
};
+                memcpy(clear.value, patterns[i], sizeof(clear.value));
                 CHECK(FMT("clear_pattern_%s[%d]", type, i), 4, 4, t, t, {
                     .op    = SWS_OP_CLEAR,
                     .type  = t,
-                    .clear = patterns[i],
+                    .clear = clear,
                 });
             }
         } else if (!ff_sws_pixel_type_is_int(t)) {
@@ -574,6 +576,7 @@ static void check_clear(void)
                 .op   = SWS_OP_CLEAR,
                 .type = t,
                 .clear.value[3] = { 0, 1 },
+                .clear.mask = SWS_COMP(3),
             });
         }
     }

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

Reply via email to