PR #25542 opened by Ramiro Polla (ramiro)
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25542
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25542.patch

Based on suggestion from 
https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25387#issuecomment-75633



>From 83cb47e3845b1856e443a03137a1c094ca6c707f Mon Sep 17 00:00:00 2001
From: Ramiro Polla <[email protected]>
Date: Tue, 27 Oct 2026 18:00:34 +0100
Subject: [PATCH 1/5] swscale/ops_memcpy: load per-plane pointers and strides
 once

This makes the code easier to read and will let us do a few more
simplifications.
---
 libswscale/ops_memcpy.c | 32 +++++++++++++++++---------------
 1 file changed, 17 insertions(+), 15 deletions(-)

diff --git a/libswscale/ops_memcpy.c b/libswscale/ops_memcpy.c
index 735006ab188..a079d8fcc4a 100644
--- a/libswscale/ops_memcpy.c
+++ b/libswscale/ops_memcpy.c
@@ -46,30 +46,32 @@ static void process(const SwsOpExec *exec, const void *priv,
     av_assert1(x_start == 0 && x_end == exec->width);
 
     for (int i = 0; i < p->num_planes; i++) {
-        uint8_t *out = exec->out[i];
-        const int idx = p->index[i];
+        uint8_t         *out        = exec->out[i];
+        const ptrdiff_t  out_stride = exec->out_stride[i];
+        const int        idx        = p->index[i];
+        const uint8_t   *in         = (idx >= 0) ? exec->in[idx] : NULL;
+        const ptrdiff_t  in_stride  = (idx >= 0) ? exec->in_stride[idx] : 0;
         const int bytes = x_end * exec->block_size_out[i];
-        const int use_loop = exec->out_stride[i] < 0 ||
-                             exec->out_stride[i] > bytes + SWS_MAX_PADDING;
-        const size_t span = (size_t) (lines - 1) * exec->out_stride[i] + bytes;
-        if (idx < 0 && !use_loop) {
+        const int use_loop = out_stride < 0 ||
+                             out_stride > bytes + SWS_MAX_PADDING;
+        const size_t span = (size_t) (lines - 1) * out_stride + bytes;
+        if (!in && !use_loop) {
             memset(out, p->clear_value[i], span);
-        } else if (idx < 0) {
+        } else if (!in) {
             for (int y = y_start; y < y_end; y++) {
                 memset(out, p->clear_value[i], bytes);
-                out += exec->out_stride[i];
+                out += out_stride;
             }
-        } else if (out == exec->in[idx]) {
-            av_assert1(exec->out_stride[i] == exec->in_stride[idx]);
+        } else if (out == in) {
+            av_assert1(out_stride == in_stride);
             continue; /* plane was already ref'd */
-        } else if (exec->out_stride[i] == exec->in_stride[idx] && !use_loop) {
-            memcpy(out, exec->in[idx], span);
+        } else if (out_stride == in_stride && !use_loop) {
+            memcpy(out, in, span);
         } else {
-            const uint8_t *in = exec->in[idx];
             for (int y = y_start; y < y_end; y++) {
                 memcpy(out, in, bytes);
-                out += exec->out_stride[i];
-                in  += exec->in_stride[idx];
+                out += out_stride;
+                in  += in_stride;
             }
         }
     }
-- 
2.54.0


>From 23ec704afbcbabf2818999118ba9d5d2aab7a088 Mon Sep 17 00:00:00 2001
From: Ramiro Polla <[email protected]>
Date: Tue, 27 Oct 2026 19:05:37 +0100
Subject: [PATCH 2/5] swscale/ops_memcpy: move early-skip block before
 unrelated variable declarations

---
 libswscale/ops_memcpy.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/libswscale/ops_memcpy.c b/libswscale/ops_memcpy.c
index a079d8fcc4a..6bcc05b0cd9 100644
--- a/libswscale/ops_memcpy.c
+++ b/libswscale/ops_memcpy.c
@@ -51,6 +51,12 @@ static void process(const SwsOpExec *exec, const void *priv,
         const int        idx        = p->index[i];
         const uint8_t   *in         = (idx >= 0) ? exec->in[idx] : NULL;
         const ptrdiff_t  in_stride  = (idx >= 0) ? exec->in_stride[idx] : 0;
+
+        if (out == in) {
+            av_assert1(out_stride == in_stride);
+            continue; /* plane was already ref'd */
+        }
+
         const int bytes = x_end * exec->block_size_out[i];
         const int use_loop = out_stride < 0 ||
                              out_stride > bytes + SWS_MAX_PADDING;
@@ -62,9 +68,6 @@ static void process(const SwsOpExec *exec, const void *priv,
                 memset(out, p->clear_value[i], bytes);
                 out += out_stride;
             }
-        } else if (out == in) {
-            av_assert1(out_stride == in_stride);
-            continue; /* plane was already ref'd */
         } else if (out_stride == in_stride && !use_loop) {
             memcpy(out, in, span);
         } else {
-- 
2.54.0


>From a80350b6c8d45ae1e430d430beee96a9c02636d0 Mon Sep 17 00:00:00 2001
From: Ramiro Polla <[email protected]>
Date: Tue, 27 Oct 2026 19:05:54 +0100
Subject: [PATCH 3/5] swscale/ops_memcpy: merge bulk memset/memcpy paths into
 per-line loops

Instead of having separate paths for bulk and per-line memset/memcpy
operations, modify the loop count and size parameters.
---
 libswscale/ops_memcpy.c | 25 +++++++++++++------------
 1 file changed, 13 insertions(+), 12 deletions(-)

diff --git a/libswscale/ops_memcpy.c b/libswscale/ops_memcpy.c
index 6bcc05b0cd9..9e73554ddf2 100644
--- a/libswscale/ops_memcpy.c
+++ b/libswscale/ops_memcpy.c
@@ -42,7 +42,6 @@ static void process(const SwsOpExec *exec, const void *priv,
                     int x_start, int y_start, int x_end, int y_end)
 {
     const MemcpyPriv *p = priv;
-    const int lines = y_end - y_start;
     av_assert1(x_start == 0 && x_end == exec->width);
 
     for (int i = 0; i < p->num_planes; i++) {
@@ -57,21 +56,23 @@ static void process(const SwsOpExec *exec, const void *priv,
             continue; /* plane was already ref'd */
         }
 
-        const int bytes = x_end * exec->block_size_out[i];
-        const int use_loop = out_stride < 0 ||
-                             out_stride > bytes + SWS_MAX_PADDING;
-        const size_t span = (size_t) (lines - 1) * out_stride + bytes;
-        if (!in && !use_loop) {
-            memset(out, p->clear_value[i], span);
-        } else if (!in) {
-            for (int y = y_start; y < y_end; y++) {
+        size_t bytes = x_end * exec->block_size_out[i];
+        int lines = y_end - y_start;
+
+        /* Replace the per-line loop with a bulk memset/memcpy when possible. 
*/
+        if ((!in || out_stride == in_stride) &&
+            out_stride >= 0 && (size_t) out_stride <= bytes + SWS_MAX_PADDING) 
{
+            bytes += (size_t) (lines - 1) * out_stride;
+            lines = 1;
+        }
+
+        if (!in) {
+            for (int y = 0; y < lines; y++) {
                 memset(out, p->clear_value[i], bytes);
                 out += out_stride;
             }
-        } else if (out_stride == in_stride && !use_loop) {
-            memcpy(out, in, span);
         } else {
-            for (int y = y_start; y < y_end; y++) {
+            for (int y = 0; y < lines; y++) {
                 memcpy(out, in, bytes);
                 out += out_stride;
                 in  += in_stride;
-- 
2.54.0


>From 85823292ab39231036b8e184d766249ca6007cd2 Mon Sep 17 00:00:00 2001
From: Ramiro Polla <[email protected]>
Date: Tue, 27 Oct 2026 19:55:14 +0100
Subject: [PATCH 4/5] swscale/ops_memcpy: also use bulk memcpy/memset for
 negative strides

Just modify the base input/output pointers, the rest of the code has
already been generalized to support this.
---
 libswscale/ops_memcpy.c | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/libswscale/ops_memcpy.c b/libswscale/ops_memcpy.c
index 9e73554ddf2..f90e875b9e3 100644
--- a/libswscale/ops_memcpy.c
+++ b/libswscale/ops_memcpy.c
@@ -60,9 +60,16 @@ static void process(const SwsOpExec *exec, const void *priv,
         int lines = y_end - y_start;
 
         /* Replace the per-line loop with a bulk memset/memcpy when possible. 
*/
+        const size_t abs_stride = FFABS(out_stride);
         if ((!in || out_stride == in_stride) &&
-            out_stride >= 0 && (size_t) out_stride <= bytes + SWS_MAX_PADDING) 
{
-            bytes += (size_t) (lines - 1) * out_stride;
+            abs_stride <= bytes + SWS_MAX_PADDING) {
+            if (out_stride < 0) {
+                const ptrdiff_t offset = (lines - 1) * out_stride;
+                out += offset;
+                if (in)
+                    in += offset;
+            }
+            bytes += (lines - 1) * abs_stride;
             lines = 1;
         }
 
-- 
2.54.0


>From 61be04d3e5f5a41b06ac67c094755de37c9eedd5 Mon Sep 17 00:00:00 2001
From: Ramiro Polla <[email protected]>
Date: Tue, 27 Oct 2026 20:03:32 +0100
Subject: [PATCH 5/5] fate/libswscale: test all unscaled conversions with the
 memcpy backend

The memcpy backend only supports unscaled conversions, so we can set
the -scaler to none while testing it. We can then also clear the -p
parameter, to run all tests.
---
 tests/fate/libswscale.mak | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/tests/fate/libswscale.mak b/tests/fate/libswscale.mak
index 802ac72a03e..ae427e46ac3 100644
--- a/tests/fate/libswscale.mak
+++ b/tests/fate/libswscale.mak
@@ -81,16 +81,24 @@ fate-sws-unstable: $(FATE_SWS_UNSTABLE)
 SWS_CPU_BACKENDS := $(filter-out spirv,$(SWS_UNSTABLE_BACKENDS-yes))
 FATE_SWS_UNPADDED := $(SWS_CPU_BACKENDS:%=fate-sws-unpadded-%)
 $(FATE_SWS_UNPADDED): libswscale/tests/swscale$(EXESUF)
-$(FATE_SWS_UNPADDED): CMD = run libswscale/tests/swscale$(EXESUF) -v 16 
-backends $(@:fate-sws-unpadded-%=%) -align_src 1 -align_dst 1 -p 0.01
+$(FATE_SWS_UNPADDED): CMD = run libswscale/tests/swscale$(EXESUF) -v 16 
-backends $(@:fate-sws-unpadded-%=%) -align_src 1 -align_dst 1 $(SWS_PROB) 
$(SWS_SCALER)
 $(FATE_SWS_UNPADDED): REF = /dev/null
 fate-sws-unpadded: $(FATE_SWS_UNPADDED)
 
 FATE_SWS_FLIPPED := $(SWS_CPU_BACKENDS:%=fate-sws-flipped-%)
 $(FATE_SWS_FLIPPED): libswscale/tests/swscale$(EXESUF)
-$(FATE_SWS_FLIPPED): CMD = run libswscale/tests/swscale$(EXESUF) -v 16 
-backends $(@:fate-sws-flipped-%=%) -align_src -1 -align_dst -1 -p 0.01
+$(FATE_SWS_FLIPPED): CMD = run libswscale/tests/swscale$(EXESUF) -v 16 
-backends $(@:fate-sws-flipped-%=%) -align_src -1 -align_dst -1 $(SWS_PROB) 
$(SWS_SCALER)
 $(FATE_SWS_FLIPPED): REF = /dev/null
 fate-sws-flipped: $(FATE_SWS_FLIPPED)
 
+# Run only 1% of the tests
+$(FATE_SWS_UNPADDED) $(FATE_SWS_FLIPPED): SWS_PROB = -p 0.01
+
+# The memcpy backend only supports unscaled conversions, so test all of
+# those instead
+fate-sws-unpadded-memcpy fate-sws-flipped-memcpy: SWS_PROB =
+fate-sws-unpadded-memcpy fate-sws-flipped-memcpy: SWS_SCALER = -scaler none
+
 FATE_LIBSWSCALE += $(FATE_SWS_UNSCALED) $(FATE_SWS_UNSTABLE) 
$(FATE_SWS_UNPADDED) $(FATE_SWS_FLIPPED)
 endif
 
-- 
2.54.0

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

Reply via email to