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

Git pushed a commit to branch master
in repository ffmpeg.

commit 4e91f49e3db857e71451f7acb41b0a6808d7bad2
Author:     Ramiro Polla <[email protected]>
AuthorDate: Fri Jun 12 18:19:01 2026 +0200
Commit:     Ramiro Polla <[email protected]>
CommitDate: Sun Jul 19 15:07:02 2026 +0200

    swscale/aarch64/ops: convert swizzle operation to a series of moves
    
    This is similar to the way SWS_UOP_PERMUTE/SWS_UOP_COPY work and will
    simplify the move to uops.
    
    Sponsored-by: Sovereign Tech Fund
    Signed-off-by: Ramiro Polla <[email protected]>
---
 libswscale/aarch64/ops_asmgen.c    |  62 +++-----------
 libswscale/aarch64/ops_entries.c   | 170 ++++++++++++++++++-------------------
 libswscale/aarch64/ops_impl.c      |  33 ++++++-
 libswscale/aarch64/ops_impl.h      |   9 +-
 libswscale/aarch64/ops_impl_conv.c |  88 +++++++++++++++++--
 5 files changed, 215 insertions(+), 147 deletions(-)

diff --git a/libswscale/aarch64/ops_asmgen.c b/libswscale/aarch64/ops_asmgen.c
index 2346a26035..c270d72ec9 100644
--- a/libswscale/aarch64/ops_asmgen.c
+++ b/libswscale/aarch64/ops_asmgen.c
@@ -637,13 +637,12 @@ static void asmgen_op_swap_bytes(SwsAArch64Context *s, 
const SwsAArch64OpImplPar
 
 /*********************************************************************/
 /* rearrange channel order, or duplicate channels */
-/* AARCH64_SWS_OP_SWIZZLE */
-
-#define SWIZZLE_TMP 0xf
+/* AARCH64_SWS_OP_PERMUTE */
+/* AARCH64_SWS_OP_COPY */
 
 static const char *print_swizzle_v(char buf[8], uint8_t n, uint8_t vh)
 {
-    if (n == SWIZZLE_TMP)
+    if (n == AARCH64_MOVE_TMP)
         snprintf(buf, sizeof(char[8]), "vtmp%c", vh ? 'h' : 'l');
     else
         snprintf(buf, sizeof(char[8]), "v%c[%u]", vh ? 'h' : 'l', n);
@@ -653,7 +652,7 @@ static const char *print_swizzle_v(char buf[8], uint8_t n, 
uint8_t vh)
 
 static RasmOp swizzle_a64op(SwsAArch64Context *s, uint8_t n, uint8_t vh)
 {
-    if (n == SWIZZLE_TMP)
+    if (n == AARCH64_MOVE_TMP)
         return s->vt[vh];
     return vh ? s->vh[n] : s->vl[n];
 }
@@ -670,54 +669,18 @@ static void swizzle_emit(SwsAArch64Context *s, uint8_t 
dst, uint8_t src)
     }
 }
 
-static void asmgen_op_swizzle(SwsAArch64Context *s, const 
SwsAArch64OpImplParams *p)
+static void asmgen_op_move(SwsAArch64Context *s, const SwsAArch64OpImplParams 
*p)
 {
-    /* Compute used vectors (src and dst) */
-    uint8_t src_used[4] = { 0 };
-    bool done[4] = { true, true, true, true };
-    LOOP_MASK(p, dst) {
-        uint8_t src = MASK_GET(p->swizzle, dst);
-        src_used[src]++;
-        done[dst] = false;
-    }
+    SwsAArch64MoveOp move = p->move;
 
-    /* First perform unobstructed copies. */
-    for (bool progress = true; progress; ) {
-        progress = false;
-        for (int dst = 0; dst < 4; dst++) {
-            if (done[dst] || src_used[dst])
-                continue;
-            uint8_t src = MASK_GET(p->swizzle, dst);
-            swizzle_emit(s, dst, src);
-            src_used[src]--;
-            done[dst] = true;
-            progress = true;
-        }
-    }
-
-    /* Then swap and rotate remaining operations. */
-    for (int dst = 0; dst < 4; dst++) {
-        if (done[dst])
-            continue;
-
-        swizzle_emit(s, SWIZZLE_TMP, dst);
-
-        uint8_t cur_dst = dst;
-        uint8_t src = MASK_GET(p->swizzle, cur_dst);
-        while (src != dst) {
-            swizzle_emit(s, cur_dst, src);
-            done[cur_dst] = true;
-            cur_dst = src;
-            src = MASK_GET(p->swizzle, cur_dst);
-        }
-
-        swizzle_emit(s, cur_dst, SWIZZLE_TMP);
-        done[cur_dst] = true;
+    while (move) {
+        uint8_t src = (move     ) & 0xf;
+        uint8_t dst = (move >> 4) & 0xf;
+        swizzle_emit(s, dst, src);
+        move >>= 8;
     }
 }
 
-#undef SWIZZLE_TMP
-
 /*********************************************************************/
 /* split tightly packed data into components */
 /* AARCH64_SWS_OP_UNPACK */
@@ -1380,7 +1343,8 @@ static void asmgen_op_cps(SwsAArch64Context *s, const 
SwsAArch64OpImplParams *p)
     case AARCH64_SWS_OP_WRITE_PACKED: asmgen_op_write_packed(s, p); break;
     case AARCH64_SWS_OP_WRITE_PLANAR: asmgen_op_write_planar(s, p); break;
     case AARCH64_SWS_OP_SWAP_BYTES:   asmgen_op_swap_bytes(s, p);   break;
-    case AARCH64_SWS_OP_SWIZZLE:      asmgen_op_swizzle(s, p);      break;
+    case AARCH64_SWS_OP_PERMUTE:      asmgen_op_move(s, p);         break;
+    case AARCH64_SWS_OP_COPY:         asmgen_op_move(s, p);         break;
     case AARCH64_SWS_OP_UNPACK:       asmgen_op_unpack(s, p);       break;
     case AARCH64_SWS_OP_PACK:         asmgen_op_pack(s, p);         break;
     case AARCH64_SWS_OP_LSHIFT:       asmgen_op_lshift(s, p);       break;
diff --git a/libswscale/aarch64/ops_entries.c b/libswscale/aarch64/ops_entries.c
index 5c90cf3805..2aae4802bd 100644
--- a/libswscale/aarch64/ops_entries.c
+++ b/libswscale/aarch64/ops_entries.c
@@ -94,91 +94,91 @@
 { .op = AARCH64_SWS_OP_SWAP_BYTES, .block_size = 16, .type = 
AARCH64_PIXEL_U16, .mask = 0x0111 },
 { .op = AARCH64_SWS_OP_SWAP_BYTES, .block_size = 16, .type = 
AARCH64_PIXEL_U16, .mask = 0x1110 },
 { .op = AARCH64_SWS_OP_SWAP_BYTES, .block_size = 16, .type = 
AARCH64_PIXEL_U16, .mask = 0x1111 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x0001, .block_size = 8, .type = 
AARCH64_PIXEL_U8, .mask = 0x1111 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x0001, .block_size = 16, .type = 
AARCH64_PIXEL_U8, .mask = 0x1111 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x000f, .block_size = 8, .type = 
AARCH64_PIXEL_U8, .mask = 0x1110 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x000f, .block_size = 16, .type = 
AARCH64_PIXEL_U8, .mask = 0x1110 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x000f, .block_size = 32, .type = 
AARCH64_PIXEL_U8, .mask = 0x1110 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x0123, .block_size = 8, .type = 
AARCH64_PIXEL_U8, .mask = 0x1111 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x0123, .block_size = 16, .type = 
AARCH64_PIXEL_U8, .mask = 0x1111 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x0123, .block_size = 32, .type = 
AARCH64_PIXEL_U8, .mask = 0x1111 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x012f, .block_size = 8, .type = 
AARCH64_PIXEL_U8, .mask = 0x1110 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x012f, .block_size = 16, .type = 
AARCH64_PIXEL_U8, .mask = 0x1110 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x012f, .block_size = 32, .type = 
AARCH64_PIXEL_U8, .mask = 0x1110 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x0321, .block_size = 16, .type = 
AARCH64_PIXEL_U8, .mask = 0x1111 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x0321, .block_size = 32, .type = 
AARCH64_PIXEL_U8, .mask = 0x1111 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x03f2, .block_size = 16, .type = 
AARCH64_PIXEL_U8, .mask = 0x1101 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x0ff1, .block_size = 32, .type = 
AARCH64_PIXEL_U8, .mask = 0x1001 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x0fff, .block_size = 8, .type = 
AARCH64_PIXEL_U8, .mask = 0x1000 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x0fff, .block_size = 16, .type = 
AARCH64_PIXEL_U8, .mask = 0x1000 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x0fff, .block_size = 32, .type = 
AARCH64_PIXEL_U8, .mask = 0x1000 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x100f, .block_size = 8, .type = 
AARCH64_PIXEL_U8, .mask = 0x1110 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x100f, .block_size = 16, .type = 
AARCH64_PIXEL_U8, .mask = 0x1110 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x100f, .block_size = 32, .type = 
AARCH64_PIXEL_U8, .mask = 0x1110 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x1023, .block_size = 8, .type = 
AARCH64_PIXEL_U8, .mask = 0x1111 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x1023, .block_size = 32, .type = 
AARCH64_PIXEL_U8, .mask = 0x1111 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x102f, .block_size = 8, .type = 
AARCH64_PIXEL_U8, .mask = 0x1110 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x102f, .block_size = 32, .type = 
AARCH64_PIXEL_U8, .mask = 0x1110 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x132f, .block_size = 8, .type = 
AARCH64_PIXEL_U8, .mask = 0x1110 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x132f, .block_size = 16, .type = 
AARCH64_PIXEL_U8, .mask = 0x1110 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x1f0f, .block_size = 32, .type = 
AARCH64_PIXEL_U8, .mask = 0x1010 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x1f3f, .block_size = 8, .type = 
AARCH64_PIXEL_U8, .mask = 0x1010 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x1f3f, .block_size = 16, .type = 
AARCH64_PIXEL_U8, .mask = 0x1010 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x1f3f, .block_size = 32, .type = 
AARCH64_PIXEL_U8, .mask = 0x1010 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x1fff, .block_size = 32, .type = 
AARCH64_PIXEL_U8, .mask = 0x1000 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x20f3, .block_size = 8, .type = 
AARCH64_PIXEL_U8, .mask = 0x1101 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x20f3, .block_size = 16, .type = 
AARCH64_PIXEL_U8, .mask = 0x1101 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x20ff, .block_size = 8, .type = 
AARCH64_PIXEL_U8, .mask = 0x1100 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x20ff, .block_size = 32, .type = 
AARCH64_PIXEL_U8, .mask = 0x1100 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x2103, .block_size = 8, .type = 
AARCH64_PIXEL_U8, .mask = 0x1111 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x2103, .block_size = 16, .type = 
AARCH64_PIXEL_U8, .mask = 0x1111 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x2103, .block_size = 32, .type = 
AARCH64_PIXEL_U8, .mask = 0x1111 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x210f, .block_size = 8, .type = 
AARCH64_PIXEL_U8, .mask = 0x1110 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x210f, .block_size = 16, .type = 
AARCH64_PIXEL_U8, .mask = 0x1110 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x210f, .block_size = 32, .type = 
AARCH64_PIXEL_U8, .mask = 0x1110 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xf00f, .block_size = 8, .type = 
AARCH64_PIXEL_U8, .mask = 0x0110 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xf00f, .block_size = 16, .type = 
AARCH64_PIXEL_U8, .mask = 0x0110 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xf00f, .block_size = 32, .type = 
AARCH64_PIXEL_U8, .mask = 0x0110 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xf021, .block_size = 16, .type = 
AARCH64_PIXEL_U8, .mask = 0x0111 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xf021, .block_size = 32, .type = 
AARCH64_PIXEL_U8, .mask = 0x0111 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xf0f2, .block_size = 8, .type = 
AARCH64_PIXEL_U8, .mask = 0x0101 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xf0f2, .block_size = 16, .type = 
AARCH64_PIXEL_U8, .mask = 0x0101 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xf0f2, .block_size = 32, .type = 
AARCH64_PIXEL_U8, .mask = 0x0101 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xf0f3, .block_size = 32, .type = 
AARCH64_PIXEL_U8, .mask = 0x0101 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xf0ff, .block_size = 8, .type = 
AARCH64_PIXEL_U8, .mask = 0x0100 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xf0ff, .block_size = 32, .type = 
AARCH64_PIXEL_U8, .mask = 0x0100 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xf102, .block_size = 8, .type = 
AARCH64_PIXEL_U8, .mask = 0x0111 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xf102, .block_size = 16, .type = 
AARCH64_PIXEL_U8, .mask = 0x0111 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xf102, .block_size = 32, .type = 
AARCH64_PIXEL_U8, .mask = 0x0111 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xf123, .block_size = 8, .type = 
AARCH64_PIXEL_U8, .mask = 0x0111 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xf123, .block_size = 16, .type = 
AARCH64_PIXEL_U8, .mask = 0x0111 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xf123, .block_size = 32, .type = 
AARCH64_PIXEL_U8, .mask = 0x0111 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xf12f, .block_size = 8, .type = 
AARCH64_PIXEL_U8, .mask = 0x0110 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xf12f, .block_size = 16, .type = 
AARCH64_PIXEL_U8, .mask = 0x0110 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xf12f, .block_size = 32, .type = 
AARCH64_PIXEL_U8, .mask = 0x0110 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xf132, .block_size = 32, .type = 
AARCH64_PIXEL_U8, .mask = 0x0111 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xf321, .block_size = 8, .type = 
AARCH64_PIXEL_U8, .mask = 0x0111 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xf321, .block_size = 16, .type = 
AARCH64_PIXEL_U8, .mask = 0x0111 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xf321, .block_size = 32, .type = 
AARCH64_PIXEL_U8, .mask = 0x0111 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xf3f2, .block_size = 16, .type = 
AARCH64_PIXEL_U8, .mask = 0x0101 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xf3f2, .block_size = 32, .type = 
AARCH64_PIXEL_U8, .mask = 0x0101 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xff01, .block_size = 8, .type = 
AARCH64_PIXEL_U8, .mask = 0x0011 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xff01, .block_size = 16, .type = 
AARCH64_PIXEL_U8, .mask = 0x0011 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xff01, .block_size = 32, .type = 
AARCH64_PIXEL_U8, .mask = 0x0011 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xff03, .block_size = 8, .type = 
AARCH64_PIXEL_U8, .mask = 0x0011 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xff03, .block_size = 16, .type = 
AARCH64_PIXEL_U8, .mask = 0x0011 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xff0f, .block_size = 8, .type = 
AARCH64_PIXEL_U8, .mask = 0x0010 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xff0f, .block_size = 16, .type = 
AARCH64_PIXEL_U8, .mask = 0x0010 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xff0f, .block_size = 32, .type = 
AARCH64_PIXEL_U8, .mask = 0x0010 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xff31, .block_size = 8, .type = 
AARCH64_PIXEL_U8, .mask = 0x0011 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xff3f, .block_size = 8, .type = 
AARCH64_PIXEL_U8, .mask = 0x0010 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xff3f, .block_size = 16, .type = 
AARCH64_PIXEL_U8, .mask = 0x0010 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xff3f, .block_size = 32, .type = 
AARCH64_PIXEL_U8, .mask = 0x0010 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xfff1, .block_size = 32, .type = 
AARCH64_PIXEL_U8, .mask = 0x0001 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xfff2, .block_size = 32, .type = 
AARCH64_PIXEL_U8, .mask = 0x0001 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xfff3, .block_size = 8, .type = 
AARCH64_PIXEL_U8, .mask = 0x0001 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xfff3, .block_size = 16, .type = 
AARCH64_PIXEL_U8, .mask = 0x0001 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xfff3, .block_size = 32, .type = 
AARCH64_PIXEL_U8, .mask = 0x0001 },
+{ .op = AARCH64_SWS_OP_PERMUTE, .move = 0x000000000001ULL, .block_size = 32, 
.type = AARCH64_PIXEL_U8, .mask = 0x0001 },
+{ .op = AARCH64_SWS_OP_PERMUTE, .move = 0x000000000002ULL, .block_size = 32, 
.type = AARCH64_PIXEL_U8, .mask = 0x0001 },
+{ .op = AARCH64_SWS_OP_PERMUTE, .move = 0x000000000003ULL, .block_size = 8, 
.type = AARCH64_PIXEL_U8, .mask = 0x0001 },
+{ .op = AARCH64_SWS_OP_PERMUTE, .move = 0x000000000003ULL, .block_size = 16, 
.type = AARCH64_PIXEL_U8, .mask = 0x0001 },
+{ .op = AARCH64_SWS_OP_PERMUTE, .move = 0x000000000003ULL, .block_size = 32, 
.type = AARCH64_PIXEL_U8, .mask = 0x0001 },
+{ .op = AARCH64_SWS_OP_PERMUTE, .move = 0x000000000010ULL, .block_size = 8, 
.type = AARCH64_PIXEL_U8, .mask = 0x0010 },
+{ .op = AARCH64_SWS_OP_PERMUTE, .move = 0x000000000010ULL, .block_size = 16, 
.type = AARCH64_PIXEL_U8, .mask = 0x0010 },
+{ .op = AARCH64_SWS_OP_PERMUTE, .move = 0x000000000010ULL, .block_size = 32, 
.type = AARCH64_PIXEL_U8, .mask = 0x0010 },
+{ .op = AARCH64_SWS_OP_PERMUTE, .move = 0x000000000013ULL, .block_size = 8, 
.type = AARCH64_PIXEL_U8, .mask = 0x0010 },
+{ .op = AARCH64_SWS_OP_PERMUTE, .move = 0x000000000013ULL, .block_size = 16, 
.type = AARCH64_PIXEL_U8, .mask = 0x0010 },
+{ .op = AARCH64_SWS_OP_PERMUTE, .move = 0x000000000013ULL, .block_size = 32, 
.type = AARCH64_PIXEL_U8, .mask = 0x0010 },
+{ .op = AARCH64_SWS_OP_PERMUTE, .move = 0x000000000020ULL, .block_size = 8, 
.type = AARCH64_PIXEL_U8, .mask = 0x0100 },
+{ .op = AARCH64_SWS_OP_PERMUTE, .move = 0x000000000020ULL, .block_size = 32, 
.type = AARCH64_PIXEL_U8, .mask = 0x0100 },
+{ .op = AARCH64_SWS_OP_PERMUTE, .move = 0x000000000030ULL, .block_size = 8, 
.type = AARCH64_PIXEL_U8, .mask = 0x1000 },
+{ .op = AARCH64_SWS_OP_PERMUTE, .move = 0x000000000030ULL, .block_size = 16, 
.type = AARCH64_PIXEL_U8, .mask = 0x1000 },
+{ .op = AARCH64_SWS_OP_PERMUTE, .move = 0x000000000030ULL, .block_size = 32, 
.type = AARCH64_PIXEL_U8, .mask = 0x1000 },
+{ .op = AARCH64_SWS_OP_PERMUTE, .move = 0x000000000031ULL, .block_size = 32, 
.type = AARCH64_PIXEL_U8, .mask = 0x1000 },
+{ .op = AARCH64_SWS_OP_PERMUTE, .move = 0x000000000130ULL, .block_size = 32, 
.type = AARCH64_PIXEL_U8, .mask = 0x1001 },
+{ .op = AARCH64_SWS_OP_PERMUTE, .move = 0x000000000310ULL, .block_size = 8, 
.type = AARCH64_PIXEL_U8, .mask = 0x0011 },
+{ .op = AARCH64_SWS_OP_PERMUTE, .move = 0x000000000310ULL, .block_size = 16, 
.type = AARCH64_PIXEL_U8, .mask = 0x0011 },
+{ .op = AARCH64_SWS_OP_PERMUTE, .move = 0x000000000320ULL, .block_size = 32, 
.type = AARCH64_PIXEL_U8, .mask = 0x0101 },
+{ .op = AARCH64_SWS_OP_PERMUTE, .move = 0x000000001031ULL, .block_size = 32, 
.type = AARCH64_PIXEL_U8, .mask = 0x1010 },
+{ .op = AARCH64_SWS_OP_PERMUTE, .move = 0x000000001301ULL, .block_size = 8, 
.type = AARCH64_PIXEL_U8, .mask = 0x0011 },
+{ .op = AARCH64_SWS_OP_PERMUTE, .move = 0x000000002032ULL, .block_size = 8, 
.type = AARCH64_PIXEL_U8, .mask = 0x1100 },
+{ .op = AARCH64_SWS_OP_PERMUTE, .move = 0x000000002032ULL, .block_size = 32, 
.type = AARCH64_PIXEL_U8, .mask = 0x1100 },
+{ .op = AARCH64_SWS_OP_PERMUTE, .move = 0x000000002302ULL, .block_size = 16, 
.type = AARCH64_PIXEL_U8, .mask = 0x0101 },
+{ .op = AARCH64_SWS_OP_PERMUTE, .move = 0x000000002302ULL, .block_size = 32, 
.type = AARCH64_PIXEL_U8, .mask = 0x0101 },
+{ .op = AARCH64_SWS_OP_PERMUTE, .move = 0x000000102132ULL, .block_size = 8, 
.type = AARCH64_PIXEL_U8, .mask = 0x1110 },
+{ .op = AARCH64_SWS_OP_PERMUTE, .move = 0x000000102132ULL, .block_size = 16, 
.type = AARCH64_PIXEL_U8, .mask = 0x1110 },
+{ .op = AARCH64_SWS_OP_PERMUTE, .move = 0x000000102132ULL, .block_size = 32, 
.type = AARCH64_PIXEL_U8, .mask = 0x1110 },
+{ .op = AARCH64_SWS_OP_PERMUTE, .move = 0x000000132102ULL, .block_size = 32, 
.type = AARCH64_PIXEL_U8, .mask = 0x0111 },
+{ .op = AARCH64_SWS_OP_PERMUTE, .move = 0x0000001f01f0ULL, .block_size = 8, 
.type = AARCH64_PIXEL_U8, .mask = 0x0011 },
+{ .op = AARCH64_SWS_OP_PERMUTE, .move = 0x0000001f01f0ULL, .block_size = 16, 
.type = AARCH64_PIXEL_U8, .mask = 0x0011 },
+{ .op = AARCH64_SWS_OP_PERMUTE, .move = 0x0000001f01f0ULL, .block_size = 32, 
.type = AARCH64_PIXEL_U8, .mask = 0x0011 },
+{ .op = AARCH64_SWS_OP_PERMUTE, .move = 0x000000201231ULL, .block_size = 8, 
.type = AARCH64_PIXEL_U8, .mask = 0x1110 },
+{ .op = AARCH64_SWS_OP_PERMUTE, .move = 0x000000201231ULL, .block_size = 32, 
.type = AARCH64_PIXEL_U8, .mask = 0x1110 },
+{ .op = AARCH64_SWS_OP_PERMUTE, .move = 0x000000231201ULL, .block_size = 8, 
.type = AARCH64_PIXEL_U8, .mask = 0x0111 },
+{ .op = AARCH64_SWS_OP_PERMUTE, .move = 0x000000231201ULL, .block_size = 16, 
.type = AARCH64_PIXEL_U8, .mask = 0x0111 },
+{ .op = AARCH64_SWS_OP_PERMUTE, .move = 0x000000231201ULL, .block_size = 32, 
.type = AARCH64_PIXEL_U8, .mask = 0x0111 },
+{ .op = AARCH64_SWS_OP_PERMUTE, .move = 0x0000002f02f0ULL, .block_size = 8, 
.type = AARCH64_PIXEL_U8, .mask = 0x0101 },
+{ .op = AARCH64_SWS_OP_PERMUTE, .move = 0x0000002f02f0ULL, .block_size = 16, 
.type = AARCH64_PIXEL_U8, .mask = 0x0101 },
+{ .op = AARCH64_SWS_OP_PERMUTE, .move = 0x0000002f02f0ULL, .block_size = 32, 
.type = AARCH64_PIXEL_U8, .mask = 0x0101 },
+{ .op = AARCH64_SWS_OP_PERMUTE, .move = 0x0000002f12f1ULL, .block_size = 8, 
.type = AARCH64_PIXEL_U8, .mask = 0x0110 },
+{ .op = AARCH64_SWS_OP_PERMUTE, .move = 0x0000002f12f1ULL, .block_size = 16, 
.type = AARCH64_PIXEL_U8, .mask = 0x0110 },
+{ .op = AARCH64_SWS_OP_PERMUTE, .move = 0x0000002f12f1ULL, .block_size = 32, 
.type = AARCH64_PIXEL_U8, .mask = 0x0110 },
+{ .op = AARCH64_SWS_OP_PERMUTE, .move = 0x0000003f13f1ULL, .block_size = 8, 
.type = AARCH64_PIXEL_U8, .mask = 0x1010 },
+{ .op = AARCH64_SWS_OP_PERMUTE, .move = 0x0000003f13f1ULL, .block_size = 16, 
.type = AARCH64_PIXEL_U8, .mask = 0x1010 },
+{ .op = AARCH64_SWS_OP_PERMUTE, .move = 0x0000003f13f1ULL, .block_size = 32, 
.type = AARCH64_PIXEL_U8, .mask = 0x1010 },
+{ .op = AARCH64_SWS_OP_PERMUTE, .move = 0x00001f2102f0ULL, .block_size = 8, 
.type = AARCH64_PIXEL_U8, .mask = 0x0111 },
+{ .op = AARCH64_SWS_OP_PERMUTE, .move = 0x00001f2102f0ULL, .block_size = 16, 
.type = AARCH64_PIXEL_U8, .mask = 0x0111 },
+{ .op = AARCH64_SWS_OP_PERMUTE, .move = 0x00001f2102f0ULL, .block_size = 32, 
.type = AARCH64_PIXEL_U8, .mask = 0x0111 },
+{ .op = AARCH64_SWS_OP_PERMUTE, .move = 0x00002f1201f0ULL, .block_size = 16, 
.type = AARCH64_PIXEL_U8, .mask = 0x0111 },
+{ .op = AARCH64_SWS_OP_PERMUTE, .move = 0x00002f1201f0ULL, .block_size = 32, 
.type = AARCH64_PIXEL_U8, .mask = 0x0111 },
+{ .op = AARCH64_SWS_OP_PERMUTE, .move = 0x00002f12f103ULL, .block_size = 8, 
.type = AARCH64_PIXEL_U8, .mask = 0x0111 },
+{ .op = AARCH64_SWS_OP_PERMUTE, .move = 0x00002f12f103ULL, .block_size = 16, 
.type = AARCH64_PIXEL_U8, .mask = 0x0111 },
+{ .op = AARCH64_SWS_OP_PERMUTE, .move = 0x00002f12f103ULL, .block_size = 32, 
.type = AARCH64_PIXEL_U8, .mask = 0x0111 },
+{ .op = AARCH64_SWS_OP_PERMUTE, .move = 0x00002f12f130ULL, .block_size = 8, 
.type = AARCH64_PIXEL_U8, .mask = 0x1110 },
+{ .op = AARCH64_SWS_OP_PERMUTE, .move = 0x00002f12f130ULL, .block_size = 16, 
.type = AARCH64_PIXEL_U8, .mask = 0x1110 },
+{ .op = AARCH64_SWS_OP_PERMUTE, .move = 0x00002f12f130ULL, .block_size = 32, 
.type = AARCH64_PIXEL_U8, .mask = 0x1110 },
+{ .op = AARCH64_SWS_OP_PERMUTE, .move = 0x00002f3203f0ULL, .block_size = 8, 
.type = AARCH64_PIXEL_U8, .mask = 0x1101 },
+{ .op = AARCH64_SWS_OP_PERMUTE, .move = 0x00002f3203f0ULL, .block_size = 16, 
.type = AARCH64_PIXEL_U8, .mask = 0x1101 },
+{ .op = AARCH64_SWS_OP_PERMUTE, .move = 0x00003f2302f0ULL, .block_size = 16, 
.type = AARCH64_PIXEL_U8, .mask = 0x1101 },
+{ .op = AARCH64_SWS_OP_PERMUTE, .move = 0x00003f2312f1ULL, .block_size = 8, 
.type = AARCH64_PIXEL_U8, .mask = 0x1110 },
+{ .op = AARCH64_SWS_OP_PERMUTE, .move = 0x00003f2312f1ULL, .block_size = 16, 
.type = AARCH64_PIXEL_U8, .mask = 0x1110 },
+{ .op = AARCH64_SWS_OP_PERMUTE, .move = 0x001f213203f0ULL, .block_size = 8, 
.type = AARCH64_PIXEL_U8, .mask = 0x1111 },
+{ .op = AARCH64_SWS_OP_PERMUTE, .move = 0x001f213203f0ULL, .block_size = 16, 
.type = AARCH64_PIXEL_U8, .mask = 0x1111 },
+{ .op = AARCH64_SWS_OP_PERMUTE, .move = 0x001f213203f0ULL, .block_size = 32, 
.type = AARCH64_PIXEL_U8, .mask = 0x1111 },
+{ .op = AARCH64_SWS_OP_PERMUTE, .move = 0x002f123103f0ULL, .block_size = 8, 
.type = AARCH64_PIXEL_U8, .mask = 0x1111 },
+{ .op = AARCH64_SWS_OP_PERMUTE, .move = 0x002f123103f0ULL, .block_size = 32, 
.type = AARCH64_PIXEL_U8, .mask = 0x1111 },
+{ .op = AARCH64_SWS_OP_PERMUTE, .move = 0x003f231201f0ULL, .block_size = 16, 
.type = AARCH64_PIXEL_U8, .mask = 0x1111 },
+{ .op = AARCH64_SWS_OP_PERMUTE, .move = 0x003f231201f0ULL, .block_size = 32, 
.type = AARCH64_PIXEL_U8, .mask = 0x1111 },
+{ .op = AARCH64_SWS_OP_PERMUTE, .move = 0x2f12f13f03f0ULL, .block_size = 8, 
.type = AARCH64_PIXEL_U8, .mask = 0x1111 },
+{ .op = AARCH64_SWS_OP_PERMUTE, .move = 0x2f12f13f03f0ULL, .block_size = 16, 
.type = AARCH64_PIXEL_U8, .mask = 0x1111 },
+{ .op = AARCH64_SWS_OP_PERMUTE, .move = 0x2f12f13f03f0ULL, .block_size = 32, 
.type = AARCH64_PIXEL_U8, .mask = 0x1111 },
+{ .op = AARCH64_SWS_OP_COPY, .move = 0x000000002010ULL, .block_size = 8, .type 
= AARCH64_PIXEL_U8, .mask = 0x0110 },
+{ .op = AARCH64_SWS_OP_COPY, .move = 0x000000002010ULL, .block_size = 16, 
.type = AARCH64_PIXEL_U8, .mask = 0x0110 },
+{ .op = AARCH64_SWS_OP_COPY, .move = 0x000000002010ULL, .block_size = 32, 
.type = AARCH64_PIXEL_U8, .mask = 0x0110 },
+{ .op = AARCH64_SWS_OP_COPY, .move = 0x000000103120ULL, .block_size = 8, .type 
= AARCH64_PIXEL_U8, .mask = 0x1110 },
+{ .op = AARCH64_SWS_OP_COPY, .move = 0x000000103120ULL, .block_size = 16, 
.type = AARCH64_PIXEL_U8, .mask = 0x1110 },
+{ .op = AARCH64_SWS_OP_COPY, .move = 0x000000103120ULL, .block_size = 32, 
.type = AARCH64_PIXEL_U8, .mask = 0x1110 },
+{ .op = AARCH64_SWS_OP_COPY, .move = 0x000000302010ULL, .block_size = 8, .type 
= AARCH64_PIXEL_U8, .mask = 0x1110 },
+{ .op = AARCH64_SWS_OP_COPY, .move = 0x000000302010ULL, .block_size = 16, 
.type = AARCH64_PIXEL_U8, .mask = 0x1110 },
+{ .op = AARCH64_SWS_OP_COPY, .move = 0x000000302010ULL, .block_size = 32, 
.type = AARCH64_PIXEL_U8, .mask = 0x1110 },
+{ .op = AARCH64_SWS_OP_COPY, .move = 0x001f01f03020ULL, .block_size = 8, .type 
= AARCH64_PIXEL_U8, .mask = 0x1111 },
+{ .op = AARCH64_SWS_OP_COPY, .move = 0x001f01f03020ULL, .block_size = 16, 
.type = AARCH64_PIXEL_U8, .mask = 0x1111 },
 { .op = AARCH64_SWS_OP_UNPACK, .pack = 0x0121, .block_size = 8, .type = 
AARCH64_PIXEL_U8, .mask = 0x0111 },
 { .op = AARCH64_SWS_OP_UNPACK, .pack = 0x0121, .block_size = 16, .type = 
AARCH64_PIXEL_U8, .mask = 0x0111 },
 { .op = AARCH64_SWS_OP_UNPACK, .pack = 0x0233, .block_size = 8, .type = 
AARCH64_PIXEL_U8, .mask = 0x0111 },
diff --git a/libswscale/aarch64/ops_impl.c b/libswscale/aarch64/ops_impl.c
index d5be4563c6..d056b88162 100644
--- a/libswscale/aarch64/ops_impl.c
+++ b/libswscale/aarch64/ops_impl.c
@@ -85,7 +85,8 @@ static const char op_types[AARCH64_SWS_OP_TYPE_NB][32] = {
     [AARCH64_SWS_OP_WRITE_PACKED  ] = "AARCH64_SWS_OP_WRITE_PACKED",
     [AARCH64_SWS_OP_WRITE_PLANAR  ] = "AARCH64_SWS_OP_WRITE_PLANAR",
     [AARCH64_SWS_OP_SWAP_BYTES    ] = "AARCH64_SWS_OP_SWAP_BYTES",
-    [AARCH64_SWS_OP_SWIZZLE       ] = "AARCH64_SWS_OP_SWIZZLE",
+    [AARCH64_SWS_OP_PERMUTE       ] = "AARCH64_SWS_OP_PERMUTE",
+    [AARCH64_SWS_OP_COPY          ] = "AARCH64_SWS_OP_COPY",
     [AARCH64_SWS_OP_UNPACK        ] = "AARCH64_SWS_OP_UNPACK",
     [AARCH64_SWS_OP_PACK          ] = "AARCH64_SWS_OP_PACK",
     [AARCH64_SWS_OP_LSHIFT        ] = "AARCH64_SWS_OP_LSHIFT",
@@ -120,7 +121,8 @@ static const char op_type_names[AARCH64_SWS_OP_TYPE_NB][16] 
= {
     [AARCH64_SWS_OP_WRITE_PACKED  ] = "write_packed",
     [AARCH64_SWS_OP_WRITE_PLANAR  ] = "write_planar",
     [AARCH64_SWS_OP_SWAP_BYTES    ] = "swap_bytes",
-    [AARCH64_SWS_OP_SWIZZLE       ] = "swizzle",
+    [AARCH64_SWS_OP_PERMUTE       ] = "permute",
+    [AARCH64_SWS_OP_COPY          ] = "copy",
     [AARCH64_SWS_OP_UNPACK        ] = "unpack",
     [AARCH64_SWS_OP_PACK          ] = "pack",
     [AARCH64_SWS_OP_LSHIFT        ] = "lshift",
@@ -282,6 +284,28 @@ static int cmp_u16(void *pa, void *pb)
     return 0;
 }
 
+static void print_u48_name(char **pbuf, size_t *prem, void *p)
+{
+    uint64_t val = *(uint64_t *) p;
+    buf_appendf(pbuf, prem, "_%012" PRIx64, val);
+}
+
+static void print_u48_val(char **pbuf, size_t *prem, void *p)
+{
+    uint64_t val = *(uint64_t *) p;
+    buf_appendf(pbuf, prem, "0x%012" PRIx64 "ULL", val);
+}
+
+static int cmp_u48(void *pa, void *pb)
+{
+    int64_t ia = (int64_t) *((uint64_t *) pa);
+    int64_t ib = (int64_t) *((uint64_t *) pb);
+    int64_t diff = ia - ib;
+    if (diff)
+        return diff < 0 ? -1 : 1;
+    return 0;
+}
+
 static void print_u40_name(char **pbuf, size_t *prem, void *p)
 {
     uint64_t val = *(uint64_t *) p;
@@ -310,7 +334,7 @@ static const ParamField field_mask             = { 
PARAM_FIELD(mask),
 static const ParamField field_type             = { PARAM_FIELD(type),          
   print_pixel_name, print_pixel_val, cmp_pixel };
 static const ParamField field_block_size       = { PARAM_FIELD(block_size),    
   print_u8_name,    print_u8_val,    cmp_u8 };
 static const ParamField field_shift            = { PARAM_FIELD(shift),         
   print_u8_name,    print_u8_val,    cmp_u8 };
-static const ParamField field_swizzle          = { PARAM_FIELD(swizzle),       
   print_u16_name,   print_u16_val,   cmp_u16 };
+static const ParamField field_move             = { PARAM_FIELD(move),          
   print_u48_name,   print_u48_val,   cmp_u48 };
 static const ParamField field_pack             = { PARAM_FIELD(pack),          
   print_u16_name,   print_u16_val,   cmp_u16 };
 static const ParamField field_to_type          = { PARAM_FIELD(to_type),       
   print_pixel_name, print_pixel_val, cmp_pixel };
 static const ParamField field_linear_mask      = { PARAM_FIELD(linear.mask),   
   print_u40_name,   print_u40_val,   cmp_u40 };
@@ -330,7 +354,8 @@ static const ParamField 
*op_fields[AARCH64_SWS_OP_TYPE_NB][MAX_LEVELS] = {
     [AARCH64_SWS_OP_WRITE_PACKED  ] = { &field_op,                             
                     &field_block_size, &field_type, &field_mask },
     [AARCH64_SWS_OP_WRITE_PLANAR  ] = { &field_op,                             
                     &field_block_size, &field_type, &field_mask },
     [AARCH64_SWS_OP_SWAP_BYTES    ] = { &field_op,                             
                     &field_block_size, &field_type, &field_mask },
-    [AARCH64_SWS_OP_SWIZZLE       ] = { &field_op, &field_swizzle,             
                     &field_block_size, &field_type, &field_mask },
+    [AARCH64_SWS_OP_PERMUTE       ] = { &field_op, &field_move,                
                     &field_block_size, &field_type, &field_mask },
+    [AARCH64_SWS_OP_COPY          ] = { &field_op, &field_move,                
                     &field_block_size, &field_type, &field_mask },
     [AARCH64_SWS_OP_UNPACK        ] = { &field_op, &field_pack,                
                     &field_block_size, &field_type, &field_mask },
     [AARCH64_SWS_OP_PACK          ] = { &field_op, &field_pack,                
                     &field_block_size, &field_type, &field_mask },
     [AARCH64_SWS_OP_LSHIFT        ] = { &field_op, &field_shift,               
                     &field_block_size, &field_type, &field_mask },
diff --git a/libswscale/aarch64/ops_impl.h b/libswscale/aarch64/ops_impl.h
index 9950ccdad8..04ded26f34 100644
--- a/libswscale/aarch64/ops_impl.h
+++ b/libswscale/aarch64/ops_impl.h
@@ -46,7 +46,8 @@ typedef enum SwsAArch64OpType {
     AARCH64_SWS_OP_WRITE_PACKED,
     AARCH64_SWS_OP_WRITE_PLANAR,
     AARCH64_SWS_OP_SWAP_BYTES,
-    AARCH64_SWS_OP_SWIZZLE,
+    AARCH64_SWS_OP_PERMUTE,
+    AARCH64_SWS_OP_COPY,
     AARCH64_SWS_OP_UNPACK,
     AARCH64_SWS_OP_PACK,
     AARCH64_SWS_OP_LSHIFT,
@@ -65,6 +66,10 @@ typedef enum SwsAArch64OpType {
 /* Each nibble in the mask corresponds to one component. */
 typedef uint16_t SwsAArch64OpMask;
 
+/* Each byte is an LSB src|dst pair until 00 is reached. */
+typedef uint64_t SwsAArch64MoveOp;
+#define AARCH64_MOVE_TMP 0xf
+
 /**
  * Affine coefficient mask for linear op. Packs a 4x5 matrix in execution
  * order, where the offset is the first element, with 2 bits per element:
@@ -96,7 +101,7 @@ typedef struct SwsAArch64OpImplParams {
     uint8_t block_size;
     union {
         uint8_t             shift;
-        SwsAArch64OpMask    swizzle;
+        SwsAArch64MoveOp    move;
         SwsAArch64OpMask    pack;
         SwsAArch64PixelType to_type;
         SwsAArch64LinearOp  linear;
diff --git a/libswscale/aarch64/ops_impl_conv.c 
b/libswscale/aarch64/ops_impl_conv.c
index 20b9f41fad..a17612d123 100644
--- a/libswscale/aarch64/ops_impl_conv.c
+++ b/libswscale/aarch64/ops_impl_conv.c
@@ -52,6 +52,66 @@ static int linear_index_from_sws_op(int idx)
     return reorder_col[idx];
 }
 
+static void swizzle_emit(SwsAArch64OpImplParams *out, uint8_t dst, uint8_t 
src, int idx)
+{
+    uint64_t pair = src | (dst << 4);
+    out->move |= pair << (idx * 8);
+}
+
+static void convert_swizzle_to_moves(const SwsOp *op, SwsAArch64OpImplParams 
*out)
+{
+    SwsAArch64OpMask swizzle = 0;
+    int num_moves = 0;
+
+    MASK_SET(swizzle, 0, op->swizzle.in[0]);
+    MASK_SET(swizzle, 1, op->swizzle.in[1]);
+    MASK_SET(swizzle, 2, op->swizzle.in[2]);
+    MASK_SET(swizzle, 3, op->swizzle.in[3]);
+
+    /* Compute used vectors (src and dst) */
+    uint8_t src_used[4] = { 0 };
+    bool done[4] = { true, true, true, true };
+    LOOP(out->mask, dst) {
+        uint8_t src = MASK_GET(swizzle, dst);
+        src_used[src]++;
+        done[dst] = false;
+    }
+
+    /* First perform unobstructed copies. */
+    for (bool progress = true; progress; ) {
+        progress = false;
+        for (int dst = 0; dst < 4; dst++) {
+            if (done[dst] || src_used[dst])
+                continue;
+            uint8_t src = MASK_GET(swizzle, dst);
+            swizzle_emit(out, dst, src, num_moves++);
+            src_used[src]--;
+            done[dst] = true;
+            progress = true;
+        }
+    }
+
+    /* Then swap and rotate remaining operations. */
+    for (int dst = 0; dst < 4; dst++) {
+        if (done[dst])
+            continue;
+
+        swizzle_emit(out, AARCH64_MOVE_TMP, dst, num_moves++);
+
+        uint8_t cur_dst = dst;
+        uint8_t src = MASK_GET(swizzle, cur_dst);
+        while (src != dst) {
+            swizzle_emit(out, cur_dst, src, num_moves++);
+            done[cur_dst] = true;
+            cur_dst = src;
+            src = MASK_GET(swizzle, cur_dst);
+        }
+
+        swizzle_emit(out, cur_dst, AARCH64_MOVE_TMP, num_moves++);
+        done[cur_dst] = true;
+    }
+}
+
 /**
  * Convert SwsOp to a SwsAArch64OpImplParams. Read the comments regarding
  * SwsAArch64OpImplParams in ops_impl.h for more information.
@@ -114,7 +174,23 @@ static int convert_to_aarch64_impl(SwsContext *ctx, const 
SwsOpList *ops, int n,
             return AVERROR(ENOTSUP);
         break;
     case SWS_OP_SWAP_BYTES: out->op = AARCH64_SWS_OP_SWAP_BYTES; break;
-    case SWS_OP_SWIZZLE:    out->op = AARCH64_SWS_OP_SWIZZLE;    break;
+    case SWS_OP_SWIZZLE: {
+        /**
+         * Detect whether copies are needed or if a simple permute is
+         * enough.
+         */
+        out->op = AARCH64_SWS_OP_PERMUTE;
+        SwsAArch64OpMask seen = 0;
+        LOOP(out->mask, i) {
+            uint8_t src = op->swizzle.in[i];
+            if (MASK_GET(seen, src)) {
+                out->op = AARCH64_SWS_OP_COPY;
+                break;
+            }
+            MASK_SET(seen, src, 1);
+        }
+        break;
+    }
     case SWS_OP_UNPACK:     out->op = AARCH64_SWS_OP_UNPACK;     break;
     case SWS_OP_PACK:       out->op = AARCH64_SWS_OP_PACK;       break;
     case SWS_OP_LSHIFT:     out->op = AARCH64_SWS_OP_LSHIFT;     break;
@@ -149,17 +225,15 @@ static int convert_to_aarch64_impl(SwsContext *ctx, const 
SwsOpList *ops, int n,
         case 4: out->mask = 0x1111; break;
         };
         break;
-    case AARCH64_SWS_OP_SWIZZLE:
+    case AARCH64_SWS_OP_PERMUTE:
+    case AARCH64_SWS_OP_COPY:
         /* Recompute mask taking identity swizzle into account */
         out->mask = 0;
         for (int i = 0; i < 4; i++) {
-            if (SWS_OP_NEEDED(op, i) && op->swizzle.in[i] != i) {
+            if (SWS_OP_NEEDED(op, i) && op->swizzle.in[i] != i)
                 MASK_SET(out->mask, i, 1);
-                MASK_SET(out->swizzle, i, op->swizzle.in[i]);
-            } else {
-                MASK_SET(out->swizzle, i, 0xf);
-            }
         }
+        convert_swizzle_to_moves(op, out);
         /* The element size and type don't matter. */
         out->block_size = block_size * ff_sws_pixel_type_size(op->type);
         out->type = AARCH64_PIXEL_U8;

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

Reply via email to