PR #22888 opened by mkver
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/22888
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/22888.patch

Fixes issue #21113. Also port the offending function to SSE2.


>From e4ecb98333fd0ecaf7071b63b19f6da7307d1207 Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <[email protected]>
Date: Tue, 21 Apr 2026 13:47:34 +0200
Subject: [PATCH 1/3] swscale/x86/swscale_template: Don't set use_mmx_vfilter
 when disabled

Commit 554c2bc7086f49ef5a6a989ad6bc4bc11807eb6f
ported the yuv2planeX functions that are set iff
use_mmx_vfilter is set to external assembly
and did it in a way that resulted in linking failures
when inline assembly is enabled, but external assembly
is disabled. This was later fixed in commit
c00567647e9002094255df755e18c719e75b3333, but in such
a manner that use_mmx_vfilter can be set without any
of the accompanying yuv2planeX functions being set;
and in case inline assembly was unavailable,
these external assembly functions would never be selected.

This makes the filter-fps and filter-fps-cfr tests fail
with inline assembly but with --disable-x86asm, as
reported in issue #21113. Fix this by moving sws_init_swscale_mmxext
directly into ff_sws_init_swscale_x86() and setting
use_mmx_vfilter directly besides the yuv2planeX function pointer.

Signed-off-by: Andreas Rheinhardt <[email protected]>
---
 libswscale/swscale.c              |  2 +-
 libswscale/x86/swscale.c          | 97 +++++++++++++++++++++++++++----
 libswscale/x86/swscale_template.c | 76 ------------------------
 3 files changed, 87 insertions(+), 88 deletions(-)

diff --git a/libswscale/swscale.c b/libswscale/swscale.c
index 38320fe1c4..902053aac7 100644
--- a/libswscale/swscale.c
+++ b/libswscale/swscale.c
@@ -512,7 +512,7 @@ int ff_swscale(SwsInternal *c, const uint8_t *const src[], 
const int srcStride[]
         if (!enough_lines)
             break;  // we can't output a dstY line so let's try with the next 
slice
 
-#if HAVE_MMX_INLINE
+#if ARCH_X86 && HAVE_MMX
         ff_updateMMXDitherTables(c, dstY);
         c->dstW_mmx = c->opts.dst_w;
 #endif
diff --git a/libswscale/x86/swscale.c b/libswscale/x86/swscale.c
index 9bd4f526ba..26fd8aed3c 100644
--- a/libswscale/x86/swscale.c
+++ b/libswscale/x86/swscale.c
@@ -55,6 +55,7 @@ DECLARE_ASM_CONST(8, uint64_t, M24C) = 0x0000FF0000FF0000LL;
 #define RENAME(a) a ## _mmxext
 #include "swscale_template.c"
 #endif
+#endif /* HAVE_INLINE_ASM */
 
 void ff_updateMMXDitherTables(SwsInternal *c, int dstY)
 {
@@ -172,7 +173,6 @@ void ff_updateMMXDitherTables(SwsInternal *c, int dstY)
         }
     }
 }
-#endif /* HAVE_INLINE_ASM */
 
 #define YUV2YUVX_FUNC_MMX(opt, step)  \
 void ff_yuv2yuvX_ ##opt(const int16_t *filter, int filterSize, int srcOffset, \
@@ -489,23 +489,98 @@ av_cold void ff_sws_init_range_convert_x86(SwsInternal *c)
 av_cold void ff_sws_init_swscale_x86(SwsInternal *c)
 {
     int cpu_flags = av_get_cpu_flags();
+    enum AVPixelFormat dst_format = c->opts.dst_format;
 
+    c->use_mmx_vfilter = 0;
+
+    if (X86_MMXEXT(cpu_flags)) {
+        if (!is16BPS(dst_format) && !isNBPS(dst_format) && 
!isSemiPlanarYUV(dst_format)
+            && dst_format != AV_PIX_FMT_GRAYF32BE && dst_format != 
AV_PIX_FMT_GRAYF32LE
+            && !(c->opts.flags & SWS_BITEXACT)) {
+            if (c->opts.flags & SWS_ACCURATE_RND) {
 #if HAVE_MMXEXT_INLINE
-    if (INLINE_MMXEXT(cpu_flags))
-        sws_init_swscale_mmxext(c);
+                if (!(c->opts.flags & SWS_FULL_CHR_H_INT)) {
+                    switch (c->opts.dst_format) {
+                    case AV_PIX_FMT_RGB32:   c->yuv2packedX = 
yuv2rgb32_X_ar_mmxext;   break;
+#if HAVE_6REGS
+                    case AV_PIX_FMT_BGR24:   c->yuv2packedX = 
yuv2bgr24_X_ar_mmxext;   break;
 #endif
-    if(c->use_mmx_vfilter && !(c->opts.flags & SWS_ACCURATE_RND)) {
+                    case AV_PIX_FMT_RGB555:  c->yuv2packedX = 
yuv2rgb555_X_ar_mmxext;  break;
+                    case AV_PIX_FMT_RGB565:  c->yuv2packedX = 
yuv2rgb565_X_ar_mmxext;  break;
+                    case AV_PIX_FMT_YUYV422: c->yuv2packedX = 
yuv2yuyv422_X_ar_mmxext; break;
+                    default: break;
+                    }
+                }
+#endif
+            } else {
 #if HAVE_MMXEXT_EXTERNAL
-        if (EXTERNAL_MMXEXT(cpu_flags))
-            c->yuv2planeX = yuv2yuvX_mmxext;
-#endif
+                c->use_mmx_vfilter = 1;
+                c->yuv2planeX = yuv2yuvX_mmxext;
 #if HAVE_SSE3_EXTERNAL
-        if (EXTERNAL_SSE3(cpu_flags))
-            c->yuv2planeX = yuv2yuvX_sse3;
+                if (EXTERNAL_SSE3(cpu_flags))
+                    c->yuv2planeX = yuv2yuvX_sse3;
 #endif
 #if HAVE_AVX2_EXTERNAL
-        if (EXTERNAL_AVX2_FAST(cpu_flags))
-            c->yuv2planeX = yuv2yuvX_avx2;
+                if (EXTERNAL_AVX2_FAST(cpu_flags))
+                    c->yuv2planeX = yuv2yuvX_avx2;
+#endif
+#endif /* HAVE_MMXEXT_EXTERNAL */
+#if HAVE_MMXEXT_INLINE
+                if (!(c->opts.flags & SWS_FULL_CHR_H_INT)) {
+                    switch (c->opts.dst_format) {
+                    case AV_PIX_FMT_RGB32:   c->yuv2packedX = 
yuv2rgb32_X_mmxext;   break;
+                    case AV_PIX_FMT_BGR32:   c->yuv2packedX = 
yuv2bgr32_X_mmxext;   break;
+#if HAVE_6REGS
+                    case AV_PIX_FMT_BGR24:   c->yuv2packedX = 
yuv2bgr24_X_mmxext;   break;
+#endif
+                    case AV_PIX_FMT_RGB555:  c->yuv2packedX = 
yuv2rgb555_X_mmxext;  break;
+                    case AV_PIX_FMT_RGB565:  c->yuv2packedX = 
yuv2rgb565_X_mmxext;  break;
+                    case AV_PIX_FMT_YUYV422: c->yuv2packedX = 
yuv2yuyv422_X_mmxext; break;
+                    default: break;
+                    }
+                }
+#endif
+            }
+#if HAVE_MMXEXT_INLINE
+            if (!(c->opts.flags & SWS_FULL_CHR_H_INT)) {
+                switch (c->opts.dst_format) {
+                case AV_PIX_FMT_RGB32:
+                    c->yuv2packed1 = yuv2rgb32_1_mmxext;
+                    c->yuv2packed2 = yuv2rgb32_2_mmxext;
+                    break;
+                case AV_PIX_FMT_BGR24:
+                    c->yuv2packed1 = yuv2bgr24_1_mmxext;
+                    c->yuv2packed2 = yuv2bgr24_2_mmxext;
+                    break;
+                case AV_PIX_FMT_RGB555:
+                    c->yuv2packed1 = yuv2rgb555_1_mmxext;
+                    c->yuv2packed2 = yuv2rgb555_2_mmxext;
+                    break;
+                case AV_PIX_FMT_RGB565:
+                    c->yuv2packed1 = yuv2rgb565_1_mmxext;
+                    c->yuv2packed2 = yuv2rgb565_2_mmxext;
+                    break;
+                case AV_PIX_FMT_YUYV422:
+                    c->yuv2packed1 = yuv2yuyv422_1_mmxext;
+                    c->yuv2packed2 = yuv2yuyv422_2_mmxext;
+                    break;
+                default:
+                    break;
+                }
+            }
+#endif
+        }
+#if HAVE_MMXEXT_INLINE
+        if (c->srcBpc == 8 && c->dstBpc <= 14) {
+            // Use the new MMX scaler if the MMXEXT one can't be used (it is 
faster than the x86 ASM one).
+            if (c->opts.flags & SWS_FAST_BILINEAR && c->canMMXEXTBeUsed) {
+                c->hyscale_fast = ff_hyscale_fast_mmxext;
+                c->hcscale_fast = ff_hcscale_fast_mmxext;
+            } else {
+                c->hyscale_fast = NULL;
+                c->hcscale_fast = NULL;
+            }
+        }
 #endif
     }
 
diff --git a/libswscale/x86/swscale_template.c 
b/libswscale/x86/swscale_template.c
index 2313a649e9..94be51ff12 100644
--- a/libswscale/x86/swscale_template.c
+++ b/libswscale/x86/swscale_template.c
@@ -1326,79 +1326,3 @@ static void RENAME(yuv2yuyv422_1)(SwsInternal *c, const 
int16_t *buf0,
         );
     }
 }
-static av_cold void RENAME(sws_init_swscale)(SwsInternal *c)
-{
-    enum AVPixelFormat dstFormat = c->opts.dst_format;
-
-    c->use_mmx_vfilter= 0;
-    if (!is16BPS(dstFormat) && !isNBPS(dstFormat) && 
!isSemiPlanarYUV(dstFormat)
-        && dstFormat != AV_PIX_FMT_GRAYF32BE && dstFormat != 
AV_PIX_FMT_GRAYF32LE
-        && !(c->opts.flags & SWS_BITEXACT)) {
-            if (c->opts.flags & SWS_ACCURATE_RND) {
-                if (!(c->opts.flags & SWS_FULL_CHR_H_INT)) {
-                    switch (c->opts.dst_format) {
-                    case AV_PIX_FMT_RGB32:   c->yuv2packedX = 
RENAME(yuv2rgb32_X_ar);   break;
-#if HAVE_6REGS
-                    case AV_PIX_FMT_BGR24:   c->yuv2packedX = 
RENAME(yuv2bgr24_X_ar);   break;
-#endif
-                    case AV_PIX_FMT_RGB555:  c->yuv2packedX = 
RENAME(yuv2rgb555_X_ar);  break;
-                    case AV_PIX_FMT_RGB565:  c->yuv2packedX = 
RENAME(yuv2rgb565_X_ar);  break;
-                    case AV_PIX_FMT_YUYV422: c->yuv2packedX = 
RENAME(yuv2yuyv422_X_ar); break;
-                    default: break;
-                    }
-                }
-            } else {
-                c->use_mmx_vfilter= 1;
-                if (!(c->opts.flags & SWS_FULL_CHR_H_INT)) {
-                    switch (c->opts.dst_format) {
-                    case AV_PIX_FMT_RGB32:   c->yuv2packedX = 
RENAME(yuv2rgb32_X);   break;
-                    case AV_PIX_FMT_BGR32:   c->yuv2packedX = 
RENAME(yuv2bgr32_X);   break;
-#if HAVE_6REGS
-                    case AV_PIX_FMT_BGR24:   c->yuv2packedX = 
RENAME(yuv2bgr24_X);   break;
-#endif
-                    case AV_PIX_FMT_RGB555:  c->yuv2packedX = 
RENAME(yuv2rgb555_X);  break;
-                    case AV_PIX_FMT_RGB565:  c->yuv2packedX = 
RENAME(yuv2rgb565_X);  break;
-                    case AV_PIX_FMT_YUYV422: c->yuv2packedX = 
RENAME(yuv2yuyv422_X); break;
-                    default: break;
-                    }
-                }
-            }
-        if (!(c->opts.flags & SWS_FULL_CHR_H_INT)) {
-            switch (c->opts.dst_format) {
-            case AV_PIX_FMT_RGB32:
-                c->yuv2packed1 = RENAME(yuv2rgb32_1);
-                c->yuv2packed2 = RENAME(yuv2rgb32_2);
-                break;
-            case AV_PIX_FMT_BGR24:
-                c->yuv2packed1 = RENAME(yuv2bgr24_1);
-                c->yuv2packed2 = RENAME(yuv2bgr24_2);
-                break;
-            case AV_PIX_FMT_RGB555:
-                c->yuv2packed1 = RENAME(yuv2rgb555_1);
-                c->yuv2packed2 = RENAME(yuv2rgb555_2);
-                break;
-            case AV_PIX_FMT_RGB565:
-                c->yuv2packed1 = RENAME(yuv2rgb565_1);
-                c->yuv2packed2 = RENAME(yuv2rgb565_2);
-                break;
-            case AV_PIX_FMT_YUYV422:
-                c->yuv2packed1 = RENAME(yuv2yuyv422_1);
-                c->yuv2packed2 = RENAME(yuv2yuyv422_2);
-                break;
-            default:
-                break;
-            }
-        }
-    }
-
-    if (c->srcBpc == 8 && c->dstBpc <= 14) {
-        // Use the new MMX scaler if the MMXEXT one can't be used (it is 
faster than the x86 ASM one).
-        if (c->opts.flags & SWS_FAST_BILINEAR && c->canMMXEXTBeUsed) {
-            c->hyscale_fast = ff_hyscale_fast_mmxext;
-            c->hcscale_fast = ff_hcscale_fast_mmxext;
-        } else {
-            c->hyscale_fast = NULL;
-            c->hcscale_fast = NULL;
-        }
-    }
-}
-- 
2.52.0


>From 9f1116ef5a728c113bb00bfd9848cc4fe67dff70 Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <[email protected]>
Date: Wed, 22 Apr 2026 14:50:22 +0200
Subject: [PATCH 2/3] swscale/x86/yuv2yuvX: Port ff_yuv2yuvX_mmxext to SSE2

The mmx function performs two registers in parallel;
given the larger register size of SSE2, the same amount
of data can be processed in one register with some speedups.
(Given that this function is used for tail-processing,
not processing more data is important.)

Switching to SSE2 also fixes a bug introduced in
554c2bc7086f49ef5a6a989ad6bc4bc11807eb6f: Since said
commit, only half the dither values were used. This
seems to matter in practice, as the functions here
use dither only in the following form:
((filtersize-1)*8+dither)>>4. The dither values used
here come from ff_dither_8x8_128 which has the property
that ff_dither_8x8_128[i][j] and ff_dither_8x8_128[i][j+4]
always lead to the same result in the above formula.

Old benchmarks:
yuv2yuvX_8_2_0_512_approximate_c:                     2309.9 ( 1.00x)
yuv2yuvX_8_2_0_512_approximate_mmxext:                 250.2 ( 9.23x)
yuv2yuvX_8_2_0_512_approximate_sse3:                    98.8 (23.39x)
yuv2yuvX_8_2_0_512_approximate_avx2:                    52.9 (43.63x)
yuv2yuvX_8_2_16_512_approximate_c:                    2263.0 ( 1.00x)
yuv2yuvX_8_2_16_512_approximate_mmxext:                245.3 ( 9.22x)
yuv2yuvX_8_2_16_512_approximate_sse3:                  114.3 (19.80x)
yuv2yuvX_8_2_16_512_approximate_avx2:                   85.6 (26.45x)
yuv2yuvX_8_2_32_512_approximate_c:                    2155.8 ( 1.00x)
yuv2yuvX_8_2_32_512_approximate_mmxext:                235.6 ( 9.15x)
yuv2yuvX_8_2_32_512_approximate_sse3:                   93.6 (23.04x)
yuv2yuvX_8_2_32_512_approximate_avx2:                   78.1 (27.60x)
yuv2yuvX_8_2_48_512_approximate_c:                    2084.8 ( 1.00x)
yuv2yuvX_8_2_48_512_approximate_mmxext:                230.2 ( 9.05x)
yuv2yuvX_8_2_48_512_approximate_sse3:                  105.0 (19.85x)
yuv2yuvX_8_2_48_512_approximate_avx2:                   71.9 (29.00x)
yuv2yuvX_8_4_0_512_approximate_c:                     3496.3 ( 1.00x)
yuv2yuvX_8_4_0_512_approximate_mmxext:                 455.0 ( 7.68x)
yuv2yuvX_8_4_0_512_approximate_sse3:                   157.5 (22.20x)
yuv2yuvX_8_4_0_512_approximate_avx2:                    88.4 (39.53x)
yuv2yuvX_8_4_16_512_approximate_c:                    3380.9 ( 1.00x)
yuv2yuvX_8_4_16_512_approximate_mmxext:                440.0 ( 7.68x)
yuv2yuvX_8_4_16_512_approximate_sse3:                  175.0 (19.32x)
yuv2yuvX_8_4_16_512_approximate_avx2:                  134.1 (25.22x)
yuv2yuvX_8_4_32_512_approximate_c:                    3277.6 ( 1.00x)
yuv2yuvX_8_4_32_512_approximate_mmxext:                427.2 ( 7.67x)
yuv2yuvX_8_4_32_512_approximate_sse3:                  149.7 (21.89x)
yuv2yuvX_8_4_32_512_approximate_avx2:                  115.5 (28.37x)
yuv2yuvX_8_4_48_512_approximate_c:                    3167.8 ( 1.00x)
yuv2yuvX_8_4_48_512_approximate_mmxext:                414.9 ( 7.63x)
yuv2yuvX_8_4_48_512_approximate_sse3:                  164.1 (19.31x)
yuv2yuvX_8_4_48_512_approximate_avx2:                  101.2 (31.30x)
yuv2yuvX_8_8_0_512_approximate_c:                     5987.5 ( 1.00x)
yuv2yuvX_8_8_0_512_approximate_mmxext:                 854.1 ( 7.01x)
yuv2yuvX_8_8_0_512_approximate_sse3:                   294.6 (20.32x)
yuv2yuvX_8_8_0_512_approximate_avx2:                   144.1 (41.56x)
yuv2yuvX_8_8_16_512_approximate_c:                    5848.9 ( 1.00x)
yuv2yuvX_8_8_16_512_approximate_mmxext:                834.4 ( 7.01x)
yuv2yuvX_8_8_16_512_approximate_sse3:                  312.1 (18.74x)
yuv2yuvX_8_8_16_512_approximate_avx2:                  214.9 (27.22x)
yuv2yuvX_8_8_32_512_approximate_c:                    5610.1 ( 1.00x)
yuv2yuvX_8_8_32_512_approximate_mmxext:                811.6 ( 6.91x)
yuv2yuvX_8_8_32_512_approximate_sse3:                  277.5 (20.21x)
yuv2yuvX_8_8_32_512_approximate_avx2:                  189.8 (29.55x)
yuv2yuvX_8_8_48_512_approximate_c:                    5415.8 ( 1.00x)
yuv2yuvX_8_8_48_512_approximate_mmxext:                782.3 ( 6.92x)
yuv2yuvX_8_8_48_512_approximate_sse3:                  289.4 (18.72x)
yuv2yuvX_8_8_48_512_approximate_avx2:                  165.3 (32.76x)
yuv2yuvX_8_16_0_512_approximate_c:                   11100.7 ( 1.00x)
yuv2yuvX_8_16_0_512_approximate_mmxext:               1682.1 ( 6.60x)
yuv2yuvX_8_16_0_512_approximate_sse3:                  558.8 (19.86x)
yuv2yuvX_8_16_0_512_approximate_avx2:                  280.1 (39.63x)
yuv2yuvX_8_16_16_512_approximate_c:                  10772.1 ( 1.00x)
yuv2yuvX_8_16_16_512_approximate_mmxext:              1611.0 ( 6.69x)
yuv2yuvX_8_16_16_512_approximate_sse3:                 578.1 (18.63x)
yuv2yuvX_8_16_16_512_approximate_avx2:                 418.8 (25.72x)
yuv2yuvX_8_16_32_512_approximate_c:                  10381.5 ( 1.00x)
yuv2yuvX_8_16_32_512_approximate_mmxext:              1560.4 ( 6.65x)
yuv2yuvX_8_16_32_512_approximate_sse3:                 525.8 (19.74x)
yuv2yuvX_8_16_32_512_approximate_avx2:                 370.7 (28.01x)
yuv2yuvX_8_16_48_512_approximate_c:                  10046.1 ( 1.00x)
yuv2yuvX_8_16_48_512_approximate_mmxext:              1512.4 ( 6.64x)
yuv2yuvX_8_16_48_512_approximate_sse3:                 546.0 (18.40x)
yuv2yuvX_8_16_48_512_approximate_avx2:                 315.0 (31.89x)

New benchmarks:
yuv2yuvX_8_2_0_512_approximate_c:                     2302.5 ( 1.00x)
yuv2yuvX_8_2_0_512_approximate_sse2:                   184.4 (12.49x)
yuv2yuvX_8_2_0_512_approximate_sse3:                   100.1 (23.01x)
yuv2yuvX_8_2_0_512_approximate_avx2:                    54.9 (41.98x)
yuv2yuvX_8_2_16_512_approximate_c:                    2224.6 ( 1.00x)
yuv2yuvX_8_2_16_512_approximate_sse2:                  180.0 (12.36x)
yuv2yuvX_8_2_16_512_approximate_sse3:                  109.5 (20.31x)
yuv2yuvX_8_2_16_512_approximate_avx2:                   81.3 (27.35x)
yuv2yuvX_8_2_32_512_approximate_c:                    2165.3 ( 1.00x)
yuv2yuvX_8_2_32_512_approximate_sse2:                  176.6 (12.26x)
yuv2yuvX_8_2_32_512_approximate_sse3:                   93.7 (23.11x)
yuv2yuvX_8_2_32_512_approximate_avx2:                   73.1 (29.61x)
yuv2yuvX_8_2_48_512_approximate_c:                    2088.0 ( 1.00x)
yuv2yuvX_8_2_48_512_approximate_sse2:                  170.7 (12.23x)
yuv2yuvX_8_2_48_512_approximate_sse3:                  103.4 (20.20x)
yuv2yuvX_8_2_48_512_approximate_avx2:                   69.4 (30.10x)
yuv2yuvX_8_4_0_512_approximate_c:                     3496.8 ( 1.00x)
yuv2yuvX_8_4_0_512_approximate_sse2:                   320.3 (10.92x)
yuv2yuvX_8_4_0_512_approximate_sse3:                   158.8 (22.02x)
yuv2yuvX_8_4_0_512_approximate_avx2:                    86.4 (40.49x)
yuv2yuvX_8_4_16_512_approximate_c:                    3443.5 ( 1.00x)
yuv2yuvX_8_4_16_512_approximate_sse2:                  325.3 (10.59x)
yuv2yuvX_8_4_16_512_approximate_sse3:                  171.9 (20.03x)
yuv2yuvX_8_4_16_512_approximate_avx2:                  123.6 (27.85x)
yuv2yuvX_8_4_32_512_approximate_c:                    3272.2 ( 1.00x)
yuv2yuvX_8_4_32_512_approximate_sse2:                  302.7 (10.81x)
yuv2yuvX_8_4_32_512_approximate_sse3:                  148.9 (21.98x)
yuv2yuvX_8_4_32_512_approximate_avx2:                  110.6 (29.58x)
yuv2yuvX_8_4_48_512_approximate_c:                    3166.3 ( 1.00x)
yuv2yuvX_8_4_48_512_approximate_sse2:                  291.0 (10.88x)
yuv2yuvX_8_4_48_512_approximate_sse3:                  162.9 (19.44x)
yuv2yuvX_8_4_48_512_approximate_avx2:                  102.3 (30.95x)
yuv2yuvX_8_8_0_512_approximate_c:                     5967.6 ( 1.00x)
yuv2yuvX_8_8_0_512_approximate_sse2:                   691.2 ( 8.63x)
yuv2yuvX_8_8_0_512_approximate_sse3:                   294.2 (20.28x)
yuv2yuvX_8_8_0_512_approximate_avx2:                   154.9 (38.52x)
yuv2yuvX_8_8_16_512_approximate_c:                    5780.2 ( 1.00x)
yuv2yuvX_8_8_16_512_approximate_sse2:                  606.2 ( 9.53x)
yuv2yuvX_8_8_16_512_approximate_sse3:                  309.3 (18.69x)
yuv2yuvX_8_8_16_512_approximate_avx2:                  208.7 (27.69x)
yuv2yuvX_8_8_32_512_approximate_c:                    5604.3 ( 1.00x)
yuv2yuvX_8_8_32_512_approximate_sse2:                  592.3 ( 9.46x)
yuv2yuvX_8_8_32_512_approximate_sse3:                  281.1 (19.94x)
yuv2yuvX_8_8_32_512_approximate_avx2:                  185.4 (30.23x)
yuv2yuvX_8_8_48_512_approximate_c:                    5413.7 ( 1.00x)
yuv2yuvX_8_8_48_512_approximate_sse2:                  570.4 ( 9.49x)
yuv2yuvX_8_8_48_512_approximate_sse3:                  294.9 (18.36x)
yuv2yuvX_8_8_48_512_approximate_avx2:                  166.5 (32.51x)
yuv2yuvX_8_16_0_512_approximate_c:                   11099.4 ( 1.00x)
yuv2yuvX_8_16_0_512_approximate_sse2:                 1213.6 ( 9.15x)
yuv2yuvX_8_16_0_512_approximate_sse3:                  563.0 (19.72x)
yuv2yuvX_8_16_0_512_approximate_avx2:                  294.8 (37.65x)
yuv2yuvX_8_16_16_512_approximate_c:                  10718.1 ( 1.00x)
yuv2yuvX_8_16_16_512_approximate_sse2:                1121.2 ( 9.56x)
yuv2yuvX_8_16_16_512_approximate_sse3:                 563.7 (19.01x)
yuv2yuvX_8_16_16_512_approximate_avx2:                 389.5 (27.51x)
yuv2yuvX_8_16_32_512_approximate_c:                  10373.3 ( 1.00x)
yuv2yuvX_8_16_32_512_approximate_sse2:                1096.2 ( 9.46x)
yuv2yuvX_8_16_32_512_approximate_sse3:                 526.7 (19.70x)
yuv2yuvX_8_16_32_512_approximate_avx2:                 354.7 (29.24x)
yuv2yuvX_8_16_48_512_approximate_c:                  10066.9 ( 1.00x)
yuv2yuvX_8_16_48_512_approximate_sse2:                1055.8 ( 9.53x)
yuv2yuvX_8_16_48_512_approximate_sse3:                 527.9 (19.07x)
yuv2yuvX_8_16_48_512_approximate_avx2:                 313.7 (32.09x)

Signed-off-by: Andreas Rheinhardt <[email protected]>
---
 libswscale/x86/swscale.c    | 51 ++++++++++++++++++-------------------
 libswscale/x86/yuv2yuvX.asm | 44 ++++++++++++++++++--------------
 tests/checkasm/sw_scale.c   |  6 ++---
 3 files changed, 53 insertions(+), 48 deletions(-)

diff --git a/libswscale/x86/swscale.c b/libswscale/x86/swscale.c
index 26fd8aed3c..25461d787f 100644
--- a/libswscale/x86/swscale.c
+++ b/libswscale/x86/swscale.c
@@ -174,19 +174,6 @@ void ff_updateMMXDitherTables(SwsInternal *c, int dstY)
     }
 }
 
-#define YUV2YUVX_FUNC_MMX(opt, step)  \
-void ff_yuv2yuvX_ ##opt(const int16_t *filter, int filterSize, int srcOffset, \
-                           uint8_t *dest, int dstW,  \
-                           const uint8_t *dither, int offset); \
-static void yuv2yuvX_ ##opt(const int16_t *filter, int filterSize, \
-                           const int16_t **src, uint8_t *dest, int dstW, \
-                           const uint8_t *dither, int offset) \
-{ \
-    if(dstW > 0) \
-        ff_yuv2yuvX_ ##opt(filter, filterSize - 1, 0, dest - offset, dstW + 
offset, dither, offset); \
-    return; \
-}
-
 #define YUV2YUVX_FUNC(opt, step)  \
 void ff_yuv2yuvX_ ##opt(const int16_t *filter, int filterSize, int srcOffset, \
                            uint8_t *dest, int dstW,  \
@@ -198,26 +185,36 @@ static void yuv2yuvX_ ##opt(const int16_t *filter, int 
filterSize, \
     int remainder = (dstW % step); \
     int pixelsProcessed = dstW - remainder; \
     if(((uintptr_t)dest) & 15){ \
-        yuv2yuvX_mmxext(filter, filterSize, src, dest, dstW, dither, offset); \
+        yuv2yuvX_sse2(filter, filterSize, src, dest, dstW, dither, offset); \
         return; \
     } \
     if(pixelsProcessed > 0) \
         ff_yuv2yuvX_ ##opt(filter, filterSize - 1, 0, dest - offset, 
pixelsProcessed + offset, dither, offset); \
     if(remainder > 0){ \
-      ff_yuv2yuvX_mmxext(filter, filterSize - 1, pixelsProcessed, dest - 
offset, pixelsProcessed + remainder + offset, dither, offset); \
+        ff_yuv2yuvX_sse2(filter, filterSize - 1, pixelsProcessed, dest - 
offset, pixelsProcessed + remainder + offset, dither, offset); \
     } \
     return; \
 }
 
-#if HAVE_MMXEXT_EXTERNAL
-YUV2YUVX_FUNC_MMX(mmxext, 16)
-#endif
+#if HAVE_SSE2_EXTERNAL
+void ff_yuv2yuvX_sse2(const int16_t *filter, int filterSize, int srcOffset,
+                      uint8_t *dest, int dstW,
+                      const uint8_t *dither, int offset);
+static void yuv2yuvX_sse2(const int16_t *filter, int filterSize,
+                          const int16_t **src, uint8_t *dest, int dstW,
+                           const uint8_t *dither, int offset)
+{
+    if (dstW > 0)
+        ff_yuv2yuvX_sse2(filter, filterSize - 1, 0, dest - offset, dstW + 
offset, dither, offset);
+    return;
+}
 #if HAVE_SSE3_EXTERNAL
 YUV2YUVX_FUNC(sse3, 32)
 #endif
 #if HAVE_AVX2_EXTERNAL
 YUV2YUVX_FUNC(avx2, 64)
 #endif
+#endif
 
 #define SCALE_FUNC(filter_n, from_bpc, to_bpc, opt) \
 void ff_hscale ## from_bpc ## to ## to_bpc ## _ ## filter_n ## _ ## opt( \
@@ -513,18 +510,20 @@ av_cold void ff_sws_init_swscale_x86(SwsInternal *c)
                 }
 #endif
             } else {
-#if HAVE_MMXEXT_EXTERNAL
-                c->use_mmx_vfilter = 1;
-                c->yuv2planeX = yuv2yuvX_mmxext;
+#if HAVE_SSE2_EXTERNAL
+                if (EXTERNAL_SSE2(cpu_flags)) {
+                    c->use_mmx_vfilter = 1;
+                    c->yuv2planeX = yuv2yuvX_sse2;
 #if HAVE_SSE3_EXTERNAL
-                if (EXTERNAL_SSE3(cpu_flags))
-                    c->yuv2planeX = yuv2yuvX_sse3;
+                    if (EXTERNAL_SSE3(cpu_flags))
+                        c->yuv2planeX = yuv2yuvX_sse3;
 #endif
 #if HAVE_AVX2_EXTERNAL
-                if (EXTERNAL_AVX2_FAST(cpu_flags))
-                    c->yuv2planeX = yuv2yuvX_avx2;
+                    if (EXTERNAL_AVX2_FAST(cpu_flags))
+                        c->yuv2planeX = yuv2yuvX_avx2;
 #endif
-#endif /* HAVE_MMXEXT_EXTERNAL */
+                }
+#endif /* HAVE_SSE2_EXTERNAL */
 #if HAVE_MMXEXT_INLINE
                 if (!(c->opts.flags & SWS_FULL_CHR_H_INT)) {
                     switch (c->opts.dst_format) {
diff --git a/libswscale/x86/yuv2yuvX.asm b/libswscale/x86/yuv2yuvX.asm
index 7137be2e17..66eff06e03 100644
--- a/libswscale/x86/yuv2yuvX.asm
+++ b/libswscale/x86/yuv2yuvX.asm
@@ -34,13 +34,13 @@ SECTION .text
 ;-----------------------------------------------------------------------------
 
 %macro YUV2YUVX_FUNC 0
-cglobal yuv2yuvX, 7, 7, 8, filter, filterSize, src, dest, dstW, dither, offset
+cglobal yuv2yuvX, 7, 7, 6+2*cpuflag(sse3), filter, filterSize, src, dest, 
dstW, dither, offset
 %if notcpuflag(sse3)
-%define movr mova
+%define movr movq
 %define unroll 1
 %else
 %define movr movdqu
-%define unroll 2
+%define unroll 4
 %endif
     movsxdifnidn         dstWq, dstWd
     movsxdifnidn         offsetq, offsetd
@@ -67,14 +67,14 @@ cglobal yuv2yuvX, 7, 7, 8, filter, filterSize, src, dest, 
dstW, dither, offset
     mov                  srcq, [filterSizeq]
     punpcklbw            m3, m0
     psllw                m1, m1, 3
-    paddw                m3, m3, m1
-    psraw                m7, m3, 4
+    paddw                m1, m3
+    psraw                m1, 4
 .outerloop:
-    mova                 m4, m7
-    mova                 m3, m7
+    mova                 m3, m1
 %if cpuflag(sse3)
-    mova                 m6, m7
-    mova                 m1, m7
+    mova                 m4, m1
+    mova                 m6, m1
+    mova                 m7, m1
 %endif
 .loop:
 %if cpuflag(avx2)
@@ -82,31 +82,37 @@ cglobal yuv2yuvX, 7, 7, 8, filter, filterSize, src, dest, 
dstW, dither, offset
 %elif cpuflag(sse3)
     movddup              m0, [filterSizeq + 8]
 %else
-    mova                 m0, [filterSizeq + 8]
+    movq                 m0, [filterSizeq + 8]
+    punpcklqdq           m0, m0
 %endif
+
+%if cpuflag(sse3)
     pmulhw               m2, m0, [srcq + offsetq * 2]
     pmulhw               m5, m0, [srcq + offsetq * 2 + mmsize]
     paddw                m3, m3, m2
     paddw                m4, m4, m5
-%if cpuflag(sse3)
     pmulhw               m2, m0, [srcq + offsetq * 2 + 2 * mmsize]
     pmulhw               m5, m0, [srcq + offsetq * 2 + 3 * mmsize]
     paddw                m6, m6, m2
-    paddw                m1, m1, m5
+    paddw                m7, m7, m5
+%else
+    movu                 m2, [srcq + offsetq * 2]
+    pmulhw               m2, m0
+    paddw                m3, m2
 %endif
     add                  filterSizeq, 0x10
     mov                  srcq, [filterSizeq]
     test                 srcq, srcq
     jnz                  .loop
     psraw                m3, m3, 3
+%if cpuflag(sse3)
     psraw                m4, m4, 3
-%if cpuflag(sse3)
     psraw                m6, m6, 3
-    psraw                m1, m1, 3
-%endif
+    psraw                m7, m7, 3
     packuswb             m3, m3, m4
-%if cpuflag(sse3)
-    packuswb             m6, m6, m1
+    packuswb             m6, m6, m7
+%else
+    packuswb             m3, m3
 %endif
     mov                  srcq, [filterq]
 %if cpuflag(avx2)
@@ -117,14 +123,14 @@ cglobal yuv2yuvX, 7, 7, 8, filter, filterSize, src, dest, 
dstW, dither, offset
 %if cpuflag(sse3)
     movr                 [destq + offsetq + mmsize], m6
 %endif
-    add                  offsetq, mmsize * unroll
+    add                  offsetq, mmsize / 2 * unroll
     mov                  filterSizeq, filterq
     cmp                  offsetq, dstWq
     jb                  .outerloop
     RET
 %endmacro
 
-INIT_MMX mmxext
+INIT_XMM sse2
 YUV2YUVX_FUNC
 INIT_XMM sse3
 YUV2YUVX_FUNC
diff --git a/tests/checkasm/sw_scale.c b/tests/checkasm/sw_scale.c
index f3dd0019e5..3c33785122 100644
--- a/tests/checkasm/sw_scale.c
+++ b/tests/checkasm/sw_scale.c
@@ -181,9 +181,9 @@ static void check_yuv2yuvX(int accurate, int bit_depth, int 
dst_pix_format)
     static const int input_sizes[] = {8, 24, 128, 144, 256, 512};
     const char *accurate_str = (accurate) ? "accurate" : "approximate";
 
-    declare_func_emms(AV_CPU_FLAG_MMX, void, const int16_t *filter,
-                      int filterSize, const int16_t **src, uint8_t *dest,
-                      int dstW, const uint8_t *dither, int offset);
+    declare_func(void, const int16_t *filter,
+                       int filterSize, const int16_t **src, uint8_t *dest,
+                       int dstW, const uint8_t *dither, int offset);
 
     const int16_t **src;
     LOCAL_ALIGNED_16(int16_t, src_pixels, [LARGEST_FILTER * 
LARGEST_INPUT_SIZE]);
-- 
2.52.0


>From 9d94e7bcaf4bb89216b50e5d585b7cca0cedefed Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <[email protected]>
Date: Wed, 22 Apr 2026 15:36:12 +0200
Subject: [PATCH 3/3] swscale/x86/yuv2yuvX: Simplify rotating

Signed-off-by: Andreas Rheinhardt <[email protected]>
---
 libswscale/x86/yuv2yuvX.asm | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/libswscale/x86/yuv2yuvX.asm b/libswscale/x86/yuv2yuvX.asm
index 66eff06e03..54a87d44bc 100644
--- a/libswscale/x86/yuv2yuvX.asm
+++ b/libswscale/x86/yuv2yuvX.asm
@@ -54,9 +54,10 @@ cglobal yuv2yuvX, 7, 7, 6+2*cpuflag(sse3), filter, 
filterSize, src, dest, dstW,
     jz                   .offset
 
     ; offset != 0 path.
-    psrlq                m5, m3, 0x18
-    psllq                m3, m3, 0x28
-    por                  m3, m3, m5
+%if notcpuflag(avx2)
+    punpcklqdq           m3, m3
+%endif
+    psrldq               m3, 3
 
 .offset:
     add offsetq, srcq
-- 
2.52.0

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

Reply via email to