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

Cherry-picked a bit of low hanging fruit to get an LLM review and CI workflow.


>From 127efb70727bd9a82659238f415506c913bac66a Mon Sep 17 00:00:00 2001
From: Niklas Haas <[email protected]>
Date: Tue, 16 Jun 2026 15:03:56 +0200
Subject: [PATCH 01/16] swscale/format: pass SwsFormat to
 ff_sws_decode_colors()

Needed to set initial plane size metadata. I decided to update
ff_sws_encode_colors() as well for symmetry.

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

diff --git a/libswscale/format.c b/libswscale/format.c
index 545ba1909e..c34d335500 100644
--- a/libswscale/format.c
+++ b/libswscale/format.c
@@ -958,11 +958,10 @@ static void swizzle_inv(SwsSwizzleOp *swiz)
  * it will end up getting pushed towards the output or optimized away entirely
  * by the optimization pass.
  */
-static SwsClearOp fmt_clear(enum AVPixelFormat fmt)
+static SwsClearOp fmt_clear(const SwsFormat *fmt)
 {
-    const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(fmt);
-    const bool has_chroma = desc->nb_components >= 3;
-    const bool has_alpha  = desc->flags & AV_PIX_FMT_FLAG_ALPHA;
+    const bool has_chroma = fmt->desc->nb_components >= 3;
+    const bool has_alpha  = fmt->desc->flags & AV_PIX_FMT_FLAG_ALPHA;
 
     SwsClearOp c = {0};
     if (!has_chroma) {
@@ -984,9 +983,9 @@ static SwsClearOp fmt_clear(enum AVPixelFormat fmt)
 #  define NATIVE_ENDIAN_FLAG 0
 #endif
 
-int ff_sws_decode_pixfmt(SwsOpList *ops, enum AVPixelFormat fmt)
+int ff_sws_decode_pixfmt(SwsOpList *ops, const SwsFormat *fmt)
 {
-    const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(fmt);
+    const AVPixFmtDescriptor *desc = fmt->desc;
     SwsPixelType pixel_type, raw_type;
     SwsReadWriteOp rw_op;
     SwsSwizzleOp swizzle;
@@ -994,7 +993,7 @@ int ff_sws_decode_pixfmt(SwsOpList *ops, enum AVPixelFormat 
fmt)
     SwsComps *comps = &ops->comps_src;
     SwsShiftOp shift;
 
-    RET(fmt_analyze(fmt, &rw_op, &unpack, &swizzle, &shift,
+    RET(fmt_analyze(fmt->format, &rw_op, &unpack, &swizzle, &shift,
                     &pixel_type, &raw_type));
 
     swizzle_inv(&swizzle);
@@ -1073,16 +1072,16 @@ int ff_sws_decode_pixfmt(SwsOpList *ops, enum 
AVPixelFormat fmt)
     return 0;
 }
 
-int ff_sws_encode_pixfmt(SwsOpList *ops, enum AVPixelFormat fmt)
+int ff_sws_encode_pixfmt(SwsOpList *ops, const SwsFormat *fmt)
 {
-    const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(fmt);
+    const AVPixFmtDescriptor *desc = fmt->desc;
     SwsPixelType pixel_type, raw_type;
     SwsReadWriteOp rw_op;
     SwsSwizzleOp swizzle;
     SwsPackOp pack;
     SwsShiftOp shift;
 
-    RET(fmt_analyze(fmt, &rw_op, &pack, &swizzle, &shift,
+    RET(fmt_analyze(fmt->format, &rw_op, &pack, &swizzle, &shift,
                     &pixel_type, &raw_type));
 
     if (shift.amount) {
@@ -1680,7 +1679,7 @@ int ff_sws_op_list_generate(SwsContext *ctx, const 
SwsFormat *src,
     ops->dst = *dst;
 
     const SwsPixelType type = SWS_PIXEL_F32;
-    int ret = ff_sws_decode_pixfmt(ops, src->format);
+    int ret = ff_sws_decode_pixfmt(ops, src);
     if (ret < 0)
         goto fail;
     ret = ff_sws_decode_colors(ctx, type, ops, src, incomplete);
@@ -1692,7 +1691,7 @@ int ff_sws_op_list_generate(SwsContext *ctx, const 
SwsFormat *src,
     ret = ff_sws_encode_colors(ctx, type, ops, src, dst, incomplete);
     if (ret < 0)
         goto fail;
-    ret = ff_sws_encode_pixfmt(ops, dst->format);
+    ret = ff_sws_encode_pixfmt(ops, dst);
     if (ret < 0)
         goto fail;
 
diff --git a/libswscale/format.h b/libswscale/format.h
index 67f25d7006..36158da55a 100644
--- a/libswscale/format.h
+++ b/libswscale/format.h
@@ -174,8 +174,8 @@ typedef enum SwsPixelType SwsPixelType;
  *
  * Returns 0 on success, or a negative error code on failure.
  */
-int ff_sws_decode_pixfmt(SwsOpList *ops, enum AVPixelFormat fmt);
-int ff_sws_encode_pixfmt(SwsOpList *ops, enum AVPixelFormat fmt);
+int ff_sws_decode_pixfmt(SwsOpList *ops, const SwsFormat *fmt);
+int ff_sws_encode_pixfmt(SwsOpList *ops, const SwsFormat *fmt);
 
 /**
  * Append a set of operations for transforming decoded pixel values to/from
-- 
2.52.0


>From e52459195c247b51cd813fd5aa8ab68e88d3affe Mon Sep 17 00:00:00 2001
From: Niklas Haas <[email protected]>
Date: Sat, 20 Jun 2026 02:50:26 +0200
Subject: [PATCH 02/16] swscale/ops: simplify SWS_OP_READ default comps
 handling

We can still pre-fill the prev array here; ff_sws_apply_op_q() is a no-op.

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

diff --git a/libswscale/ops.c b/libswscale/ops.c
index 31bb2bdec4..1ea5261c3d 100644
--- a/libswscale/ops.c
+++ b/libswscale/ops.c
@@ -361,7 +361,6 @@ void ff_sws_op_list_update_comps(SwsOpList *ops)
         SwsOp *op = &ops->ops[n];
 
         switch (op->op) {
-        case SWS_OP_READ:
         case SWS_OP_LINEAR:
         case SWS_OP_DITHER:
         case SWS_OP_SWAP_BYTES:
@@ -393,11 +392,6 @@ void ff_sws_op_list_update_comps(SwsOpList *ops)
                 op->comps.min[i]   = ops->comps_src.min[idx];
                 op->comps.max[i]   = ops->comps_src.max[idx];
             }
-            for (int i = op->rw.elems; i < 4; i++) {
-                op->comps.flags[i] = prev.flags[i];
-                op->comps.min[i]   = prev.min[i];
-                op->comps.max[i]   = prev.max[i];
-            }
 
             if (op->rw.filter.op) {
                 const SwsComps prev = op->comps;
-- 
2.52.0


>From faac9fa705e58ea60597da091e35e58a7640128a Mon Sep 17 00:00:00 2001
From: Niklas Haas <[email protected]>
Date: Sat, 20 Jun 2026 02:52:02 +0200
Subject: [PATCH 03/16] swscale/ops_optimizer: set correct range metadata after
 split pass

Replaces a few "nan" value ranges by real values, and drops a bunch of
redundant non-FMA variants that resulted from this bug.

Sponsored-by: Sovereign Tech Fund
Signed-off-by: Niklas Haas <[email protected]>
---
 libswscale/ops_optimizer.c  |  5 ++++-
 libswscale/uops_macros.h    | 16 ----------------
 tests/ref/fate/sws-ops-list |  2 +-
 3 files changed, 5 insertions(+), 18 deletions(-)

diff --git a/libswscale/ops_optimizer.c b/libswscale/ops_optimizer.c
index 69973b63ce..e6ebd21515 100644
--- a/libswscale/ops_optimizer.c
+++ b/libswscale/ops_optimizer.c
@@ -1005,8 +1005,11 @@ int ff_sws_op_list_subpass(SwsOpList *ops1, SwsOpList 
**out_rest)
     ops1->dst = ops2->src;
 
     for (int i = 0; i < nb_planes; i++) {
+        const int idx = swiz_wr.in[i];
         ops1->plane_dst[i] = ops2->plane_src[i] = i;
-        ops2->comps_src.flags[i] = prev->comps.flags[swiz_wr.in[i]];
+        ops2->comps_src.flags[i]  = prev->comps.flags[idx];
+        ops2->comps_src.min[i]    = prev->comps.min[idx];
+        ops2->comps_src.max[i]    = prev->comps.max[idx];
     }
 
     ff_sws_op_list_remove_at(ops1, idx, ops1->num_ops - idx);
diff --git a/libswscale/uops_macros.h b/libswscale/uops_macros.h
index 3c4d6b6a3e..5d9e1a8026 100644
--- a/libswscale/uops_macros.h
+++ b/libswscale/uops_macros.h
@@ -1177,8 +1177,6 @@
     MACRO(__VA_ARGS__, f32_linear_xyzw_x0000_0x000_00x00_000x0 , .type = 
SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR          , .mask = 0xf, .par.lin.one = 
0x0, .par.lin.zero = 0xbefbe)
 #define SWS_FOR_F32_LINEAR_FMA(MACRO, ...) \
     MACRO(__VA_ARGS__, f32_linear_fma_x_xxx0x                  , 
SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA      , 0x1, 0x41040, 0xbefa8, 0xfffe8) \
-    MACRO(__VA_ARGS__, f32_linear_fma_x_XXx0x                  , 
SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA      , 0x1, 0x41040, 0xbefa8, 0xfffeb) \
-    MACRO(__VA_ARGS__, f32_linear_fma_x_xXX0x                  , 
SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA      , 0x1, 0x41040, 0xbefa8, 0xfffee) \
     MACRO(__VA_ARGS__, f32_linear_fma_x_XXX0x                  , 
SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA      , 0x1, 0x41040, 0xbefa8, 0xfffef) \
     MACRO(__VA_ARGS__, f32_linear_fma_x_x000x                  , 
SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA      , 0x1, 0x41040, 0xbefae, 0xfffee) \
     MACRO(__VA_ARGS__, f32_linear_fma_x_X000x                  , 
SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA      , 0x1, 0x41040, 0xbefae, 0xfffef) \
@@ -1188,18 +1186,12 @@
     MACRO(__VA_ARGS__, f32_linear_fma_x_xXX00                  , 
SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA      , 0x1, 0x41040, 0xbefb8, 0xffffe) \
     MACRO(__VA_ARGS__, f32_linear_fma_y_0x000                  , 
SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA      , 0x2, 0x41001, 0xbefbe, 0xfffbf) \
     MACRO(__VA_ARGS__, f32_linear_fma_xyz_xxx0x_xxx0x_xxx0x    , 
SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA      , 0x7, 0x40000, 0xba108, 0xfa108) \
-    MACRO(__VA_ARGS__, f32_linear_fma_xyz_XXx0x_XXx0x_XXx0x    , 
SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA      , 0x7, 0x40000, 0xba108, 0xfad6b) \
     MACRO(__VA_ARGS__, f32_linear_fma_xyz_XXX0x_XxX0x_XXX0x    , 
SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA      , 0x7, 0x40000, 0xba108, 0xfbdaf) \
-    MACRO(__VA_ARGS__, f32_linear_fma_xyz_xXX0x_xXX0x_xXX0x    , 
SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA      , 0x7, 0x40000, 0xba108, 0xfb9ce) \
     MACRO(__VA_ARGS__, f32_linear_fma_xyz_XXX0x_XXX0x_XXX0x    , 
SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA      , 0x7, 0x40000, 0xba108, 0xfbdef) \
-    MACRO(__VA_ARGS__, f32_linear_fma_xyz_x0x0x_xxx0x_xx00x    , 
SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA      , 0x7, 0x40000, 0xbb10a, 0xfb10a) \
     MACRO(__VA_ARGS__, f32_linear_fma_xyz_X0X0x_XXX0x_XX00x    , 
SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA      , 0x7, 0x40000, 0xbb10a, 0xfbdef) \
     MACRO(__VA_ARGS__, f32_linear_fma_xyz_xxx00_xxx0x_xxx0x    , 
SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA      , 0x7, 0x40000, 0xba118, 0xfa118) \
-    MACRO(__VA_ARGS__, f32_linear_fma_xyz_xXx00_XXx0x_XXx0x    , 
SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA      , 0x7, 0x40000, 0xba118, 0xfad7a) \
     MACRO(__VA_ARGS__, f32_linear_fma_xyz_xXX00_XxX0x_XXX0x    , 
SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA      , 0x7, 0x40000, 0xba118, 0xfbdbe) \
-    MACRO(__VA_ARGS__, f32_linear_fma_xyz_xXX00_xXX0x_xXX0x    , 
SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA      , 0x7, 0x40000, 0xba118, 0xfb9de) \
     MACRO(__VA_ARGS__, f32_linear_fma_xyz_xXX00_XXX0x_XXX0x    , 
SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA      , 0x7, 0x40000, 0xba118, 0xfbdfe) \
-    MACRO(__VA_ARGS__, f32_linear_fma_xyz_x000x_0x00x_00x0x    , 
SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA      , 0x7, 0x40000, 0xbadae, 0xfadae) \
     MACRO(__VA_ARGS__, f32_linear_fma_xyz_X000x_0X00x_00X0x    , 
SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA      , 0x7, 0x40000, 0xbadae, 0xfbdef) \
     MACRO(__VA_ARGS__, f32_linear_fma_xyz_x0000_0x000_00x00    , 
SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA      , 0x7, 0x40000, 0xbefbe, 0xfefbe) \
     MACRO(__VA_ARGS__, f32_linear_fma_xyz_10X0x_1XX0x_1X00x    , 
SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA      , 0x7, 0x40421, 0xbb10a, 0xfbdef) \
@@ -1214,8 +1206,6 @@
     MACRO(__VA_ARGS__, f32_linear_fma_xyzw_x0000_0x000_00x00_000x0, 
SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA      , 0xf, 0x00000, 0xbefbe, 0xbefbe)
 #define SWS_FOR_STRUCT_F32_LINEAR_FMA(MACRO, ...) \
     MACRO(__VA_ARGS__, f32_linear_fma_x_xxx0x                  , .type = 
SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA      , .mask = 0x1, .par.lin.one = 
0x41040, .par.lin.zero = 0xbefa8, .par.lin.exact = 0xfffe8) \
-    MACRO(__VA_ARGS__, f32_linear_fma_x_XXx0x                  , .type = 
SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA      , .mask = 0x1, .par.lin.one = 
0x41040, .par.lin.zero = 0xbefa8, .par.lin.exact = 0xfffeb) \
-    MACRO(__VA_ARGS__, f32_linear_fma_x_xXX0x                  , .type = 
SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA      , .mask = 0x1, .par.lin.one = 
0x41040, .par.lin.zero = 0xbefa8, .par.lin.exact = 0xfffee) \
     MACRO(__VA_ARGS__, f32_linear_fma_x_XXX0x                  , .type = 
SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA      , .mask = 0x1, .par.lin.one = 
0x41040, .par.lin.zero = 0xbefa8, .par.lin.exact = 0xfffef) \
     MACRO(__VA_ARGS__, f32_linear_fma_x_x000x                  , .type = 
SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA      , .mask = 0x1, .par.lin.one = 
0x41040, .par.lin.zero = 0xbefae, .par.lin.exact = 0xfffee) \
     MACRO(__VA_ARGS__, f32_linear_fma_x_X000x                  , .type = 
SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA      , .mask = 0x1, .par.lin.one = 
0x41040, .par.lin.zero = 0xbefae, .par.lin.exact = 0xfffef) \
@@ -1225,18 +1215,12 @@
     MACRO(__VA_ARGS__, f32_linear_fma_x_xXX00                  , .type = 
SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA      , .mask = 0x1, .par.lin.one = 
0x41040, .par.lin.zero = 0xbefb8, .par.lin.exact = 0xffffe) \
     MACRO(__VA_ARGS__, f32_linear_fma_y_0x000                  , .type = 
SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA      , .mask = 0x2, .par.lin.one = 
0x41001, .par.lin.zero = 0xbefbe, .par.lin.exact = 0xfffbf) \
     MACRO(__VA_ARGS__, f32_linear_fma_xyz_xxx0x_xxx0x_xxx0x    , .type = 
SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA      , .mask = 0x7, .par.lin.one = 
0x40000, .par.lin.zero = 0xba108, .par.lin.exact = 0xfa108) \
-    MACRO(__VA_ARGS__, f32_linear_fma_xyz_XXx0x_XXx0x_XXx0x    , .type = 
SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA      , .mask = 0x7, .par.lin.one = 
0x40000, .par.lin.zero = 0xba108, .par.lin.exact = 0xfad6b) \
     MACRO(__VA_ARGS__, f32_linear_fma_xyz_XXX0x_XxX0x_XXX0x    , .type = 
SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA      , .mask = 0x7, .par.lin.one = 
0x40000, .par.lin.zero = 0xba108, .par.lin.exact = 0xfbdaf) \
-    MACRO(__VA_ARGS__, f32_linear_fma_xyz_xXX0x_xXX0x_xXX0x    , .type = 
SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA      , .mask = 0x7, .par.lin.one = 
0x40000, .par.lin.zero = 0xba108, .par.lin.exact = 0xfb9ce) \
     MACRO(__VA_ARGS__, f32_linear_fma_xyz_XXX0x_XXX0x_XXX0x    , .type = 
SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA      , .mask = 0x7, .par.lin.one = 
0x40000, .par.lin.zero = 0xba108, .par.lin.exact = 0xfbdef) \
-    MACRO(__VA_ARGS__, f32_linear_fma_xyz_x0x0x_xxx0x_xx00x    , .type = 
SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA      , .mask = 0x7, .par.lin.one = 
0x40000, .par.lin.zero = 0xbb10a, .par.lin.exact = 0xfb10a) \
     MACRO(__VA_ARGS__, f32_linear_fma_xyz_X0X0x_XXX0x_XX00x    , .type = 
SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA      , .mask = 0x7, .par.lin.one = 
0x40000, .par.lin.zero = 0xbb10a, .par.lin.exact = 0xfbdef) \
     MACRO(__VA_ARGS__, f32_linear_fma_xyz_xxx00_xxx0x_xxx0x    , .type = 
SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA      , .mask = 0x7, .par.lin.one = 
0x40000, .par.lin.zero = 0xba118, .par.lin.exact = 0xfa118) \
-    MACRO(__VA_ARGS__, f32_linear_fma_xyz_xXx00_XXx0x_XXx0x    , .type = 
SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA      , .mask = 0x7, .par.lin.one = 
0x40000, .par.lin.zero = 0xba118, .par.lin.exact = 0xfad7a) \
     MACRO(__VA_ARGS__, f32_linear_fma_xyz_xXX00_XxX0x_XXX0x    , .type = 
SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA      , .mask = 0x7, .par.lin.one = 
0x40000, .par.lin.zero = 0xba118, .par.lin.exact = 0xfbdbe) \
-    MACRO(__VA_ARGS__, f32_linear_fma_xyz_xXX00_xXX0x_xXX0x    , .type = 
SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA      , .mask = 0x7, .par.lin.one = 
0x40000, .par.lin.zero = 0xba118, .par.lin.exact = 0xfb9de) \
     MACRO(__VA_ARGS__, f32_linear_fma_xyz_xXX00_XXX0x_XXX0x    , .type = 
SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA      , .mask = 0x7, .par.lin.one = 
0x40000, .par.lin.zero = 0xba118, .par.lin.exact = 0xfbdfe) \
-    MACRO(__VA_ARGS__, f32_linear_fma_xyz_x000x_0x00x_00x0x    , .type = 
SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA      , .mask = 0x7, .par.lin.one = 
0x40000, .par.lin.zero = 0xbadae, .par.lin.exact = 0xfadae) \
     MACRO(__VA_ARGS__, f32_linear_fma_xyz_X000x_0X00x_00X0x    , .type = 
SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA      , .mask = 0x7, .par.lin.one = 
0x40000, .par.lin.zero = 0xbadae, .par.lin.exact = 0xfbdef) \
     MACRO(__VA_ARGS__, f32_linear_fma_xyz_x0000_0x000_00x00    , .type = 
SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA      , .mask = 0x7, .par.lin.one = 
0x40000, .par.lin.zero = 0xbefbe, .par.lin.exact = 0xfefbe) \
     MACRO(__VA_ARGS__, f32_linear_fma_xyz_10X0x_1XX0x_1X00x    , .type = 
SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA      , .mask = 0x7, .par.lin.one = 
0x40421, .par.lin.zero = 0xbb10a, .par.lin.exact = 0xfbdef) \
diff --git a/tests/ref/fate/sws-ops-list b/tests/ref/fate/sws-ops-list
index 6b4003121a..dcda011ccc 100644
--- a/tests/ref/fate/sws-ops-list
+++ b/tests/ref/fate/sws-ops-list
@@ -1 +1 @@
-bbe27c8c324f08d933f6397f5fb96650
+e490d908612d059c644e64b43247fb08
-- 
2.52.0


>From b120505ce2d5e934451019250af4e846d0ced9c4 Mon Sep 17 00:00:00 2001
From: Niklas Haas <[email protected]>
Date: Sat, 20 Jun 2026 02:55:04 +0200
Subject: [PATCH 04/16] swscale/ops: apply ff_sws_comp_mask_swizzle() in-place

More convenient at every use site.

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

diff --git a/libswscale/ops.c b/libswscale/ops.c
index 1ea5261c3d..71f450fc6b 100644
--- a/libswscale/ops.c
+++ b/libswscale/ops.c
@@ -144,16 +144,17 @@ SwsCompMask ff_sws_comp_mask_q4(const AVRational q[4])
     return mask;
 }
 
-SwsCompMask ff_sws_comp_mask_swizzle(const SwsCompMask mask, const 
SwsSwizzleOp *swiz)
+void ff_sws_comp_mask_swizzle(SwsCompMask *mask, const SwsSwizzleOp *swiz)
 {
+    const SwsCompMask orig = *mask;
     SwsCompMask res = 0;
     for (int i = 0; i < 4; i++) {
         const int src = swiz->in[i];
-        if (SWS_COMP_TEST(mask, src))
+        if (SWS_COMP_TEST(orig, src))
             res |= SWS_COMP(i);
     }
 
-    return res;
+    *mask = res;
 }
 
 SwsCompMask ff_sws_comp_mask_needed(const SwsOp *op)
diff --git a/libswscale/ops.h b/libswscale/ops.h
index 41755f35f4..b5de7546d5 100644
--- a/libswscale/ops.h
+++ b/libswscale/ops.h
@@ -146,7 +146,7 @@ typedef struct SwsSwizzleOp {
 } SwsSwizzleOp;
 
 #define SWS_SWIZZLE(X,Y,Z,W) ((SwsSwizzleOp) { .in = {X, Y, Z, W} })
-SwsCompMask ff_sws_comp_mask_swizzle(SwsCompMask mask, const SwsSwizzleOp 
*swiz);
+void ff_sws_comp_mask_swizzle(SwsCompMask *mask, const SwsSwizzleOp *swiz);
 
 typedef struct SwsShiftOp {
     uint8_t amount; /* number of bits to shift */
diff --git a/libswscale/ops_optimizer.c b/libswscale/ops_optimizer.c
index e6ebd21515..8c473c1a52 100644
--- a/libswscale/ops_optimizer.c
+++ b/libswscale/ops_optimizer.c
@@ -61,7 +61,7 @@ static bool op_commute_clear(SwsOp *op, SwsOp *next)
         op->type = next->filter.type;
         return true;
     case SWS_OP_SWIZZLE:
-        op->clear.mask = ff_sws_comp_mask_swizzle(op->clear.mask, 
&next->swizzle);
+        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:
-- 
2.52.0


>From d474b408f2966646a824be2500e82a39038a5dc5 Mon Sep 17 00:00:00 2001
From: Niklas Haas <[email protected]>
Date: Fri, 19 Jun 2026 16:14:49 +0200
Subject: [PATCH 05/16] swscale/ops_optimizer: simplify unused op check
 (cosmetic)

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

diff --git a/libswscale/ops_optimizer.c b/libswscale/ops_optimizer.c
index 8c473c1a52..e41af380e9 100644
--- a/libswscale/ops_optimizer.c
+++ b/libswscale/ops_optimizer.c
@@ -393,12 +393,10 @@ retry:
         SwsOp *next = n + 1 < ops->num_ops ? &ops->ops[n + 1] : &dummy;
 
         /* common helper variable */
+        const SwsCompMask needed = ff_sws_comp_mask_needed(op);
         bool noop = true;
 
-        if (!SWS_OP_NEEDED(op, 0) && !SWS_OP_NEEDED(op, 1) &&
-            !SWS_OP_NEEDED(op, 2) && !SWS_OP_NEEDED(op, 3) &&
-            op->op != SWS_OP_WRITE)
-        {
+        if (!needed && op->op != SWS_OP_WRITE) {
             /* Remove any operation whose output is not needed */
             ff_sws_op_list_remove_at(ops, n, 1);
             goto retry;
-- 
2.52.0


>From cb8a006f8a2777ad2766ed7018458e9024586ad8 Mon Sep 17 00:00:00 2001
From: Niklas Haas <[email protected]>
Date: Fri, 19 Jun 2026 14:09:42 +0200
Subject: [PATCH 06/16] swscale/graph: don't over-allocate pass buffer lines

This is not only wasteful but also serves no real purpose. Looping over
the correct number of lines is trivial; there is far less point in vertical
padding than horizontal padding.

Furthermore, this might actually introduce issues when linking output buffers;
since the extra padding depends on the pass's alignment and threading
requirements, which may differ from pass to pass.

Sponsored-by: Sovereign Tech Fund
Signed-off-by: Niklas Haas <[email protected]>
---
 libswscale/graph.c | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/libswscale/graph.c b/libswscale/graph.c
index 3db3b98c7b..06e5ebefc8 100644
--- a/libswscale/graph.c
+++ b/libswscale/graph.c
@@ -201,6 +201,10 @@ int ff_sws_graph_add_pass(SwsGraph *graph, enum 
AVPixelFormat fmt,
         goto fail;
     }
 
+    pass->output->height = pass->height;
+    pass->output->width  = pass->width;
+    pass->output->width_align = 1;
+
     if (!align) {
         pass->slice_h = pass->height;
         pass->num_slices = 1;
@@ -210,11 +214,6 @@ int ff_sws_graph_add_pass(SwsGraph *graph, enum 
AVPixelFormat fmt,
         pass->num_slices = (pass->height + pass->slice_h - 1) / pass->slice_h;
     }
 
-    /* Align output buffer to include extra slice padding */
-    pass->output->height = pass->slice_h * pass->num_slices;
-    pass->output->width  = pass->width;
-    pass->output->width_align = 1;
-
     ret = av_dynarray_add_nofree(&graph->passes, &graph->num_passes, pass);
     if (ret < 0)
         goto fail;
-- 
2.52.0


>From ba1c1d9eee75a2bd5f2677907af1753112c5c69f Mon Sep 17 00:00:00 2001
From: Niklas Haas <[email protected]>
Date: Sat, 20 Jun 2026 02:55:31 +0200
Subject: [PATCH 07/16] swscale/graph: separate pass dispatch size from buffer
 size

This allows adding passes which will be dispatched over a reduced number of
lines, without affecting the allocated buffer dimensions - e.g. for passes
which purely write to subsampled chroma planes.

A few hard-coded references to pass->width/height need to be replaced by
the corresponding output frame references, but it's not a huge deal.

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

diff --git a/libswscale/graph.c b/libswscale/graph.c
index 06e5ebefc8..a765b4cd5c 100644
--- a/libswscale/graph.c
+++ b/libswscale/graph.c
@@ -174,7 +174,8 @@ static void pass_free(SwsPass *pass)
 
 int ff_sws_graph_add_pass(SwsGraph *graph, enum AVPixelFormat fmt,
                           int width, int height, SwsPass *input,
-                          int align, SwsPassFunc run, SwsPassSetup setup,
+                          int lines, int align,
+                          SwsPassFunc run, SwsPassSetup setup,
                           void *priv, void (*free_cb)(void *priv),
                           SwsPass **out_pass)
 {
@@ -186,14 +187,16 @@ int ff_sws_graph_add_pass(SwsGraph *graph, enum 
AVPixelFormat fmt,
         return AVERROR(ENOMEM);
     }
 
+    if (!lines)
+        lines = height;
+
     pass->graph  = graph;
     pass->run    = run;
     pass->setup  = setup;
     pass->priv   = priv;
     pass->free   = free_cb;
     pass->format = fmt;
-    pass->width  = width;
-    pass->height = height;
+    pass->lines  = lines;
     pass->input  = input;
     pass->output = av_refstruct_alloc_ext(sizeof(*pass->output), 0, NULL, 
free_buffer);
     if (!pass->output) {
@@ -201,17 +204,17 @@ int ff_sws_graph_add_pass(SwsGraph *graph, enum 
AVPixelFormat fmt,
         goto fail;
     }
 
-    pass->output->height = pass->height;
-    pass->output->width  = pass->width;
+    pass->output->height = height;
+    pass->output->width  = width;
     pass->output->width_align = 1;
 
     if (!align) {
-        pass->slice_h = pass->height;
+        pass->slice_h = pass->lines;
         pass->num_slices = 1;
     } else {
-        pass->slice_h = (pass->height + graph->num_threads - 1) / 
graph->num_threads;
+        pass->slice_h = (pass->lines + graph->num_threads - 1) / 
graph->num_threads;
         pass->slice_h = FFALIGN(pass->slice_h, align);
-        pass->num_slices = (pass->height + pass->slice_h - 1) / pass->slice_h;
+        pass->num_slices = (pass->lines + pass->slice_h - 1) / pass->slice_h;
     }
 
     ret = av_dynarray_add_nofree(&graph->passes, &graph->num_passes, pass);
@@ -267,7 +270,7 @@ static void run_rgb0(const SwsFrame *out, const SwsFrame 
*in, int y, int h,
 {
     SwsInternal *c = pass->priv;
     const int x0 = c->src0Alpha - 1;
-    const int w4 = 4 * pass->width;
+    const int w4 = 4 * out->width;
     const int src_stride = in->linesize[0];
     const int dst_stride = out->linesize[0];
     const uint8_t *src = in->data[0] + y * src_stride;
@@ -289,7 +292,7 @@ static void run_xyz2rgb(const SwsFrame *out, const SwsFrame 
*in, int y, int h,
     const SwsInternal *c = pass->priv;
     c->xyz12Torgb48(c, out->data[0] + y * out->linesize[0], out->linesize[0],
                     in->data[0] + y * in->linesize[0], in->linesize[0],
-                    pass->width, h);
+                    out->width, h);
 }
 
 static void run_rgb2xyz(const SwsFrame *out, const SwsFrame *in, int y, int h,
@@ -298,7 +301,7 @@ static void run_rgb2xyz(const SwsFrame *out, const SwsFrame 
*in, int y, int h,
     const SwsInternal *c = pass->priv;
     c->rgb48Toxyz12(c, out->data[0] + y * out->linesize[0], out->linesize[0],
                     in->data[0] + y * in->linesize[0], in->linesize[0],
-                    pass->width, h);
+                    out->width, h);
 }
 
 /***********************************************************************
@@ -465,7 +468,7 @@ static int init_legacy_subpass(SwsGraph *graph, SwsContext 
*sws,
 
     if (c->src0Alpha && !c->dst0Alpha && isALPHA(sws->dst_format)) {
         ret = ff_sws_graph_add_pass(graph, AV_PIX_FMT_RGBA, src_w, src_h, 
input,
-                                    1, run_rgb0, NULL, c, NULL, &input);
+                                    0, 1, run_rgb0, NULL, c, NULL, &input);
         if (ret < 0) {
             sws_free_context(&sws);
             return ret;
@@ -474,14 +477,14 @@ static int init_legacy_subpass(SwsGraph *graph, 
SwsContext *sws,
 
     if (c->srcXYZ && !(c->dstXYZ && unscaled)) {
         ret = ff_sws_graph_add_pass(graph, AV_PIX_FMT_RGB48, src_w, src_h, 
input,
-                                    1, run_xyz2rgb, NULL, c, NULL, &input);
+                                    0, 1, run_xyz2rgb, NULL, c, NULL, &input);
         if (ret < 0) {
             sws_free_context(&sws);
             return ret;
         }
     }
 
-    ret = ff_sws_graph_add_pass(graph, sws->dst_format, dst_w, dst_h, input, 
align,
+    ret = ff_sws_graph_add_pass(graph, sws->dst_format, dst_w, dst_h, input, 
0, align,
                                 c->convert_unscaled ? run_legacy_unscaled : 
run_legacy_swscale,
                                 setup_legacy_swscale, sws, 
free_legacy_swscale, &pass);
     if (ret < 0)
@@ -533,7 +536,7 @@ static int init_legacy_subpass(SwsGraph *graph, SwsContext 
*sws,
 
     if (c->dstXYZ && !(c->srcXYZ && unscaled)) {
         ret = ff_sws_graph_add_pass(graph, AV_PIX_FMT_RGB48, dst_w, dst_h, 
pass,
-                                    1, run_rgb2xyz, NULL, c, NULL, &pass);
+                                    0, 1, run_rgb2xyz, NULL, c, NULL, &pass);
         if (ret < 0)
             return ret;
     }
@@ -715,7 +718,7 @@ static void run_lut3d(const SwsFrame *out, const SwsFrame 
*in, int y, int h,
     frame_shift(out, y, out_data);
 
     ff_sws_lut3d_apply(lut, in_data[0], in->linesize[0], out_data[0],
-                       out->linesize[0], pass->width, h);
+                       out->linesize[0], out->width, h);
 }
 
 static int adapt_colors(SwsGraph *graph, const SwsFormat *src_fmt,
@@ -777,7 +780,7 @@ static int adapt_colors(SwsGraph *graph, const SwsFormat 
*src_fmt,
     }
 
     return ff_sws_graph_add_pass(graph, fmt_out, src.width, src.height,
-                                 input, 1, run_lut3d, setup_lut3d, lut,
+                                 input, 0, 1, run_lut3d, setup_lut3d, lut,
                                  free_lut3d, output);
 }
 
@@ -812,7 +815,7 @@ static int init_passes(SwsGraph *graph)
 
     /* Add threaded memcpy pass */
     return ff_sws_graph_add_pass(graph, dst.format, dst.width, dst.height,
-                                 pass, 1, run_copy, NULL, NULL, NULL, &pass);
+                                 pass, 0, 1, run_copy, NULL, NULL, NULL, 
&pass);
 }
 
 static void sws_graph_worker(void *priv, int jobnr, int threadnr, int nb_jobs,
@@ -821,7 +824,7 @@ static void sws_graph_worker(void *priv, int jobnr, int 
threadnr, int nb_jobs,
     SwsGraph *graph = priv;
     const SwsPass *pass = graph->exec.pass;
     const int slice_y = jobnr * pass->slice_h;
-    const int slice_h = FFMIN(pass->slice_h, pass->height - slice_y);
+    const int slice_h = FFMIN(pass->slice_h, pass->lines - slice_y);
 
     pass->run(graph->exec.output, graph->exec.input, slice_y, slice_h, pass);
 }
@@ -1016,7 +1019,7 @@ int ff_sws_graph_run(SwsGraph *graph, const AVFrame *dst, 
const AVFrame *src)
         }
 
         if (pass->num_slices == 1) {
-            pass->run(graph->exec.output, graph->exec.input, 0, pass->height, 
pass);
+            pass->run(graph->exec.output, graph->exec.input, 0, pass->lines, 
pass);
         } else {
             avpriv_slicethread_execute(graph->slicethread, pass->num_slices, 
0);
         }
diff --git a/libswscale/graph.h b/libswscale/graph.h
index adf4b19675..eff2dcc47f 100644
--- a/libswscale/graph.h
+++ b/libswscale/graph.h
@@ -83,7 +83,7 @@ struct SwsPass {
     SwsPassFunc run;
     SwsBackend backend; /* backend this pass is using, or 0 */
     enum AVPixelFormat format; /* new pixel format */
-    int width, height; /* new output size */
+    int lines;         /* pass dispatch size */
     int slice_h;       /* filter granularity */
     int num_slices;
 
@@ -184,6 +184,7 @@ int ff_sws_graph_create(SwsContext *ctx, const SwsFormat 
*dst, const SwsFormat *
  * @param w      Width of the output image.
  * @param h      Height of the output image.
  * @param input  Previous pass to read from, or NULL for the input image.
+ * @param lines  Override the number of lines processed for this pass. 
(Optional)
  * @param align  Minimum slice alignment for this pass, or 0 for no threading.
  * @param run    Filter function to run.
  * @param setup  Optional setup function to run from the main thread.
@@ -194,7 +195,8 @@ int ff_sws_graph_create(SwsContext *ctx, const SwsFormat 
*dst, const SwsFormat *
  */
 int ff_sws_graph_add_pass(SwsGraph *graph, enum AVPixelFormat fmt,
                           int width, int height, SwsPass *input,
-                          int align, SwsPassFunc run, SwsPassSetup setup,
+                          int lines, int align,
+                          SwsPassFunc run, SwsPassSetup setup,
                           void *priv, void (*free)(void *priv),
                           SwsPass **out_pass);
 
diff --git a/libswscale/ops_dispatch.c b/libswscale/ops_dispatch.c
index 44248195d7..abf67b0d55 100644
--- a/libswscale/ops_dispatch.c
+++ b/libswscale/ops_dispatch.c
@@ -202,6 +202,7 @@ static int op_pass_setup(const SwsFrame *out, const 
SwsFrame *in,
 {
     const AVPixFmtDescriptor *indesc  = av_pix_fmt_desc_get(in->format);
     const bool float_in = indesc->flags & AV_PIX_FMT_FLAG_FLOAT;
+    const int width = out->width;
 
     SwsOpPass *p = pass->priv;
     SwsOpExec *exec = &p->exec_base;
@@ -209,9 +210,9 @@ static int op_pass_setup(const SwsFrame *out, const 
SwsFrame *in,
 
     /* Set up main loop parameters */
     const unsigned block_size = comp->block_size;
-    const size_t num_blocks   = (pass->width + block_size - 1) / block_size;
+    const size_t num_blocks   = (width + block_size - 1) / block_size;
     const size_t aligned_w    = num_blocks * block_size;
-    if (aligned_w < pass->width) /* overflow */
+    if (aligned_w < width) /* overflow */
         return AVERROR(EINVAL);
     p->num_blocks   = num_blocks;
     p->memcpy_first = false;
@@ -280,14 +281,14 @@ static int op_pass_setup(const SwsFrame *out, const 
SwsFrame *in,
     *tail = *exec;
 
     const size_t safe_width = safe_blocks * block_size;
-    const size_t tail_size  = pass->width - safe_width;
+    const size_t tail_size  = width - safe_width;
     p->tail_off_out  = pixel_bytes(safe_width, p->pixel_bits_out, 
AV_ROUND_DOWN);
     p->tail_size_out = pixel_bytes(tail_size,  p->pixel_bits_out, AV_ROUND_UP);
     p->tail_blocks   = num_blocks - safe_blocks;
 
     if (exec->in_offset_x) {
         p->tail_off_in  = exec->in_offset_x[safe_width];
-        p->tail_size_in = exec->in_offset_x[pass->width - 1] - p->tail_off_in;
+        p->tail_size_in = exec->in_offset_x[width - 1] - p->tail_off_in;
         p->tail_size_in += pixel_bytes(p->filter_size_h, p->pixel_bits_in, 
AV_ROUND_UP);
     } else {
         p->tail_off_in  = pixel_bytes(safe_width, p->pixel_bits_in, 
AV_ROUND_DOWN);
@@ -387,7 +388,7 @@ static void op_pass_run(const SwsFrame *out, const SwsFrame 
*in, const int y,
      *    memcpy the last column on the output side if unpadded.
      */
 
-    const bool memcpy_in  = p->memcpy_last && y + h == pass->height ||
+    const bool memcpy_in  = p->memcpy_last && y + h == pass->lines ||
                             p->memcpy_first && y == 0;
     const bool memcpy_out = p->memcpy_out;
     const size_t num_blocks  = p->num_blocks;
@@ -515,7 +516,7 @@ static int compile(SwsGraph *graph, const SwsOpBackend 
*backend,
         SwsCompiledOp c = *comp;
         av_free(p);
         ret = ff_sws_graph_add_pass(graph, dst->format, dst->width, 
dst->height,
-                                    input, c.slice_align, c.func_opaque,
+                                    input, 0, c.slice_align, c.func_opaque,
                                     NULL, c.priv, c.free, output);
         if (ret >= 0)
             (*output)->backend = comp->backend->flags;
@@ -616,7 +617,7 @@ static int compile(SwsGraph *graph, const SwsOpBackend 
*backend,
     }
 
     ret = ff_sws_graph_add_pass(graph, dst->format, dst->width, dst->height,
-                                input, comp->slice_align, op_pass_run,
+                                input, 0, comp->slice_align, op_pass_run,
                                 op_pass_setup, p, op_pass_free, output);
     if (ret < 0)
         return ret;
-- 
2.52.0


>From 3a2c5050c6eb5dd2ffdf74b0af735c4d76ee9013 Mon Sep 17 00:00:00 2001
From: Niklas Haas <[email protected]>
Date: Fri, 19 Jun 2026 13:30:08 +0200
Subject: [PATCH 08/16] swscale: fix format equality check

I can't say I remember why this logic was written this way, but I can't
think of any good reason why we should exclude comparing the image
dimensions here - the intent is obviously to allow passthrough / noop.

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 c0cdd17b78..508967a13c 100644
--- a/libswscale/swscale.c
+++ b/libswscale/swscale.c
@@ -1512,7 +1512,7 @@ int sws_frame_setup(SwsContext *ctx, const AVFrame *dst, 
const AVFrame *src)
 
         src_ok = ff_test_fmt(backends, &src_fmt, 0);
         dst_ok = ff_test_fmt(backends, &dst_fmt, 1);
-        if ((!src_ok || !dst_ok) && !ff_props_equal(&src_fmt, &dst_fmt)) {
+        if ((!src_ok || !dst_ok) && !ff_fmt_equal(&src_fmt, &dst_fmt)) {
             err_msg = src_ok ? "Unsupported output" : "Unsupported input";
             ret = AVERROR(ENOTSUP);
             goto fail;
-- 
2.52.0


>From 7e7c1c0d94634543a7cc215d7c3b32235e487e25 Mon Sep 17 00:00:00 2001
From: Niklas Haas <[email protected]>
Date: Fri, 19 Jun 2026 13:31:30 +0200
Subject: [PATCH 09/16] swscale/format: nuke ff_props_equal()

And merge it with the more clear ff_fmt_equal().

Signed-off-by: Niklas Haas <[email protected]>
---
 libswscale/format.h | 18 ++++++------------
 1 file changed, 6 insertions(+), 12 deletions(-)

diff --git a/libswscale/format.h b/libswscale/format.h
index 36158da55a..24d53b8e80 100644
--- a/libswscale/format.h
+++ b/libswscale/format.h
@@ -120,23 +120,17 @@ static inline int ff_color_equal(const SwsColor *c1, 
const SwsColor *c2)
             ff_prim_equal(&c1->gamut, &c2->gamut);
 }
 
-/* Tests only the static components of a colorspace, ignoring dimensions and 
per-frame data */
-static inline int ff_props_equal(const SwsFormat *fmt1, const SwsFormat *fmt2)
-{
-    return fmt1->interlaced == fmt2->interlaced &&
-           fmt1->format     == fmt2->format     &&
-           fmt1->range      == fmt2->range      &&
-           fmt1->csp        == fmt2->csp        &&
-           fmt1->loc        == fmt2->loc        &&
-           ff_color_equal(&fmt1->color, &fmt2->color);
-}
-
 /* Tests only the static components of a colorspace, ignoring per-frame data */
 static inline int ff_fmt_equal(const SwsFormat *fmt1, const SwsFormat *fmt2)
 {
     return fmt1->width      == fmt2->width      &&
            fmt1->height     == fmt2->height     &&
-           ff_props_equal(fmt1, fmt2);
+           fmt1->interlaced == fmt2->interlaced &&
+           fmt1->format     == fmt2->format     &&
+           fmt1->range      == fmt2->range      &&
+           fmt1->csp        == fmt2->csp        &&
+           fmt1->loc        == fmt2->loc        &&
+           ff_color_equal(&fmt1->color, &fmt2->color);
 }
 
 static inline int ff_fmt_align(enum AVPixelFormat fmt)
-- 
2.52.0


>From aedede0cee249e32a7cd9712255d4d33f89e5858 Mon Sep 17 00:00:00 2001
From: Niklas Haas <[email protected]>
Date: Fri, 19 Jun 2026 14:25:02 +0200
Subject: [PATCH 10/16] swscale/format: add SwsFormat.field

This metadata is needed to compute the correct chroma sampling offsets.
We previously stored this in graph->field, but that's a bad place for it,
because it doesn't survive the translation to the ops abstraction layer.

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

diff --git a/libswscale/format.c b/libswscale/format.c
index c34d335500..a68565e8e5 100644
--- a/libswscale/format.c
+++ b/libswscale/format.c
@@ -388,6 +388,7 @@ SwsFormat ff_fmt_from_frame(const AVFrame *frame, int field)
     if (frame->flags & AV_FRAME_FLAG_INTERLACED) {
         fmt.height = (fmt.height + (field == FIELD_TOP)) >> 1;
         fmt.interlaced = 1;
+        fmt.field = field;
     }
 
     /* Set luminance and gamut information */
diff --git a/libswscale/format.h b/libswscale/format.h
index 24d53b8e80..9b852efd39 100644
--- a/libswscale/format.h
+++ b/libswscale/format.h
@@ -77,6 +77,7 @@ static inline void ff_color_update_dynamic(SwsColor *dst, 
const SwsColor *src)
 typedef struct SwsFormat {
     int width, height;
     int interlaced;
+    int field;
     enum AVPixelFormat format;
     enum AVPixelFormat hw_format;
     enum AVColorRange range;
@@ -126,6 +127,7 @@ static inline int ff_fmt_equal(const SwsFormat *fmt1, const 
SwsFormat *fmt2)
     return fmt1->width      == fmt2->width      &&
            fmt1->height     == fmt2->height     &&
            fmt1->interlaced == fmt2->interlaced &&
+           fmt1->field      == fmt2->field      &&
            fmt1->format     == fmt2->format     &&
            fmt1->range      == fmt2->range      &&
            fmt1->csp        == fmt2->csp        &&
-- 
2.52.0


>From 4653e68aaba6754cd63a8da4327113564a9a9d0b Mon Sep 17 00:00:00 2001
From: Niklas Haas <[email protected]>
Date: Fri, 19 Jun 2026 14:30:25 +0200
Subject: [PATCH 11/16] swscale/graph: nuke SwsGraph.field

No longer needed after the previous commit.

Sponsored-by: Sovereign Tech Fund
Signed-off-by: Niklas Haas <[email protected]>
---
 libswscale/graph.c      | 28 +++++++++++++++-------------
 libswscale/graph.h      |  7 +++----
 libswscale/swscale.c    |  2 +-
 libswscale/vulkan/ops.c |  2 +-
 4 files changed, 20 insertions(+), 19 deletions(-)

diff --git a/libswscale/graph.c b/libswscale/graph.c
index a765b4cd5c..73df6b8907 100644
--- a/libswscale/graph.c
+++ b/libswscale/graph.c
@@ -405,7 +405,7 @@ static void get_chroma_pos(SwsGraph *graph, int *h_chr_pos, 
int *v_chr_pos,
          * For 4x vertical subsampling (v_sub == 2), they are only placed
          * next to every *other* even row, so we need to shift by three luma
          * rows to get to the chroma sample. */
-        if (graph->field == FIELD_BOTTOM)
+        if (fmt->field == FIELD_BOTTOM)
             y_pos += (256 << sub_y) - 256;
 
         /* Luma row distance is doubled for fields, so halve offsets */
@@ -846,7 +846,7 @@ static void graph_uninit(SwsGraph *graph)
 }
 
 int ff_sws_graph_init(SwsGraph *graph, SwsContext *ctx, const SwsFormat *dst,
-                      const SwsFormat *src, int field)
+                      const SwsFormat *src)
 {
     int ret;
     if (graph->ctx) {
@@ -857,8 +857,9 @@ int ff_sws_graph_init(SwsGraph *graph, SwsContext *ctx, 
const SwsFormat *dst,
     graph->ctx = ctx;
     graph->src = *src;
     graph->dst = *dst;
-    graph->field = field;
     graph->opts_copy = *ctx;
+    av_assert0(src->interlaced == dst->interlaced);
+    av_assert0(src->field      == dst->field);
 
     if (ctx->threads == 1) {
         graph->num_threads = 1;
@@ -895,13 +896,13 @@ error:
 }
 
 int ff_sws_graph_create(SwsContext *ctx, const SwsFormat *dst, const SwsFormat 
*src,
-                        int field, SwsGraph **out_graph)
+                        SwsGraph **out_graph)
 {
     SwsGraph *graph = ff_sws_graph_alloc();
     if (!graph)
         return AVERROR(ENOMEM);
 
-    int ret = ff_sws_graph_init(graph, ctx, dst, src, field);
+    int ret = ff_sws_graph_init(graph, ctx, dst, src);
     if (ret < 0) {
         ff_sws_graph_free(&graph);
         return ret;
@@ -950,7 +951,7 @@ static int opts_equal(const SwsContext *c1, const 
SwsContext *c2)
 }
 
 int ff_sws_graph_reinit(SwsGraph *graph, SwsContext *ctx, const SwsFormat *dst,
-                        const SwsFormat *src, int field)
+                        const SwsFormat *src)
 {
     if (ff_fmt_equal(&graph->src, src) && ff_fmt_equal(&graph->dst, dst) &&
         opts_equal(ctx, &graph->opts_copy))
@@ -960,7 +961,7 @@ int ff_sws_graph_reinit(SwsGraph *graph, SwsContext *ctx, 
const SwsFormat *dst,
     }
 
     graph_uninit(graph);
-    return ff_sws_graph_init(graph, ctx, dst, src, field);
+    return ff_sws_graph_init(graph, ctx, dst, src);
 }
 
 void ff_sws_graph_update_metadata(SwsGraph *graph, const SwsColor *color)
@@ -971,16 +972,17 @@ void ff_sws_graph_update_metadata(SwsGraph *graph, const 
SwsColor *color)
     ff_color_update_dynamic(&graph->src.color, color);
 }
 
-static void get_field(SwsGraph *graph, const AVFrame *avframe, SwsFrame *frame)
+static void get_field(SwsGraph *graph, const SwsFormat *fmt,
+                      const AVFrame *avframe, SwsFrame *frame)
 {
     ff_sws_frame_from_avframe(frame, avframe);
 
     if (!(avframe->flags & AV_FRAME_FLAG_INTERLACED)) {
-        av_assert1(!graph->field);
+        av_assert1(!fmt->field);
         return;
     }
 
-    if (graph->field == FIELD_BOTTOM) {
+    if (fmt->field == FIELD_BOTTOM) {
         /* Odd rows, offset by one line */
         const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(frame->format);
         for (int i = 0; i < 4; i++) {
@@ -995,7 +997,7 @@ static void get_field(SwsGraph *graph, const AVFrame 
*avframe, SwsFrame *frame)
     for (int i = 0; i < 4; i++)
         frame->linesize[i] <<= 1;
 
-    frame->height = (frame->height + (graph->field == FIELD_TOP)) >> 1;
+    frame->height = (frame->height + (fmt->field == FIELD_TOP)) >> 1;
 }
 
 int ff_sws_graph_run(SwsGraph *graph, const AVFrame *dst, const AVFrame *src)
@@ -1004,8 +1006,8 @@ int ff_sws_graph_run(SwsGraph *graph, const AVFrame *dst, 
const AVFrame *src)
     av_assert0(src->format == graph->src.hw_format || src->format == 
graph->src.format);
 
     SwsFrame src_field, dst_field;
-    get_field(graph, dst, &dst_field);
-    get_field(graph, src, &src_field);
+    get_field(graph, &graph->dst, dst, &dst_field);
+    get_field(graph, &graph->src, src, &src_field);
 
     for (int i = 0; i < graph->num_passes; i++) {
         const SwsPass *pass = graph->passes[i];
diff --git a/libswscale/graph.h b/libswscale/graph.h
index eff2dcc47f..cb06f480cc 100644
--- a/libswscale/graph.h
+++ b/libswscale/graph.h
@@ -143,7 +143,6 @@ typedef struct SwsGraph {
      * Currently active format and processing parameters.
      */
     SwsFormat src, dst;
-    int field;
 
     /**
      * Temporary execution state inside ff_sws_graph_run(); used to pass
@@ -166,13 +165,13 @@ SwsGraph *ff_sws_graph_alloc(void);
  * negative error.
  */
 int ff_sws_graph_init(SwsGraph *graph, SwsContext *ctx, const SwsFormat *dst,
-                      const SwsFormat *src, int field);
+                      const SwsFormat *src);
 
 /**
  * Allocate and initialize the filter graph. Returns 0 or a negative error.
  */
 int ff_sws_graph_create(SwsContext *ctx, const SwsFormat *dst, const SwsFormat 
*src,
-                        int field, SwsGraph **out_graph);
+                        SwsGraph **out_graph);
 
 
 /**
@@ -223,7 +222,7 @@ void ff_sws_graph_update_metadata(SwsGraph *graph, const 
SwsColor *color);
  * will have no effect.
  */
 int ff_sws_graph_reinit(SwsGraph *graph, SwsContext *ctx, const SwsFormat *dst,
-                        const SwsFormat *src, int field);
+                        const SwsFormat *src);
 
 /**
  * Dispatch the filter graph on a single field of the given frames. Internally
diff --git a/libswscale/swscale.c b/libswscale/swscale.c
index 508967a13c..969456efcc 100644
--- a/libswscale/swscale.c
+++ b/libswscale/swscale.c
@@ -1527,7 +1527,7 @@ int sws_frame_setup(SwsContext *ctx, const AVFrame *dst, 
const AVFrame *src)
             }
         }
 
-        ret = ff_sws_graph_reinit(s->graph[field], ctx, &dst_fmt, &src_fmt, 
field);
+        ret = ff_sws_graph_reinit(s->graph[field], ctx, &dst_fmt, &src_fmt);
         if (ret < 0) {
             err_msg = "Failed initializing scaling graph";
             goto fail;
diff --git a/libswscale/vulkan/ops.c b/libswscale/vulkan/ops.c
index 1218fab2c7..9d5f201e69 100644
--- a/libswscale/vulkan/ops.c
+++ b/libswscale/vulkan/ops.c
@@ -153,7 +153,7 @@ static void process(const SwsFrame *dst, const SwsFrame 
*src, int y, int h,
     });
 
     if (p->interlaced) {
-        uint32_t field = pass->graph ? pass->graph->field : 0;
+        uint32_t field = pass->graph ? pass->graph->dst.field : 0;
         ff_vk_shader_update_push_const(&p->s->vkctx, ec, &p->shd,
                                        VK_SHADER_STAGE_COMPUTE_BIT,
                                        0, sizeof(field), &field);
-- 
2.52.0


>From 1f6dc79c807ab6044e8b4ef990386b2e9d9e918e Mon Sep 17 00:00:00 2001
From: Niklas Haas <[email protected]>
Date: Fri, 19 Jun 2026 15:07:24 +0200
Subject: [PATCH 12/16] swscale/format: factor out ff_sws_chroma_pos() helper

Moved here from graph.c, as it's needed for the new chroma scaling code.

Sponsored-by: Sovereign Tech Fund
Signed-off-by: Niklas Haas <[email protected]>
---
 libswscale/format.c | 41 ++++++++++++++++++++++++++++++++
 libswscale/format.h |  7 ++++++
 libswscale/graph.c  | 58 ++++++++++-----------------------------------
 3 files changed, 61 insertions(+), 45 deletions(-)

diff --git a/libswscale/format.c b/libswscale/format.c
index a68565e8e5..0538ab9db4 100644
--- a/libswscale/format.c
+++ b/libswscale/format.c
@@ -1393,6 +1393,47 @@ linear_mat3(const AVRational m00, const AVRational m01, 
const AVRational m02,
     return c;
 }
 
+void ff_sws_chroma_pos(const SwsFormat *fmt, bool *incomplete,
+                       int *out_x_pos, int *out_y_pos)
+{
+    enum AVChromaLocation chroma_loc = fmt->loc;
+    const int sub_x = fmt->desc->log2_chroma_w;
+    const int sub_y = fmt->desc->log2_chroma_h;
+    int x_pos, y_pos;
+
+    /* Explicitly default to center siting for compatibility with swscale */
+    if (chroma_loc == AVCHROMA_LOC_UNSPECIFIED) {
+        chroma_loc = AVCHROMA_LOC_CENTER;
+        *incomplete |= sub_x || sub_y;
+    }
+
+    /* av_chroma_location_enum_to_pos() always gives us values in the range 
from
+     * 0 to 256, but we need to adjust this to the true value range of the
+     * subsampling grid, which may be larger for h/v_sub > 1 */
+    av_chroma_location_enum_to_pos(&x_pos, &y_pos, chroma_loc);
+    x_pos *= (1 << sub_x) - 1;
+    y_pos *= (1 << sub_y) - 1;
+
+    /* Fix vertical chroma position for interlaced frames */
+    if (sub_y && fmt->interlaced) {
+        /* When vertically subsampling, chroma samples are effectively only
+         * placed next to even rows. To access them from the odd field, we need
+         * to account for this shift by offsetting the distance of one luma 
row.
+         *
+         * For 4x vertical subsampling (v_sub == 2), they are only placed
+         * next to every *other* even row, so we need to shift by three luma
+         * rows to get to the chroma sample. */
+        if (fmt->field == FIELD_BOTTOM)
+            y_pos += (256 << sub_y) - 256;
+
+        /* Luma row distance is doubled for fields, so halve offsets */
+        y_pos >>= 1;
+    }
+
+    *out_x_pos = x_pos;
+    *out_y_pos = y_pos;
+}
+
 int ff_sws_decode_colors(SwsContext *ctx, SwsPixelType type,
                          SwsOpList *ops, const SwsFormat *fmt, bool 
*incomplete)
 {
diff --git a/libswscale/format.h b/libswscale/format.h
index 9b852efd39..ea2ab7dc41 100644
--- a/libswscale/format.h
+++ b/libswscale/format.h
@@ -161,6 +161,13 @@ int ff_test_fmt(SwsBackend backends, const SwsFormat *fmt, 
int output);
 /* Returns true if the formats are incomplete, false otherwise */
 bool ff_infer_colors(SwsColor *src, SwsColor *dst);
 
+/**
+ * Wrapper around av_chroma_location_enum_to_pos() that accounts for
+ * the per-field offset introduced by interlacing.
+ */
+void ff_sws_chroma_pos(const SwsFormat *fmt, bool *incomplete,
+                       int *out_xpos, int *out_ypos);
+
 typedef struct SwsOpList SwsOpList;
 typedef enum SwsPixelType SwsPixelType;
 
diff --git a/libswscale/graph.c b/libswscale/graph.c
index 73df6b8907..a99cd7cadf 100644
--- a/libswscale/graph.c
+++ b/libswscale/graph.c
@@ -375,49 +375,6 @@ static void run_legacy_swscale(const SwsFrame *out, const 
SwsFrame *in,
                sws->src_h, out_data, out->linesize, y, h);
 }
 
-static void get_chroma_pos(SwsGraph *graph, int *h_chr_pos, int *v_chr_pos,
-                           const SwsFormat *fmt)
-{
-    enum AVChromaLocation chroma_loc = fmt->loc;
-    const int sub_x = fmt->desc->log2_chroma_w;
-    const int sub_y = fmt->desc->log2_chroma_h;
-    int x_pos, y_pos;
-
-    /* Explicitly default to center siting for compatibility with swscale */
-    if (chroma_loc == AVCHROMA_LOC_UNSPECIFIED) {
-        chroma_loc = AVCHROMA_LOC_CENTER;
-        graph->incomplete |= sub_x || sub_y;
-    }
-
-    /* av_chroma_location_enum_to_pos() always gives us values in the range 
from
-     * 0 to 256, but we need to adjust this to the true value range of the
-     * subsampling grid, which may be larger for h/v_sub > 1 */
-    av_chroma_location_enum_to_pos(&x_pos, &y_pos, chroma_loc);
-    x_pos *= (1 << sub_x) - 1;
-    y_pos *= (1 << sub_y) - 1;
-
-    /* Fix vertical chroma position for interlaced frames */
-    if (sub_y && fmt->interlaced) {
-        /* When vertically subsampling, chroma samples are effectively only
-         * placed next to even rows. To access them from the odd field, we need
-         * to account for this shift by offsetting the distance of one luma 
row.
-         *
-         * For 4x vertical subsampling (v_sub == 2), they are only placed
-         * next to every *other* even row, so we need to shift by three luma
-         * rows to get to the chroma sample. */
-        if (fmt->field == FIELD_BOTTOM)
-            y_pos += (256 << sub_y) - 256;
-
-        /* Luma row distance is doubled for fields, so halve offsets */
-        y_pos >>= 1;
-    }
-
-    /* Explicitly strip chroma offsets when not subsampling, because it
-     * interferes with the operation of flags like SWS_FULL_CHR_H_INP */
-    *h_chr_pos = sub_x ? x_pos : -513;
-    *v_chr_pos = sub_y ? y_pos : -513;
-}
-
 static void legacy_chr_pos(SwsGraph *graph, int *chr_pos, int override, int 
*warned)
 {
     if (override == -513 || override == *chr_pos)
@@ -582,8 +539,8 @@ static int add_legacy_sws_pass(SwsGraph *graph, const 
SwsFormat *src,
     sws->dst_h      = dst->height;
     sws->dst_format = dst->format;
     sws->dst_range  = dst->range == AVCOL_RANGE_JPEG;
-    get_chroma_pos(graph, &sws->src_h_chr_pos, &sws->src_v_chr_pos, src);
-    get_chroma_pos(graph, &sws->dst_h_chr_pos, &sws->dst_v_chr_pos, dst);
+    ff_sws_chroma_pos(src, &graph->incomplete, &sws->src_h_chr_pos, 
&sws->src_v_chr_pos);
+    ff_sws_chroma_pos(dst, &graph->incomplete, &sws->dst_h_chr_pos, 
&sws->dst_v_chr_pos);
 
     graph->incomplete |= src->range == AVCOL_RANGE_UNSPECIFIED;
     graph->incomplete |= dst->range == AVCOL_RANGE_UNSPECIFIED;
@@ -594,6 +551,17 @@ static int add_legacy_sws_pass(SwsGraph *graph, const 
SwsFormat *src,
     legacy_chr_pos(graph, &sws->dst_h_chr_pos, ctx->dst_h_chr_pos, &warned);
     legacy_chr_pos(graph, &sws->dst_v_chr_pos, ctx->dst_v_chr_pos, &warned);
 
+    /* Explicitly strip chroma offsets when not subsampling, because it
+     * interferes with the operation of flags like SWS_FULL_CHR_H_INP */
+    if (!src->desc->log2_chroma_w)
+        sws->src_h_chr_pos = -513;
+    if (!src->desc->log2_chroma_h)
+        sws->src_v_chr_pos = -513;
+    if (!dst->desc->log2_chroma_w)
+        sws->dst_h_chr_pos = -513;
+    if (!dst->desc->log2_chroma_h)
+        sws->dst_v_chr_pos = -513;
+
     for (int i = 0; i < SWS_NUM_SCALER_PARAMS; i++)
         sws->scaler_params[i] = ctx->scaler_params[i];
 
-- 
2.52.0


>From 8215e9bbea07173b59e842a860df58aca18ff01a Mon Sep 17 00:00:00 2001
From: Niklas Haas <[email protected]>
Date: Mon, 8 Jun 2026 14:44:01 +0200
Subject: [PATCH 13/16] swscale/filters: add option for adding an input pixel
 offset

This is needed for chroma subsampling, which requires a different filter
offset for chroma subsamples (according to the frame's chroma location).

Sponsored-by: Sovereign Tech Fund
Signed-off-by: Niklas Haas <[email protected]>
---
 libswscale/filters.c | 3 ++-
 libswscale/filters.h | 8 ++++++++
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/libswscale/filters.c b/libswscale/filters.c
index 7e8865659e..81a388e692 100644
--- a/libswscale/filters.c
+++ b/libswscale/filters.c
@@ -75,7 +75,7 @@ static void compute_row(SwsFilterWeights *f, const 
SwsFilterFunction *fun,
      * the entire square from (0,0) to (1,1). When normalizing between 
different
      * image sizes, we therefore need to add/subtract off these 0.5 offsets.
      */
-    const double src_pos = (dst_pos + 0.5) * ratio_inv - 0.5;
+    const double src_pos = (dst_pos + 0.5) * ratio_inv - 0.5 + f->offset;
     if (f->filter_size == 1) {
         *pos = fmin(fmax(round(src_pos), 0.0), f->src_size - 1);
         *out = SWS_FILTER_SCALE;
@@ -257,6 +257,7 @@ int ff_sws_filter_generate(void *log, const SwsFilterParams 
*params,
     memcpy(filter->name, fun.name, sizeof(filter->name));
     filter->src_size = params->src_size;
     filter->dst_size = params->dst_size;
+    filter->offset = params->offset;
     filter->filter_size = filter_size;
     if (filter->filter_size == 1)
         filter->sum_positive = SWS_FILTER_SCALE;
diff --git a/libswscale/filters.h b/libswscale/filters.h
index 1bfdb196b8..143fc2c5e3 100644
--- a/libswscale/filters.h
+++ b/libswscale/filters.h
@@ -56,6 +56,13 @@ typedef struct SwsFilterParams {
      */
     int src_size;
     int dst_size;
+
+    /**
+     * The sample offset, in units of input pixels. This is added onto all
+     * sampled coordinates directly, i.e. a value of offset = 1.0 would shift
+     * the output to the top/left by one whole source pixel.
+     */
+    double offset;
 } SwsFilterParams;
 
 /**
@@ -88,6 +95,7 @@ typedef struct SwsFilterWeights {
      */
     int src_size;
     int dst_size;
+    double offset;
 
     /**
      * Extra metadata about the filter, used to inform the optimizer / range
-- 
2.52.0


>From fa1ca69a8bde7a74e7c01777c75bb7c7e0754ee3 Mon Sep 17 00:00:00 2001
From: Niklas Haas <[email protected]>
Date: Fri, 19 Jun 2026 15:36:08 +0200
Subject: [PATCH 14/16] swscale/filters: add ability to set a virtual output
 size

Odd-size luma planes are not exact multiples of the chroma plane; but the
sample grid is still matched as though it were. We need to account for this
when translating a luma sample to the corresponding chroma sample coordinates.

Sponsored-by: Sovereign Tech Fund
Signed-off-by: Niklas Haas <[email protected]>
---
 libswscale/filters.c |  7 ++++++-
 libswscale/filters.h | 15 +++++++++++++++
 2 files changed, 21 insertions(+), 1 deletion(-)

diff --git a/libswscale/filters.c b/libswscale/filters.c
index 81a388e692..fb54d2bbd8 100644
--- a/libswscale/filters.c
+++ b/libswscale/filters.c
@@ -194,7 +194,11 @@ int ff_sws_filter_generate(void *log, const 
SwsFilterParams *params,
     if (scaler == SWS_SCALE_AUTO)
         scaler = SWS_SCALE_BICUBIC;
 
-    const double ratio = (double) params->dst_size / params->src_size;
+    double virtual_size = params->virtual_size;
+    if (!virtual_size)
+        virtual_size = params->dst_size;
+
+    const double ratio = virtual_size / params->src_size;
     double stretch = 1.0;
     if (ratio < 1.0 && scaler != SWS_SCALE_POINT) {
         /* Widen filter for downscaling (anti-aliasing) */
@@ -257,6 +261,7 @@ int ff_sws_filter_generate(void *log, const SwsFilterParams 
*params,
     memcpy(filter->name, fun.name, sizeof(filter->name));
     filter->src_size = params->src_size;
     filter->dst_size = params->dst_size;
+    filter->virtual_size = virtual_size;
     filter->offset = params->offset;
     filter->filter_size = filter_size;
     if (filter->filter_size == 1)
diff --git a/libswscale/filters.h b/libswscale/filters.h
index 143fc2c5e3..a10e6f3964 100644
--- a/libswscale/filters.h
+++ b/libswscale/filters.h
@@ -57,6 +57,20 @@ typedef struct SwsFilterParams {
     int src_size;
     int dst_size;
 
+    /**
+     * The virtual output size. If zero, this is assumed to be the same as
+     * `dst_size`. Matters for e.g. chroma subsampling, where the the luma
+     * plane may be smaller than the dst_size. For example, a 99x99 input
+     * image has a chroma size of 50x50, which would be 100x100 after
+     * chroma upscaling; but is sampled only at 99x99 resolution. In this
+     * instance, dst_size is 99x99 and virtual_size is 100x100.
+     *
+     * The upscaling offset from this shift is implicit and does not need
+     * to be accounted for in `offset`. In other words, `offset` is taken
+     * relative to the virtual size, not the sampled size.
+     */
+    double virtual_size;
+
     /**
      * The sample offset, in units of input pixels. This is added onto all
      * sampled coordinates directly, i.e. a value of offset = 1.0 would shift
@@ -95,6 +109,7 @@ typedef struct SwsFilterWeights {
      */
     int src_size;
     int dst_size;
+    double virtual_size;
     double offset;
 
     /**
-- 
2.52.0


>From 8cc6b2ddafe184cf544a0a10a954570740e94912 Mon Sep 17 00:00:00 2001
From: Niklas Haas <[email protected]>
Date: Fri, 19 Jun 2026 16:30:28 +0200
Subject: [PATCH 15/16] swscale/tests/swscale: fix unscaled subsampled chroma
 format check

This should be matching against the *chroma* scaler, not the main scaler.
Of course, under normal circumstances, scaler_sub matches scaler, but this
allows users to explicitly override this defaulting by setting e.g.

-scaler none -scaler_sub bicubic

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

diff --git a/libswscale/tests/swscale.c b/libswscale/tests/swscale.c
index b5b8faeeff..6de9327ba9 100644
--- a/libswscale/tests/swscale.c
+++ b/libswscale/tests/swscale.c
@@ -691,8 +691,9 @@ static inline int fmt_is_supported_by_hw(enum AVPixelFormat 
fmt)
 
 static inline int fmt_disabled(const struct options *opts, enum AVPixelFormat 
fmt)
 {
+    const int scaler_sub = opts->scaler_sub ? opts->scaler_sub : opts->scaler;
     return (hw_device_constr && !fmt_is_supported_by_hw(fmt)) ||
-           (opts->scaler < 0 && fmt_is_subsampled(fmt));
+           (scaler_sub < 0 && fmt_is_subsampled(fmt));
 }
 
 static inline int test_formats(const struct options *opts,
-- 
2.52.0


>From b3689e792fdbaaac690ffb98e03dc75ca56483a6 Mon Sep 17 00:00:00 2001
From: Niklas Haas <[email protected]>
Date: Sat, 20 Jun 2026 02:56:18 +0200
Subject: [PATCH 16/16] swscale/uops: simplify permute naming scheme

We also drop the useless/unused mask from the permute ops.

Avoids a bunch of otherwise duplicate permute ops. Now that this is
handled by SWS_UOP_MOVE for x86, there is no downside to this.

The FATE change is a pure rename of the uops dumps.

Sponsored-by: Sovereign Tech Fund
Signed-off-by: Niklas Haas <[email protected]>
---
 libswscale/uops.c           |  22 ++-
 libswscale/uops_macros.h    | 258 ++++++++++++++----------------------
 tests/ref/fate/sws-ops-list |   2 +-
 3 files changed, 112 insertions(+), 170 deletions(-)

diff --git a/libswscale/uops.c b/libswscale/uops.c
index 1bd3e2f763..a0bbf5ddbc 100644
--- a/libswscale/uops.c
+++ b/libswscale/uops.c
@@ -155,6 +155,10 @@ void ff_sws_uop_name(const SwsUOp *op, char 
buf[SWS_UOP_NAME_MAX])
         av_bprintf(&bp, "_%u", par->shift.amount);
         break;
     case SWS_UOP_PERMUTE:
+        av_bprint_chars(&bp, '_', 1);
+        for (int i = 0; i < 4; i++)
+            av_bprint_chars(&bp, "xyzw"[par->swizzle.in[i]], 1);
+        break;
     case SWS_UOP_COPY:
         av_bprint_chars(&bp, '_', 1);
         for (int i = 0; i < 4; i++) {
@@ -597,13 +601,13 @@ static int translate_swizzle(SwsUOpList *ops, SwsUOpFlags 
flags, const SwsOp *op
     SwsUOp uop = {
         .type = pixel_type_to_int(op->type),
         .uop  = SWS_UOP_PERMUTE,
-        .mask = ff_sws_comp_mask_needed(op),
         .par.swizzle.in = {0, 1, 2, 3},
     };
 
+    SwsCompMask needed = ff_sws_comp_mask_needed(op);
     SwsCompMask seen = 0;
     for (int i = 0; i < 4; i++) {
-        if (!SWS_COMP_TEST(uop.mask, i))
+        if (!SWS_COMP_TEST(needed, i))
             continue;
         const int src = op->swizzle.in[i];
         if (SWS_COMP_TEST(seen, src))
@@ -615,7 +619,7 @@ static int translate_swizzle(SwsUOpList *ops, SwsUOpFlags 
flags, const SwsOp *op
     if (uop.uop == SWS_UOP_PERMUTE) {
         /* Prevent overlap by moving unused components to unseen indices */
         for (int i = 0; i < 4; i++) {
-            if (SWS_COMP_TEST(uop.mask, i))
+            if (SWS_COMP_TEST(needed, i))
                 continue;
 
             /* Prefer identity mapping if possible */
@@ -634,10 +638,14 @@ static int translate_swizzle(SwsUOpList *ops, SwsUOpFlags 
flags, const SwsOp *op
         }
     }
 
-    /* Remove remaining trivial / identity components from the mask */
-    for (int i = 0; i < 4; i++) {
-        if (uop.par.swizzle.in[i] == i)
-            uop.mask &= ~SWS_COMP(i);
+    if (uop.uop == SWS_UOP_COPY) {
+        /* Remove remaining trivial / identity components from the mask */
+        for (int i = 0; i < 4; i++) {
+            if (uop.par.swizzle.in[i] == i)
+                needed &= ~SWS_COMP(i);
+        }
+
+        uop.mask = needed;
     }
 
     return ff_sws_uop_list_append(ops, &uop);
diff --git a/libswscale/uops_macros.h b/libswscale/uops_macros.h
index 5d9e1a8026..77a4900248 100644
--- a/libswscale/uops_macros.h
+++ b/libswscale/uops_macros.h
@@ -102,67 +102,43 @@
 #define SWS_FOR_STRUCT_U8_WRITE_BIT(MACRO, ...) \
     MACRO(__VA_ARGS__, u8_write_bit_x                          , .type = 
SWS_PIXEL_U8 , .uop = SWS_UOP_WRITE_BIT       , .mask = 0x1)
 #define SWS_FOR_U8_PERMUTE(MACRO, ...) \
-    MACRO(__VA_ARGS__, u8_permute_x_y                          , SWS_PIXEL_U8 
, SWS_UOP_PERMUTE         , 0x1, 1, 0, 2, 3) \
-    MACRO(__VA_ARGS__, u8_permute_x_z                          , SWS_PIXEL_U8 
, SWS_UOP_PERMUTE         , 0x1, 2, 1, 0, 3) \
-    MACRO(__VA_ARGS__, u8_permute_x_w                          , SWS_PIXEL_U8 
, SWS_UOP_PERMUTE         , 0x1, 3, 1, 2, 0) \
-    MACRO(__VA_ARGS__, u8_permute_y_w                          , SWS_PIXEL_U8 
, SWS_UOP_PERMUTE         , 0x2, 0, 3, 2, 1) \
-    MACRO(__VA_ARGS__, u8_permute_y_x                          , SWS_PIXEL_U8 
, SWS_UOP_PERMUTE         , 0x2, 1, 0, 2, 3) \
-    MACRO(__VA_ARGS__, u8_permute_xy_yx                        , SWS_PIXEL_U8 
, SWS_UOP_PERMUTE         , 0x3, 1, 0, 2, 3) \
-    MACRO(__VA_ARGS__, u8_permute_xy_yw                        , SWS_PIXEL_U8 
, SWS_UOP_PERMUTE         , 0x3, 1, 3, 2, 0) \
-    MACRO(__VA_ARGS__, u8_permute_xy_zw                        , SWS_PIXEL_U8 
, SWS_UOP_PERMUTE         , 0x3, 2, 3, 0, 1) \
-    MACRO(__VA_ARGS__, u8_permute_xy_wx                        , SWS_PIXEL_U8 
, SWS_UOP_PERMUTE         , 0x3, 3, 0, 2, 1) \
-    MACRO(__VA_ARGS__, u8_permute_z_x                          , SWS_PIXEL_U8 
, SWS_UOP_PERMUTE         , 0x4, 1, 2, 0, 3) \
-    MACRO(__VA_ARGS__, u8_permute_xz_zx                        , SWS_PIXEL_U8 
, SWS_UOP_PERMUTE         , 0x5, 2, 1, 0, 3) \
-    MACRO(__VA_ARGS__, u8_permute_yz_zy                        , SWS_PIXEL_U8 
, SWS_UOP_PERMUTE         , 0x6, 0, 2, 1, 3) \
-    MACRO(__VA_ARGS__, u8_permute_xyz_yzx                      , SWS_PIXEL_U8 
, SWS_UOP_PERMUTE         , 0x7, 1, 2, 0, 3) \
-    MACRO(__VA_ARGS__, u8_permute_xyz_yzw                      , SWS_PIXEL_U8 
, SWS_UOP_PERMUTE         , 0x7, 1, 2, 3, 0) \
-    MACRO(__VA_ARGS__, u8_permute_xyz_zxy                      , SWS_PIXEL_U8 
, SWS_UOP_PERMUTE         , 0x7, 2, 0, 1, 3) \
-    MACRO(__VA_ARGS__, u8_permute_xyz_zwy                      , SWS_PIXEL_U8 
, SWS_UOP_PERMUTE         , 0x7, 2, 3, 1, 0) \
-    MACRO(__VA_ARGS__, u8_permute_xyz_wzy                      , SWS_PIXEL_U8 
, SWS_UOP_PERMUTE         , 0x7, 3, 2, 1, 0) \
-    MACRO(__VA_ARGS__, u8_permute_w_x                          , SWS_PIXEL_U8 
, SWS_UOP_PERMUTE         , 0x8, 3, 1, 2, 0) \
-    MACRO(__VA_ARGS__, u8_permute_yw_wy                        , SWS_PIXEL_U8 
, SWS_UOP_PERMUTE         , 0xa, 0, 3, 2, 1) \
-    MACRO(__VA_ARGS__, u8_permute_zw_xz                        , SWS_PIXEL_U8 
, SWS_UOP_PERMUTE         , 0xc, 3, 1, 0, 2) \
-    MACRO(__VA_ARGS__, u8_permute_xzw_zwx                      , SWS_PIXEL_U8 
, SWS_UOP_PERMUTE         , 0xd, 2, 1, 3, 0) \
-    MACRO(__VA_ARGS__, u8_permute_xzw_wxz                      , SWS_PIXEL_U8 
, SWS_UOP_PERMUTE         , 0xd, 3, 1, 0, 2) \
-    MACRO(__VA_ARGS__, u8_permute_yzw_zwy                      , SWS_PIXEL_U8 
, SWS_UOP_PERMUTE         , 0xe, 0, 2, 3, 1) \
-    MACRO(__VA_ARGS__, u8_permute_yzw_xyz                      , SWS_PIXEL_U8 
, SWS_UOP_PERMUTE         , 0xe, 3, 0, 1, 2) \
-    MACRO(__VA_ARGS__, u8_permute_yzw_zxy                      , SWS_PIXEL_U8 
, SWS_UOP_PERMUTE         , 0xe, 3, 2, 0, 1) \
-    MACRO(__VA_ARGS__, u8_permute_yzw_zyx                      , SWS_PIXEL_U8 
, SWS_UOP_PERMUTE         , 0xe, 3, 2, 1, 0) \
-    MACRO(__VA_ARGS__, u8_permute_xyzw_yzwx                    , SWS_PIXEL_U8 
, SWS_UOP_PERMUTE         , 0xf, 1, 2, 3, 0) \
-    MACRO(__VA_ARGS__, u8_permute_xyzw_wxyz                    , SWS_PIXEL_U8 
, SWS_UOP_PERMUTE         , 0xf, 3, 0, 1, 2) \
-    MACRO(__VA_ARGS__, u8_permute_xyzw_wzxy                    , SWS_PIXEL_U8 
, SWS_UOP_PERMUTE         , 0xf, 3, 2, 0, 1) \
-    MACRO(__VA_ARGS__, u8_permute_xyzw_wzyx                    , SWS_PIXEL_U8 
, SWS_UOP_PERMUTE         , 0xf, 3, 2, 1, 0)
+    MACRO(__VA_ARGS__, u8_permute_xzyw                         , SWS_PIXEL_U8 
, SWS_UOP_PERMUTE         , 0x0, 0, 2, 1, 3) \
+    MACRO(__VA_ARGS__, u8_permute_xzwy                         , SWS_PIXEL_U8 
, SWS_UOP_PERMUTE         , 0x0, 0, 2, 3, 1) \
+    MACRO(__VA_ARGS__, u8_permute_xwzy                         , SWS_PIXEL_U8 
, SWS_UOP_PERMUTE         , 0x0, 0, 3, 2, 1) \
+    MACRO(__VA_ARGS__, u8_permute_yxzw                         , SWS_PIXEL_U8 
, SWS_UOP_PERMUTE         , 0x0, 1, 0, 2, 3) \
+    MACRO(__VA_ARGS__, u8_permute_yzxw                         , SWS_PIXEL_U8 
, SWS_UOP_PERMUTE         , 0x0, 1, 2, 0, 3) \
+    MACRO(__VA_ARGS__, u8_permute_yzwx                         , SWS_PIXEL_U8 
, SWS_UOP_PERMUTE         , 0x0, 1, 2, 3, 0) \
+    MACRO(__VA_ARGS__, u8_permute_ywzx                         , SWS_PIXEL_U8 
, SWS_UOP_PERMUTE         , 0x0, 1, 3, 2, 0) \
+    MACRO(__VA_ARGS__, u8_permute_zxyw                         , SWS_PIXEL_U8 
, SWS_UOP_PERMUTE         , 0x0, 2, 0, 1, 3) \
+    MACRO(__VA_ARGS__, u8_permute_zyxw                         , SWS_PIXEL_U8 
, SWS_UOP_PERMUTE         , 0x0, 2, 1, 0, 3) \
+    MACRO(__VA_ARGS__, u8_permute_zywx                         , SWS_PIXEL_U8 
, SWS_UOP_PERMUTE         , 0x0, 2, 1, 3, 0) \
+    MACRO(__VA_ARGS__, u8_permute_zwxy                         , SWS_PIXEL_U8 
, SWS_UOP_PERMUTE         , 0x0, 2, 3, 0, 1) \
+    MACRO(__VA_ARGS__, u8_permute_zwyx                         , SWS_PIXEL_U8 
, SWS_UOP_PERMUTE         , 0x0, 2, 3, 1, 0) \
+    MACRO(__VA_ARGS__, u8_permute_wxyz                         , SWS_PIXEL_U8 
, SWS_UOP_PERMUTE         , 0x0, 3, 0, 1, 2) \
+    MACRO(__VA_ARGS__, u8_permute_wxzy                         , SWS_PIXEL_U8 
, SWS_UOP_PERMUTE         , 0x0, 3, 0, 2, 1) \
+    MACRO(__VA_ARGS__, u8_permute_wyxz                         , SWS_PIXEL_U8 
, SWS_UOP_PERMUTE         , 0x0, 3, 1, 0, 2) \
+    MACRO(__VA_ARGS__, u8_permute_wyzx                         , SWS_PIXEL_U8 
, SWS_UOP_PERMUTE         , 0x0, 3, 1, 2, 0) \
+    MACRO(__VA_ARGS__, u8_permute_wzxy                         , SWS_PIXEL_U8 
, SWS_UOP_PERMUTE         , 0x0, 3, 2, 0, 1) \
+    MACRO(__VA_ARGS__, u8_permute_wzyx                         , SWS_PIXEL_U8 
, SWS_UOP_PERMUTE         , 0x0, 3, 2, 1, 0)
 #define SWS_FOR_STRUCT_U8_PERMUTE(MACRO, ...) \
-    MACRO(__VA_ARGS__, u8_permute_x_y                          , .type = 
SWS_PIXEL_U8 , .uop = SWS_UOP_PERMUTE         , .mask = 0x1, .par.swizzle.in = 
{1, 0, 2, 3}) \
-    MACRO(__VA_ARGS__, u8_permute_x_z                          , .type = 
SWS_PIXEL_U8 , .uop = SWS_UOP_PERMUTE         , .mask = 0x1, .par.swizzle.in = 
{2, 1, 0, 3}) \
-    MACRO(__VA_ARGS__, u8_permute_x_w                          , .type = 
SWS_PIXEL_U8 , .uop = SWS_UOP_PERMUTE         , .mask = 0x1, .par.swizzle.in = 
{3, 1, 2, 0}) \
-    MACRO(__VA_ARGS__, u8_permute_y_w                          , .type = 
SWS_PIXEL_U8 , .uop = SWS_UOP_PERMUTE         , .mask = 0x2, .par.swizzle.in = 
{0, 3, 2, 1}) \
-    MACRO(__VA_ARGS__, u8_permute_y_x                          , .type = 
SWS_PIXEL_U8 , .uop = SWS_UOP_PERMUTE         , .mask = 0x2, .par.swizzle.in = 
{1, 0, 2, 3}) \
-    MACRO(__VA_ARGS__, u8_permute_xy_yx                        , .type = 
SWS_PIXEL_U8 , .uop = SWS_UOP_PERMUTE         , .mask = 0x3, .par.swizzle.in = 
{1, 0, 2, 3}) \
-    MACRO(__VA_ARGS__, u8_permute_xy_yw                        , .type = 
SWS_PIXEL_U8 , .uop = SWS_UOP_PERMUTE         , .mask = 0x3, .par.swizzle.in = 
{1, 3, 2, 0}) \
-    MACRO(__VA_ARGS__, u8_permute_xy_zw                        , .type = 
SWS_PIXEL_U8 , .uop = SWS_UOP_PERMUTE         , .mask = 0x3, .par.swizzle.in = 
{2, 3, 0, 1}) \
-    MACRO(__VA_ARGS__, u8_permute_xy_wx                        , .type = 
SWS_PIXEL_U8 , .uop = SWS_UOP_PERMUTE         , .mask = 0x3, .par.swizzle.in = 
{3, 0, 2, 1}) \
-    MACRO(__VA_ARGS__, u8_permute_z_x                          , .type = 
SWS_PIXEL_U8 , .uop = SWS_UOP_PERMUTE         , .mask = 0x4, .par.swizzle.in = 
{1, 2, 0, 3}) \
-    MACRO(__VA_ARGS__, u8_permute_xz_zx                        , .type = 
SWS_PIXEL_U8 , .uop = SWS_UOP_PERMUTE         , .mask = 0x5, .par.swizzle.in = 
{2, 1, 0, 3}) \
-    MACRO(__VA_ARGS__, u8_permute_yz_zy                        , .type = 
SWS_PIXEL_U8 , .uop = SWS_UOP_PERMUTE         , .mask = 0x6, .par.swizzle.in = 
{0, 2, 1, 3}) \
-    MACRO(__VA_ARGS__, u8_permute_xyz_yzx                      , .type = 
SWS_PIXEL_U8 , .uop = SWS_UOP_PERMUTE         , .mask = 0x7, .par.swizzle.in = 
{1, 2, 0, 3}) \
-    MACRO(__VA_ARGS__, u8_permute_xyz_yzw                      , .type = 
SWS_PIXEL_U8 , .uop = SWS_UOP_PERMUTE         , .mask = 0x7, .par.swizzle.in = 
{1, 2, 3, 0}) \
-    MACRO(__VA_ARGS__, u8_permute_xyz_zxy                      , .type = 
SWS_PIXEL_U8 , .uop = SWS_UOP_PERMUTE         , .mask = 0x7, .par.swizzle.in = 
{2, 0, 1, 3}) \
-    MACRO(__VA_ARGS__, u8_permute_xyz_zwy                      , .type = 
SWS_PIXEL_U8 , .uop = SWS_UOP_PERMUTE         , .mask = 0x7, .par.swizzle.in = 
{2, 3, 1, 0}) \
-    MACRO(__VA_ARGS__, u8_permute_xyz_wzy                      , .type = 
SWS_PIXEL_U8 , .uop = SWS_UOP_PERMUTE         , .mask = 0x7, .par.swizzle.in = 
{3, 2, 1, 0}) \
-    MACRO(__VA_ARGS__, u8_permute_w_x                          , .type = 
SWS_PIXEL_U8 , .uop = SWS_UOP_PERMUTE         , .mask = 0x8, .par.swizzle.in = 
{3, 1, 2, 0}) \
-    MACRO(__VA_ARGS__, u8_permute_yw_wy                        , .type = 
SWS_PIXEL_U8 , .uop = SWS_UOP_PERMUTE         , .mask = 0xa, .par.swizzle.in = 
{0, 3, 2, 1}) \
-    MACRO(__VA_ARGS__, u8_permute_zw_xz                        , .type = 
SWS_PIXEL_U8 , .uop = SWS_UOP_PERMUTE         , .mask = 0xc, .par.swizzle.in = 
{3, 1, 0, 2}) \
-    MACRO(__VA_ARGS__, u8_permute_xzw_zwx                      , .type = 
SWS_PIXEL_U8 , .uop = SWS_UOP_PERMUTE         , .mask = 0xd, .par.swizzle.in = 
{2, 1, 3, 0}) \
-    MACRO(__VA_ARGS__, u8_permute_xzw_wxz                      , .type = 
SWS_PIXEL_U8 , .uop = SWS_UOP_PERMUTE         , .mask = 0xd, .par.swizzle.in = 
{3, 1, 0, 2}) \
-    MACRO(__VA_ARGS__, u8_permute_yzw_zwy                      , .type = 
SWS_PIXEL_U8 , .uop = SWS_UOP_PERMUTE         , .mask = 0xe, .par.swizzle.in = 
{0, 2, 3, 1}) \
-    MACRO(__VA_ARGS__, u8_permute_yzw_xyz                      , .type = 
SWS_PIXEL_U8 , .uop = SWS_UOP_PERMUTE         , .mask = 0xe, .par.swizzle.in = 
{3, 0, 1, 2}) \
-    MACRO(__VA_ARGS__, u8_permute_yzw_zxy                      , .type = 
SWS_PIXEL_U8 , .uop = SWS_UOP_PERMUTE         , .mask = 0xe, .par.swizzle.in = 
{3, 2, 0, 1}) \
-    MACRO(__VA_ARGS__, u8_permute_yzw_zyx                      , .type = 
SWS_PIXEL_U8 , .uop = SWS_UOP_PERMUTE         , .mask = 0xe, .par.swizzle.in = 
{3, 2, 1, 0}) \
-    MACRO(__VA_ARGS__, u8_permute_xyzw_yzwx                    , .type = 
SWS_PIXEL_U8 , .uop = SWS_UOP_PERMUTE         , .mask = 0xf, .par.swizzle.in = 
{1, 2, 3, 0}) \
-    MACRO(__VA_ARGS__, u8_permute_xyzw_wxyz                    , .type = 
SWS_PIXEL_U8 , .uop = SWS_UOP_PERMUTE         , .mask = 0xf, .par.swizzle.in = 
{3, 0, 1, 2}) \
-    MACRO(__VA_ARGS__, u8_permute_xyzw_wzxy                    , .type = 
SWS_PIXEL_U8 , .uop = SWS_UOP_PERMUTE         , .mask = 0xf, .par.swizzle.in = 
{3, 2, 0, 1}) \
-    MACRO(__VA_ARGS__, u8_permute_xyzw_wzyx                    , .type = 
SWS_PIXEL_U8 , .uop = SWS_UOP_PERMUTE         , .mask = 0xf, .par.swizzle.in = 
{3, 2, 1, 0})
+    MACRO(__VA_ARGS__, u8_permute_xzyw                         , .type = 
SWS_PIXEL_U8 , .uop = SWS_UOP_PERMUTE         , .mask = 0x0, .par.swizzle.in = 
{0, 2, 1, 3}) \
+    MACRO(__VA_ARGS__, u8_permute_xzwy                         , .type = 
SWS_PIXEL_U8 , .uop = SWS_UOP_PERMUTE         , .mask = 0x0, .par.swizzle.in = 
{0, 2, 3, 1}) \
+    MACRO(__VA_ARGS__, u8_permute_xwzy                         , .type = 
SWS_PIXEL_U8 , .uop = SWS_UOP_PERMUTE         , .mask = 0x0, .par.swizzle.in = 
{0, 3, 2, 1}) \
+    MACRO(__VA_ARGS__, u8_permute_yxzw                         , .type = 
SWS_PIXEL_U8 , .uop = SWS_UOP_PERMUTE         , .mask = 0x0, .par.swizzle.in = 
{1, 0, 2, 3}) \
+    MACRO(__VA_ARGS__, u8_permute_yzxw                         , .type = 
SWS_PIXEL_U8 , .uop = SWS_UOP_PERMUTE         , .mask = 0x0, .par.swizzle.in = 
{1, 2, 0, 3}) \
+    MACRO(__VA_ARGS__, u8_permute_yzwx                         , .type = 
SWS_PIXEL_U8 , .uop = SWS_UOP_PERMUTE         , .mask = 0x0, .par.swizzle.in = 
{1, 2, 3, 0}) \
+    MACRO(__VA_ARGS__, u8_permute_ywzx                         , .type = 
SWS_PIXEL_U8 , .uop = SWS_UOP_PERMUTE         , .mask = 0x0, .par.swizzle.in = 
{1, 3, 2, 0}) \
+    MACRO(__VA_ARGS__, u8_permute_zxyw                         , .type = 
SWS_PIXEL_U8 , .uop = SWS_UOP_PERMUTE         , .mask = 0x0, .par.swizzle.in = 
{2, 0, 1, 3}) \
+    MACRO(__VA_ARGS__, u8_permute_zyxw                         , .type = 
SWS_PIXEL_U8 , .uop = SWS_UOP_PERMUTE         , .mask = 0x0, .par.swizzle.in = 
{2, 1, 0, 3}) \
+    MACRO(__VA_ARGS__, u8_permute_zywx                         , .type = 
SWS_PIXEL_U8 , .uop = SWS_UOP_PERMUTE         , .mask = 0x0, .par.swizzle.in = 
{2, 1, 3, 0}) \
+    MACRO(__VA_ARGS__, u8_permute_zwxy                         , .type = 
SWS_PIXEL_U8 , .uop = SWS_UOP_PERMUTE         , .mask = 0x0, .par.swizzle.in = 
{2, 3, 0, 1}) \
+    MACRO(__VA_ARGS__, u8_permute_zwyx                         , .type = 
SWS_PIXEL_U8 , .uop = SWS_UOP_PERMUTE         , .mask = 0x0, .par.swizzle.in = 
{2, 3, 1, 0}) \
+    MACRO(__VA_ARGS__, u8_permute_wxyz                         , .type = 
SWS_PIXEL_U8 , .uop = SWS_UOP_PERMUTE         , .mask = 0x0, .par.swizzle.in = 
{3, 0, 1, 2}) \
+    MACRO(__VA_ARGS__, u8_permute_wxzy                         , .type = 
SWS_PIXEL_U8 , .uop = SWS_UOP_PERMUTE         , .mask = 0x0, .par.swizzle.in = 
{3, 0, 2, 1}) \
+    MACRO(__VA_ARGS__, u8_permute_wyxz                         , .type = 
SWS_PIXEL_U8 , .uop = SWS_UOP_PERMUTE         , .mask = 0x0, .par.swizzle.in = 
{3, 1, 0, 2}) \
+    MACRO(__VA_ARGS__, u8_permute_wyzx                         , .type = 
SWS_PIXEL_U8 , .uop = SWS_UOP_PERMUTE         , .mask = 0x0, .par.swizzle.in = 
{3, 1, 2, 0}) \
+    MACRO(__VA_ARGS__, u8_permute_wzxy                         , .type = 
SWS_PIXEL_U8 , .uop = SWS_UOP_PERMUTE         , .mask = 0x0, .par.swizzle.in = 
{3, 2, 0, 1}) \
+    MACRO(__VA_ARGS__, u8_permute_wzyx                         , .type = 
SWS_PIXEL_U8 , .uop = SWS_UOP_PERMUTE         , .mask = 0x0, .par.swizzle.in = 
{3, 2, 1, 0})
 #define SWS_FOR_U8_COPY(MACRO, ...) \
     MACRO(__VA_ARGS__, u8_copy_yz_xx                           , SWS_PIXEL_U8 
, SWS_UOP_COPY            , 0x6, 0, 0, 0, 3) \
     MACRO(__VA_ARGS__, u8_copy_yzw_xxx                         , SWS_PIXEL_U8 
, SWS_UOP_COPY            , 0xe, 0, 0, 0, 0) \
@@ -440,51 +416,35 @@
 #define SWS_FOR_U16_WRITE_BIT(MACRO, ...)
 #define SWS_FOR_STRUCT_U16_WRITE_BIT(MACRO, ...)
 #define SWS_FOR_U16_PERMUTE(MACRO, ...) \
-    MACRO(__VA_ARGS__, u16_permute_x_y                         , 
SWS_PIXEL_U16, SWS_UOP_PERMUTE         , 0x1, 1, 0, 2, 3) \
-    MACRO(__VA_ARGS__, u16_permute_x_z                         , 
SWS_PIXEL_U16, SWS_UOP_PERMUTE         , 0x1, 2, 1, 0, 3) \
-    MACRO(__VA_ARGS__, u16_permute_x_w                         , 
SWS_PIXEL_U16, SWS_UOP_PERMUTE         , 0x1, 3, 1, 2, 0) \
-    MACRO(__VA_ARGS__, u16_permute_y_w                         , 
SWS_PIXEL_U16, SWS_UOP_PERMUTE         , 0x2, 0, 3, 2, 1) \
-    MACRO(__VA_ARGS__, u16_permute_y_x                         , 
SWS_PIXEL_U16, SWS_UOP_PERMUTE         , 0x2, 1, 0, 2, 3) \
-    MACRO(__VA_ARGS__, u16_permute_xy_yx                       , 
SWS_PIXEL_U16, SWS_UOP_PERMUTE         , 0x3, 1, 0, 2, 3) \
-    MACRO(__VA_ARGS__, u16_permute_xy_wx                       , 
SWS_PIXEL_U16, SWS_UOP_PERMUTE         , 0x3, 3, 0, 2, 1) \
-    MACRO(__VA_ARGS__, u16_permute_xz_zx                       , 
SWS_PIXEL_U16, SWS_UOP_PERMUTE         , 0x5, 2, 1, 0, 3) \
-    MACRO(__VA_ARGS__, u16_permute_xz_zw                       , 
SWS_PIXEL_U16, SWS_UOP_PERMUTE         , 0x5, 2, 1, 3, 0) \
-    MACRO(__VA_ARGS__, u16_permute_xyz_yzx                     , 
SWS_PIXEL_U16, SWS_UOP_PERMUTE         , 0x7, 1, 2, 0, 3) \
-    MACRO(__VA_ARGS__, u16_permute_xyz_yzw                     , 
SWS_PIXEL_U16, SWS_UOP_PERMUTE         , 0x7, 1, 2, 3, 0) \
-    MACRO(__VA_ARGS__, u16_permute_xyz_zxy                     , 
SWS_PIXEL_U16, SWS_UOP_PERMUTE         , 0x7, 2, 0, 1, 3) \
-    MACRO(__VA_ARGS__, u16_permute_xyz_zwy                     , 
SWS_PIXEL_U16, SWS_UOP_PERMUTE         , 0x7, 2, 3, 1, 0) \
-    MACRO(__VA_ARGS__, u16_permute_xyz_wzy                     , 
SWS_PIXEL_U16, SWS_UOP_PERMUTE         , 0x7, 3, 2, 1, 0) \
-    MACRO(__VA_ARGS__, u16_permute_w_x                         , 
SWS_PIXEL_U16, SWS_UOP_PERMUTE         , 0x8, 3, 1, 2, 0) \
-    MACRO(__VA_ARGS__, u16_permute_zw_xz                       , 
SWS_PIXEL_U16, SWS_UOP_PERMUTE         , 0xc, 3, 1, 0, 2) \
-    MACRO(__VA_ARGS__, u16_permute_yzw_zwy                     , 
SWS_PIXEL_U16, SWS_UOP_PERMUTE         , 0xe, 0, 2, 3, 1) \
-    MACRO(__VA_ARGS__, u16_permute_yzw_xyz                     , 
SWS_PIXEL_U16, SWS_UOP_PERMUTE         , 0xe, 3, 0, 1, 2) \
-    MACRO(__VA_ARGS__, u16_permute_yzw_zyx                     , 
SWS_PIXEL_U16, SWS_UOP_PERMUTE         , 0xe, 3, 2, 1, 0) \
-    MACRO(__VA_ARGS__, u16_permute_xyzw_yzwx                   , 
SWS_PIXEL_U16, SWS_UOP_PERMUTE         , 0xf, 1, 2, 3, 0) \
-    MACRO(__VA_ARGS__, u16_permute_xyzw_wxyz                   , 
SWS_PIXEL_U16, SWS_UOP_PERMUTE         , 0xf, 3, 0, 1, 2) \
-    MACRO(__VA_ARGS__, u16_permute_xyzw_wzyx                   , 
SWS_PIXEL_U16, SWS_UOP_PERMUTE         , 0xf, 3, 2, 1, 0)
+    MACRO(__VA_ARGS__, u16_permute_xzwy                        , 
SWS_PIXEL_U16, SWS_UOP_PERMUTE         , 0x0, 0, 2, 3, 1) \
+    MACRO(__VA_ARGS__, u16_permute_xwzy                        , 
SWS_PIXEL_U16, SWS_UOP_PERMUTE         , 0x0, 0, 3, 2, 1) \
+    MACRO(__VA_ARGS__, u16_permute_yxzw                        , 
SWS_PIXEL_U16, SWS_UOP_PERMUTE         , 0x0, 1, 0, 2, 3) \
+    MACRO(__VA_ARGS__, u16_permute_yzxw                        , 
SWS_PIXEL_U16, SWS_UOP_PERMUTE         , 0x0, 1, 2, 0, 3) \
+    MACRO(__VA_ARGS__, u16_permute_yzwx                        , 
SWS_PIXEL_U16, SWS_UOP_PERMUTE         , 0x0, 1, 2, 3, 0) \
+    MACRO(__VA_ARGS__, u16_permute_zxyw                        , 
SWS_PIXEL_U16, SWS_UOP_PERMUTE         , 0x0, 2, 0, 1, 3) \
+    MACRO(__VA_ARGS__, u16_permute_zyxw                        , 
SWS_PIXEL_U16, SWS_UOP_PERMUTE         , 0x0, 2, 1, 0, 3) \
+    MACRO(__VA_ARGS__, u16_permute_zywx                        , 
SWS_PIXEL_U16, SWS_UOP_PERMUTE         , 0x0, 2, 1, 3, 0) \
+    MACRO(__VA_ARGS__, u16_permute_zwyx                        , 
SWS_PIXEL_U16, SWS_UOP_PERMUTE         , 0x0, 2, 3, 1, 0) \
+    MACRO(__VA_ARGS__, u16_permute_wxyz                        , 
SWS_PIXEL_U16, SWS_UOP_PERMUTE         , 0x0, 3, 0, 1, 2) \
+    MACRO(__VA_ARGS__, u16_permute_wxzy                        , 
SWS_PIXEL_U16, SWS_UOP_PERMUTE         , 0x0, 3, 0, 2, 1) \
+    MACRO(__VA_ARGS__, u16_permute_wyxz                        , 
SWS_PIXEL_U16, SWS_UOP_PERMUTE         , 0x0, 3, 1, 0, 2) \
+    MACRO(__VA_ARGS__, u16_permute_wyzx                        , 
SWS_PIXEL_U16, SWS_UOP_PERMUTE         , 0x0, 3, 1, 2, 0) \
+    MACRO(__VA_ARGS__, u16_permute_wzyx                        , 
SWS_PIXEL_U16, SWS_UOP_PERMUTE         , 0x0, 3, 2, 1, 0)
 #define SWS_FOR_STRUCT_U16_PERMUTE(MACRO, ...) \
-    MACRO(__VA_ARGS__, u16_permute_x_y                         , .type = 
SWS_PIXEL_U16, .uop = SWS_UOP_PERMUTE         , .mask = 0x1, .par.swizzle.in = 
{1, 0, 2, 3}) \
-    MACRO(__VA_ARGS__, u16_permute_x_z                         , .type = 
SWS_PIXEL_U16, .uop = SWS_UOP_PERMUTE         , .mask = 0x1, .par.swizzle.in = 
{2, 1, 0, 3}) \
-    MACRO(__VA_ARGS__, u16_permute_x_w                         , .type = 
SWS_PIXEL_U16, .uop = SWS_UOP_PERMUTE         , .mask = 0x1, .par.swizzle.in = 
{3, 1, 2, 0}) \
-    MACRO(__VA_ARGS__, u16_permute_y_w                         , .type = 
SWS_PIXEL_U16, .uop = SWS_UOP_PERMUTE         , .mask = 0x2, .par.swizzle.in = 
{0, 3, 2, 1}) \
-    MACRO(__VA_ARGS__, u16_permute_y_x                         , .type = 
SWS_PIXEL_U16, .uop = SWS_UOP_PERMUTE         , .mask = 0x2, .par.swizzle.in = 
{1, 0, 2, 3}) \
-    MACRO(__VA_ARGS__, u16_permute_xy_yx                       , .type = 
SWS_PIXEL_U16, .uop = SWS_UOP_PERMUTE         , .mask = 0x3, .par.swizzle.in = 
{1, 0, 2, 3}) \
-    MACRO(__VA_ARGS__, u16_permute_xy_wx                       , .type = 
SWS_PIXEL_U16, .uop = SWS_UOP_PERMUTE         , .mask = 0x3, .par.swizzle.in = 
{3, 0, 2, 1}) \
-    MACRO(__VA_ARGS__, u16_permute_xz_zx                       , .type = 
SWS_PIXEL_U16, .uop = SWS_UOP_PERMUTE         , .mask = 0x5, .par.swizzle.in = 
{2, 1, 0, 3}) \
-    MACRO(__VA_ARGS__, u16_permute_xz_zw                       , .type = 
SWS_PIXEL_U16, .uop = SWS_UOP_PERMUTE         , .mask = 0x5, .par.swizzle.in = 
{2, 1, 3, 0}) \
-    MACRO(__VA_ARGS__, u16_permute_xyz_yzx                     , .type = 
SWS_PIXEL_U16, .uop = SWS_UOP_PERMUTE         , .mask = 0x7, .par.swizzle.in = 
{1, 2, 0, 3}) \
-    MACRO(__VA_ARGS__, u16_permute_xyz_yzw                     , .type = 
SWS_PIXEL_U16, .uop = SWS_UOP_PERMUTE         , .mask = 0x7, .par.swizzle.in = 
{1, 2, 3, 0}) \
-    MACRO(__VA_ARGS__, u16_permute_xyz_zxy                     , .type = 
SWS_PIXEL_U16, .uop = SWS_UOP_PERMUTE         , .mask = 0x7, .par.swizzle.in = 
{2, 0, 1, 3}) \
-    MACRO(__VA_ARGS__, u16_permute_xyz_zwy                     , .type = 
SWS_PIXEL_U16, .uop = SWS_UOP_PERMUTE         , .mask = 0x7, .par.swizzle.in = 
{2, 3, 1, 0}) \
-    MACRO(__VA_ARGS__, u16_permute_xyz_wzy                     , .type = 
SWS_PIXEL_U16, .uop = SWS_UOP_PERMUTE         , .mask = 0x7, .par.swizzle.in = 
{3, 2, 1, 0}) \
-    MACRO(__VA_ARGS__, u16_permute_w_x                         , .type = 
SWS_PIXEL_U16, .uop = SWS_UOP_PERMUTE         , .mask = 0x8, .par.swizzle.in = 
{3, 1, 2, 0}) \
-    MACRO(__VA_ARGS__, u16_permute_zw_xz                       , .type = 
SWS_PIXEL_U16, .uop = SWS_UOP_PERMUTE         , .mask = 0xc, .par.swizzle.in = 
{3, 1, 0, 2}) \
-    MACRO(__VA_ARGS__, u16_permute_yzw_zwy                     , .type = 
SWS_PIXEL_U16, .uop = SWS_UOP_PERMUTE         , .mask = 0xe, .par.swizzle.in = 
{0, 2, 3, 1}) \
-    MACRO(__VA_ARGS__, u16_permute_yzw_xyz                     , .type = 
SWS_PIXEL_U16, .uop = SWS_UOP_PERMUTE         , .mask = 0xe, .par.swizzle.in = 
{3, 0, 1, 2}) \
-    MACRO(__VA_ARGS__, u16_permute_yzw_zyx                     , .type = 
SWS_PIXEL_U16, .uop = SWS_UOP_PERMUTE         , .mask = 0xe, .par.swizzle.in = 
{3, 2, 1, 0}) \
-    MACRO(__VA_ARGS__, u16_permute_xyzw_yzwx                   , .type = 
SWS_PIXEL_U16, .uop = SWS_UOP_PERMUTE         , .mask = 0xf, .par.swizzle.in = 
{1, 2, 3, 0}) \
-    MACRO(__VA_ARGS__, u16_permute_xyzw_wxyz                   , .type = 
SWS_PIXEL_U16, .uop = SWS_UOP_PERMUTE         , .mask = 0xf, .par.swizzle.in = 
{3, 0, 1, 2}) \
-    MACRO(__VA_ARGS__, u16_permute_xyzw_wzyx                   , .type = 
SWS_PIXEL_U16, .uop = SWS_UOP_PERMUTE         , .mask = 0xf, .par.swizzle.in = 
{3, 2, 1, 0})
+    MACRO(__VA_ARGS__, u16_permute_xzwy                        , .type = 
SWS_PIXEL_U16, .uop = SWS_UOP_PERMUTE         , .mask = 0x0, .par.swizzle.in = 
{0, 2, 3, 1}) \
+    MACRO(__VA_ARGS__, u16_permute_xwzy                        , .type = 
SWS_PIXEL_U16, .uop = SWS_UOP_PERMUTE         , .mask = 0x0, .par.swizzle.in = 
{0, 3, 2, 1}) \
+    MACRO(__VA_ARGS__, u16_permute_yxzw                        , .type = 
SWS_PIXEL_U16, .uop = SWS_UOP_PERMUTE         , .mask = 0x0, .par.swizzle.in = 
{1, 0, 2, 3}) \
+    MACRO(__VA_ARGS__, u16_permute_yzxw                        , .type = 
SWS_PIXEL_U16, .uop = SWS_UOP_PERMUTE         , .mask = 0x0, .par.swizzle.in = 
{1, 2, 0, 3}) \
+    MACRO(__VA_ARGS__, u16_permute_yzwx                        , .type = 
SWS_PIXEL_U16, .uop = SWS_UOP_PERMUTE         , .mask = 0x0, .par.swizzle.in = 
{1, 2, 3, 0}) \
+    MACRO(__VA_ARGS__, u16_permute_zxyw                        , .type = 
SWS_PIXEL_U16, .uop = SWS_UOP_PERMUTE         , .mask = 0x0, .par.swizzle.in = 
{2, 0, 1, 3}) \
+    MACRO(__VA_ARGS__, u16_permute_zyxw                        , .type = 
SWS_PIXEL_U16, .uop = SWS_UOP_PERMUTE         , .mask = 0x0, .par.swizzle.in = 
{2, 1, 0, 3}) \
+    MACRO(__VA_ARGS__, u16_permute_zywx                        , .type = 
SWS_PIXEL_U16, .uop = SWS_UOP_PERMUTE         , .mask = 0x0, .par.swizzle.in = 
{2, 1, 3, 0}) \
+    MACRO(__VA_ARGS__, u16_permute_zwyx                        , .type = 
SWS_PIXEL_U16, .uop = SWS_UOP_PERMUTE         , .mask = 0x0, .par.swizzle.in = 
{2, 3, 1, 0}) \
+    MACRO(__VA_ARGS__, u16_permute_wxyz                        , .type = 
SWS_PIXEL_U16, .uop = SWS_UOP_PERMUTE         , .mask = 0x0, .par.swizzle.in = 
{3, 0, 1, 2}) \
+    MACRO(__VA_ARGS__, u16_permute_wxzy                        , .type = 
SWS_PIXEL_U16, .uop = SWS_UOP_PERMUTE         , .mask = 0x0, .par.swizzle.in = 
{3, 0, 2, 1}) \
+    MACRO(__VA_ARGS__, u16_permute_wyxz                        , .type = 
SWS_PIXEL_U16, .uop = SWS_UOP_PERMUTE         , .mask = 0x0, .par.swizzle.in = 
{3, 1, 0, 2}) \
+    MACRO(__VA_ARGS__, u16_permute_wyzx                        , .type = 
SWS_PIXEL_U16, .uop = SWS_UOP_PERMUTE         , .mask = 0x0, .par.swizzle.in = 
{3, 1, 2, 0}) \
+    MACRO(__VA_ARGS__, u16_permute_wzyx                        , .type = 
SWS_PIXEL_U16, .uop = SWS_UOP_PERMUTE         , .mask = 0x0, .par.swizzle.in = 
{3, 2, 1, 0})
 #define SWS_FOR_U16_COPY(MACRO, ...) \
     MACRO(__VA_ARGS__, u16_copy_yz_xx                          , 
SWS_PIXEL_U16, SWS_UOP_COPY            , 0x6, 0, 0, 0, 3) \
     MACRO(__VA_ARGS__, u16_copy_yzw_xxy                        , 
SWS_PIXEL_U16, SWS_UOP_COPY            , 0xe, 0, 0, 0, 1)
@@ -744,65 +704,39 @@
 #define SWS_FOR_U32_WRITE_BIT(MACRO, ...)
 #define SWS_FOR_STRUCT_U32_WRITE_BIT(MACRO, ...)
 #define SWS_FOR_U32_PERMUTE(MACRO, ...) \
-    MACRO(__VA_ARGS__, u32_permute_x_y                         , 
SWS_PIXEL_U32, SWS_UOP_PERMUTE         , 0x1, 1, 0, 2, 3) \
-    MACRO(__VA_ARGS__, u32_permute_x_z                         , 
SWS_PIXEL_U32, SWS_UOP_PERMUTE         , 0x1, 2, 1, 0, 3) \
-    MACRO(__VA_ARGS__, u32_permute_x_w                         , 
SWS_PIXEL_U32, SWS_UOP_PERMUTE         , 0x1, 3, 1, 2, 0) \
-    MACRO(__VA_ARGS__, u32_permute_y_w                         , 
SWS_PIXEL_U32, SWS_UOP_PERMUTE         , 0x2, 0, 3, 2, 1) \
-    MACRO(__VA_ARGS__, u32_permute_y_x                         , 
SWS_PIXEL_U32, SWS_UOP_PERMUTE         , 0x2, 1, 0, 2, 3) \
-    MACRO(__VA_ARGS__, u32_permute_xy_yx                       , 
SWS_PIXEL_U32, SWS_UOP_PERMUTE         , 0x3, 1, 0, 2, 3) \
-    MACRO(__VA_ARGS__, u32_permute_z_x                         , 
SWS_PIXEL_U32, SWS_UOP_PERMUTE         , 0x4, 1, 2, 0, 3) \
-    MACRO(__VA_ARGS__, u32_permute_xz_zx                       , 
SWS_PIXEL_U32, SWS_UOP_PERMUTE         , 0x5, 2, 1, 0, 3) \
-    MACRO(__VA_ARGS__, u32_permute_xz_zw                       , 
SWS_PIXEL_U32, SWS_UOP_PERMUTE         , 0x5, 2, 1, 3, 0) \
-    MACRO(__VA_ARGS__, u32_permute_xz_wx                       , 
SWS_PIXEL_U32, SWS_UOP_PERMUTE         , 0x5, 3, 1, 0, 2) \
-    MACRO(__VA_ARGS__, u32_permute_yz_zy                       , 
SWS_PIXEL_U32, SWS_UOP_PERMUTE         , 0x6, 0, 2, 1, 3) \
-    MACRO(__VA_ARGS__, u32_permute_xyz_yzx                     , 
SWS_PIXEL_U32, SWS_UOP_PERMUTE         , 0x7, 1, 2, 0, 3) \
-    MACRO(__VA_ARGS__, u32_permute_xyz_yzw                     , 
SWS_PIXEL_U32, SWS_UOP_PERMUTE         , 0x7, 1, 2, 3, 0) \
-    MACRO(__VA_ARGS__, u32_permute_xyz_zxy                     , 
SWS_PIXEL_U32, SWS_UOP_PERMUTE         , 0x7, 2, 0, 1, 3) \
-    MACRO(__VA_ARGS__, u32_permute_xyz_zwy                     , 
SWS_PIXEL_U32, SWS_UOP_PERMUTE         , 0x7, 2, 3, 1, 0) \
-    MACRO(__VA_ARGS__, u32_permute_xyz_wzy                     , 
SWS_PIXEL_U32, SWS_UOP_PERMUTE         , 0x7, 3, 2, 1, 0) \
-    MACRO(__VA_ARGS__, u32_permute_w_y                         , 
SWS_PIXEL_U32, SWS_UOP_PERMUTE         , 0x8, 0, 2, 3, 1) \
-    MACRO(__VA_ARGS__, u32_permute_w_x                         , 
SWS_PIXEL_U32, SWS_UOP_PERMUTE         , 0x8, 3, 1, 2, 0) \
-    MACRO(__VA_ARGS__, u32_permute_xw_yx                       , 
SWS_PIXEL_U32, SWS_UOP_PERMUTE         , 0x9, 1, 2, 3, 0) \
-    MACRO(__VA_ARGS__, u32_permute_yw_wy                       , 
SWS_PIXEL_U32, SWS_UOP_PERMUTE         , 0xa, 0, 3, 2, 1) \
-    MACRO(__VA_ARGS__, u32_permute_yw_xy                       , 
SWS_PIXEL_U32, SWS_UOP_PERMUTE         , 0xa, 3, 0, 2, 1) \
-    MACRO(__VA_ARGS__, u32_permute_zw_xz                       , 
SWS_PIXEL_U32, SWS_UOP_PERMUTE         , 0xc, 3, 1, 0, 2) \
-    MACRO(__VA_ARGS__, u32_permute_yzw_xyz                     , 
SWS_PIXEL_U32, SWS_UOP_PERMUTE         , 0xe, 3, 0, 1, 2) \
-    MACRO(__VA_ARGS__, u32_permute_yzw_zxy                     , 
SWS_PIXEL_U32, SWS_UOP_PERMUTE         , 0xe, 3, 2, 0, 1) \
-    MACRO(__VA_ARGS__, u32_permute_yzw_zyx                     , 
SWS_PIXEL_U32, SWS_UOP_PERMUTE         , 0xe, 3, 2, 1, 0) \
-    MACRO(__VA_ARGS__, u32_permute_xyzw_yzwx                   , 
SWS_PIXEL_U32, SWS_UOP_PERMUTE         , 0xf, 1, 2, 3, 0) \
-    MACRO(__VA_ARGS__, u32_permute_xyzw_wxyz                   , 
SWS_PIXEL_U32, SWS_UOP_PERMUTE         , 0xf, 3, 0, 1, 2) \
-    MACRO(__VA_ARGS__, u32_permute_xyzw_wzxy                   , 
SWS_PIXEL_U32, SWS_UOP_PERMUTE         , 0xf, 3, 2, 0, 1) \
-    MACRO(__VA_ARGS__, u32_permute_xyzw_wzyx                   , 
SWS_PIXEL_U32, SWS_UOP_PERMUTE         , 0xf, 3, 2, 1, 0)
+    MACRO(__VA_ARGS__, u32_permute_xzyw                        , 
SWS_PIXEL_U32, SWS_UOP_PERMUTE         , 0x0, 0, 2, 1, 3) \
+    MACRO(__VA_ARGS__, u32_permute_xzwy                        , 
SWS_PIXEL_U32, SWS_UOP_PERMUTE         , 0x0, 0, 2, 3, 1) \
+    MACRO(__VA_ARGS__, u32_permute_xwzy                        , 
SWS_PIXEL_U32, SWS_UOP_PERMUTE         , 0x0, 0, 3, 2, 1) \
+    MACRO(__VA_ARGS__, u32_permute_yxzw                        , 
SWS_PIXEL_U32, SWS_UOP_PERMUTE         , 0x0, 1, 0, 2, 3) \
+    MACRO(__VA_ARGS__, u32_permute_yzxw                        , 
SWS_PIXEL_U32, SWS_UOP_PERMUTE         , 0x0, 1, 2, 0, 3) \
+    MACRO(__VA_ARGS__, u32_permute_yzwx                        , 
SWS_PIXEL_U32, SWS_UOP_PERMUTE         , 0x0, 1, 2, 3, 0) \
+    MACRO(__VA_ARGS__, u32_permute_zxyw                        , 
SWS_PIXEL_U32, SWS_UOP_PERMUTE         , 0x0, 2, 0, 1, 3) \
+    MACRO(__VA_ARGS__, u32_permute_zyxw                        , 
SWS_PIXEL_U32, SWS_UOP_PERMUTE         , 0x0, 2, 1, 0, 3) \
+    MACRO(__VA_ARGS__, u32_permute_zywx                        , 
SWS_PIXEL_U32, SWS_UOP_PERMUTE         , 0x0, 2, 1, 3, 0) \
+    MACRO(__VA_ARGS__, u32_permute_zwyx                        , 
SWS_PIXEL_U32, SWS_UOP_PERMUTE         , 0x0, 2, 3, 1, 0) \
+    MACRO(__VA_ARGS__, u32_permute_wxyz                        , 
SWS_PIXEL_U32, SWS_UOP_PERMUTE         , 0x0, 3, 0, 1, 2) \
+    MACRO(__VA_ARGS__, u32_permute_wxzy                        , 
SWS_PIXEL_U32, SWS_UOP_PERMUTE         , 0x0, 3, 0, 2, 1) \
+    MACRO(__VA_ARGS__, u32_permute_wyxz                        , 
SWS_PIXEL_U32, SWS_UOP_PERMUTE         , 0x0, 3, 1, 0, 2) \
+    MACRO(__VA_ARGS__, u32_permute_wyzx                        , 
SWS_PIXEL_U32, SWS_UOP_PERMUTE         , 0x0, 3, 1, 2, 0) \
+    MACRO(__VA_ARGS__, u32_permute_wzxy                        , 
SWS_PIXEL_U32, SWS_UOP_PERMUTE         , 0x0, 3, 2, 0, 1) \
+    MACRO(__VA_ARGS__, u32_permute_wzyx                        , 
SWS_PIXEL_U32, SWS_UOP_PERMUTE         , 0x0, 3, 2, 1, 0)
 #define SWS_FOR_STRUCT_U32_PERMUTE(MACRO, ...) \
-    MACRO(__VA_ARGS__, u32_permute_x_y                         , .type = 
SWS_PIXEL_U32, .uop = SWS_UOP_PERMUTE         , .mask = 0x1, .par.swizzle.in = 
{1, 0, 2, 3}) \
-    MACRO(__VA_ARGS__, u32_permute_x_z                         , .type = 
SWS_PIXEL_U32, .uop = SWS_UOP_PERMUTE         , .mask = 0x1, .par.swizzle.in = 
{2, 1, 0, 3}) \
-    MACRO(__VA_ARGS__, u32_permute_x_w                         , .type = 
SWS_PIXEL_U32, .uop = SWS_UOP_PERMUTE         , .mask = 0x1, .par.swizzle.in = 
{3, 1, 2, 0}) \
-    MACRO(__VA_ARGS__, u32_permute_y_w                         , .type = 
SWS_PIXEL_U32, .uop = SWS_UOP_PERMUTE         , .mask = 0x2, .par.swizzle.in = 
{0, 3, 2, 1}) \
-    MACRO(__VA_ARGS__, u32_permute_y_x                         , .type = 
SWS_PIXEL_U32, .uop = SWS_UOP_PERMUTE         , .mask = 0x2, .par.swizzle.in = 
{1, 0, 2, 3}) \
-    MACRO(__VA_ARGS__, u32_permute_xy_yx                       , .type = 
SWS_PIXEL_U32, .uop = SWS_UOP_PERMUTE         , .mask = 0x3, .par.swizzle.in = 
{1, 0, 2, 3}) \
-    MACRO(__VA_ARGS__, u32_permute_z_x                         , .type = 
SWS_PIXEL_U32, .uop = SWS_UOP_PERMUTE         , .mask = 0x4, .par.swizzle.in = 
{1, 2, 0, 3}) \
-    MACRO(__VA_ARGS__, u32_permute_xz_zx                       , .type = 
SWS_PIXEL_U32, .uop = SWS_UOP_PERMUTE         , .mask = 0x5, .par.swizzle.in = 
{2, 1, 0, 3}) \
-    MACRO(__VA_ARGS__, u32_permute_xz_zw                       , .type = 
SWS_PIXEL_U32, .uop = SWS_UOP_PERMUTE         , .mask = 0x5, .par.swizzle.in = 
{2, 1, 3, 0}) \
-    MACRO(__VA_ARGS__, u32_permute_xz_wx                       , .type = 
SWS_PIXEL_U32, .uop = SWS_UOP_PERMUTE         , .mask = 0x5, .par.swizzle.in = 
{3, 1, 0, 2}) \
-    MACRO(__VA_ARGS__, u32_permute_yz_zy                       , .type = 
SWS_PIXEL_U32, .uop = SWS_UOP_PERMUTE         , .mask = 0x6, .par.swizzle.in = 
{0, 2, 1, 3}) \
-    MACRO(__VA_ARGS__, u32_permute_xyz_yzx                     , .type = 
SWS_PIXEL_U32, .uop = SWS_UOP_PERMUTE         , .mask = 0x7, .par.swizzle.in = 
{1, 2, 0, 3}) \
-    MACRO(__VA_ARGS__, u32_permute_xyz_yzw                     , .type = 
SWS_PIXEL_U32, .uop = SWS_UOP_PERMUTE         , .mask = 0x7, .par.swizzle.in = 
{1, 2, 3, 0}) \
-    MACRO(__VA_ARGS__, u32_permute_xyz_zxy                     , .type = 
SWS_PIXEL_U32, .uop = SWS_UOP_PERMUTE         , .mask = 0x7, .par.swizzle.in = 
{2, 0, 1, 3}) \
-    MACRO(__VA_ARGS__, u32_permute_xyz_zwy                     , .type = 
SWS_PIXEL_U32, .uop = SWS_UOP_PERMUTE         , .mask = 0x7, .par.swizzle.in = 
{2, 3, 1, 0}) \
-    MACRO(__VA_ARGS__, u32_permute_xyz_wzy                     , .type = 
SWS_PIXEL_U32, .uop = SWS_UOP_PERMUTE         , .mask = 0x7, .par.swizzle.in = 
{3, 2, 1, 0}) \
-    MACRO(__VA_ARGS__, u32_permute_w_y                         , .type = 
SWS_PIXEL_U32, .uop = SWS_UOP_PERMUTE         , .mask = 0x8, .par.swizzle.in = 
{0, 2, 3, 1}) \
-    MACRO(__VA_ARGS__, u32_permute_w_x                         , .type = 
SWS_PIXEL_U32, .uop = SWS_UOP_PERMUTE         , .mask = 0x8, .par.swizzle.in = 
{3, 1, 2, 0}) \
-    MACRO(__VA_ARGS__, u32_permute_xw_yx                       , .type = 
SWS_PIXEL_U32, .uop = SWS_UOP_PERMUTE         , .mask = 0x9, .par.swizzle.in = 
{1, 2, 3, 0}) \
-    MACRO(__VA_ARGS__, u32_permute_yw_wy                       , .type = 
SWS_PIXEL_U32, .uop = SWS_UOP_PERMUTE         , .mask = 0xa, .par.swizzle.in = 
{0, 3, 2, 1}) \
-    MACRO(__VA_ARGS__, u32_permute_yw_xy                       , .type = 
SWS_PIXEL_U32, .uop = SWS_UOP_PERMUTE         , .mask = 0xa, .par.swizzle.in = 
{3, 0, 2, 1}) \
-    MACRO(__VA_ARGS__, u32_permute_zw_xz                       , .type = 
SWS_PIXEL_U32, .uop = SWS_UOP_PERMUTE         , .mask = 0xc, .par.swizzle.in = 
{3, 1, 0, 2}) \
-    MACRO(__VA_ARGS__, u32_permute_yzw_xyz                     , .type = 
SWS_PIXEL_U32, .uop = SWS_UOP_PERMUTE         , .mask = 0xe, .par.swizzle.in = 
{3, 0, 1, 2}) \
-    MACRO(__VA_ARGS__, u32_permute_yzw_zxy                     , .type = 
SWS_PIXEL_U32, .uop = SWS_UOP_PERMUTE         , .mask = 0xe, .par.swizzle.in = 
{3, 2, 0, 1}) \
-    MACRO(__VA_ARGS__, u32_permute_yzw_zyx                     , .type = 
SWS_PIXEL_U32, .uop = SWS_UOP_PERMUTE         , .mask = 0xe, .par.swizzle.in = 
{3, 2, 1, 0}) \
-    MACRO(__VA_ARGS__, u32_permute_xyzw_yzwx                   , .type = 
SWS_PIXEL_U32, .uop = SWS_UOP_PERMUTE         , .mask = 0xf, .par.swizzle.in = 
{1, 2, 3, 0}) \
-    MACRO(__VA_ARGS__, u32_permute_xyzw_wxyz                   , .type = 
SWS_PIXEL_U32, .uop = SWS_UOP_PERMUTE         , .mask = 0xf, .par.swizzle.in = 
{3, 0, 1, 2}) \
-    MACRO(__VA_ARGS__, u32_permute_xyzw_wzxy                   , .type = 
SWS_PIXEL_U32, .uop = SWS_UOP_PERMUTE         , .mask = 0xf, .par.swizzle.in = 
{3, 2, 0, 1}) \
-    MACRO(__VA_ARGS__, u32_permute_xyzw_wzyx                   , .type = 
SWS_PIXEL_U32, .uop = SWS_UOP_PERMUTE         , .mask = 0xf, .par.swizzle.in = 
{3, 2, 1, 0})
+    MACRO(__VA_ARGS__, u32_permute_xzyw                        , .type = 
SWS_PIXEL_U32, .uop = SWS_UOP_PERMUTE         , .mask = 0x0, .par.swizzle.in = 
{0, 2, 1, 3}) \
+    MACRO(__VA_ARGS__, u32_permute_xzwy                        , .type = 
SWS_PIXEL_U32, .uop = SWS_UOP_PERMUTE         , .mask = 0x0, .par.swizzle.in = 
{0, 2, 3, 1}) \
+    MACRO(__VA_ARGS__, u32_permute_xwzy                        , .type = 
SWS_PIXEL_U32, .uop = SWS_UOP_PERMUTE         , .mask = 0x0, .par.swizzle.in = 
{0, 3, 2, 1}) \
+    MACRO(__VA_ARGS__, u32_permute_yxzw                        , .type = 
SWS_PIXEL_U32, .uop = SWS_UOP_PERMUTE         , .mask = 0x0, .par.swizzle.in = 
{1, 0, 2, 3}) \
+    MACRO(__VA_ARGS__, u32_permute_yzxw                        , .type = 
SWS_PIXEL_U32, .uop = SWS_UOP_PERMUTE         , .mask = 0x0, .par.swizzle.in = 
{1, 2, 0, 3}) \
+    MACRO(__VA_ARGS__, u32_permute_yzwx                        , .type = 
SWS_PIXEL_U32, .uop = SWS_UOP_PERMUTE         , .mask = 0x0, .par.swizzle.in = 
{1, 2, 3, 0}) \
+    MACRO(__VA_ARGS__, u32_permute_zxyw                        , .type = 
SWS_PIXEL_U32, .uop = SWS_UOP_PERMUTE         , .mask = 0x0, .par.swizzle.in = 
{2, 0, 1, 3}) \
+    MACRO(__VA_ARGS__, u32_permute_zyxw                        , .type = 
SWS_PIXEL_U32, .uop = SWS_UOP_PERMUTE         , .mask = 0x0, .par.swizzle.in = 
{2, 1, 0, 3}) \
+    MACRO(__VA_ARGS__, u32_permute_zywx                        , .type = 
SWS_PIXEL_U32, .uop = SWS_UOP_PERMUTE         , .mask = 0x0, .par.swizzle.in = 
{2, 1, 3, 0}) \
+    MACRO(__VA_ARGS__, u32_permute_zwyx                        , .type = 
SWS_PIXEL_U32, .uop = SWS_UOP_PERMUTE         , .mask = 0x0, .par.swizzle.in = 
{2, 3, 1, 0}) \
+    MACRO(__VA_ARGS__, u32_permute_wxyz                        , .type = 
SWS_PIXEL_U32, .uop = SWS_UOP_PERMUTE         , .mask = 0x0, .par.swizzle.in = 
{3, 0, 1, 2}) \
+    MACRO(__VA_ARGS__, u32_permute_wxzy                        , .type = 
SWS_PIXEL_U32, .uop = SWS_UOP_PERMUTE         , .mask = 0x0, .par.swizzle.in = 
{3, 0, 2, 1}) \
+    MACRO(__VA_ARGS__, u32_permute_wyxz                        , .type = 
SWS_PIXEL_U32, .uop = SWS_UOP_PERMUTE         , .mask = 0x0, .par.swizzle.in = 
{3, 1, 0, 2}) \
+    MACRO(__VA_ARGS__, u32_permute_wyzx                        , .type = 
SWS_PIXEL_U32, .uop = SWS_UOP_PERMUTE         , .mask = 0x0, .par.swizzle.in = 
{3, 1, 2, 0}) \
+    MACRO(__VA_ARGS__, u32_permute_wzxy                        , .type = 
SWS_PIXEL_U32, .uop = SWS_UOP_PERMUTE         , .mask = 0x0, .par.swizzle.in = 
{3, 2, 0, 1}) \
+    MACRO(__VA_ARGS__, u32_permute_wzyx                        , .type = 
SWS_PIXEL_U32, .uop = SWS_UOP_PERMUTE         , .mask = 0x0, .par.swizzle.in = 
{3, 2, 1, 0})
 #define SWS_FOR_U32_COPY(MACRO, ...) \
     MACRO(__VA_ARGS__, u32_copy_yz_xx                          , 
SWS_PIXEL_U32, SWS_UOP_COPY            , 0x6, 0, 0, 0, 3) \
     MACRO(__VA_ARGS__, u32_copy_yzw_xxx                        , 
SWS_PIXEL_U32, SWS_UOP_COPY            , 0xe, 0, 0, 0, 0) \
diff --git a/tests/ref/fate/sws-ops-list b/tests/ref/fate/sws-ops-list
index dcda011ccc..d47e674bec 100644
--- a/tests/ref/fate/sws-ops-list
+++ b/tests/ref/fate/sws-ops-list
@@ -1 +1 @@
-e490d908612d059c644e64b43247fb08
+a5779f7e6e5f6a56d8150261343369ac
-- 
2.52.0

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

Reply via email to