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

I know little about Vulkan so I asked AI to do it. My goal is to improve 
`libswscale/tests/swscale` but these issues got in the way.

@Lynne please review.


>From 30dcc3595f873c1bad1f85dab2b8c7aa526abcb8 Mon Sep 17 00:00:00 2001
From: Ramiro Polla <[email protected]>
Date: Mon, 19 Oct 2026 14:04:29 +0200
Subject: [PATCH 1/3] swscale/vulkan/ops: initialize unused float lanes to zero

The working vector and the unused lanes of planar float reads were
filled with OpUndef. Linear ops consume the full vector, and an
undefined float is not guaranteed to be finite, so a zero matrix
coefficient does not reliably cancel its contribution. This made
float input conversions such as gbrpf32le -> yuv444p fail on some
drivers (NVIDIA).

Use a 0.0 constant instead.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
---
 libswscale/vulkan/ops.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libswscale/vulkan/ops.c b/libswscale/vulkan/ops.c
index 68750dc3bb..a9e45bb116 100644
--- a/libswscale/vulkan/ops.c
+++ b/libswscale/vulkan/ops.c
@@ -506,7 +506,7 @@ static void define_shader_consts(SwsContext *sws, const 
SwsOpList *ops,
 
     /* Constants */
     id->u32_p = spi_OpUndef(spi, u32_type);
-    id->f32_p = spi_OpUndef(spi, f32_type);
+    id->f32_p = spi_OpConstantFloat(spi, f32_type, 0);
     id->f32_0 = spi_OpConstantFloat(spi, f32_type, 0);
     for (int i = 0; i < 5; i++)
         id->u32_cid[i] = spi_OpConstantUInt(spi, u32_type, i);
-- 
2.54.0


>From 4f4000f30d0e95adfe70ca618c1cd2fcea43dd2e Mon Sep 17 00:00:00 2001
From: Ramiro Polla <[email protected]>
Date: Mon, 19 Oct 2026 14:04:29 +0200
Subject: [PATCH 2/3] tests/fate/libswscale: enable spirv backend tests

Co-Authored-By: Claude Opus 5.5 <[email protected]>
---
 tests/fate/libswscale.mak | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/tests/fate/libswscale.mak b/tests/fate/libswscale.mak
index cba28068ed..7357a7d0f4 100644
--- a/tests/fate/libswscale.mak
+++ b/tests/fate/libswscale.mak
@@ -54,9 +54,8 @@ endif
 ifeq ($(ARCH_AARCH64),yes)
 SWS_UNSTABLE_BACKENDS-$(HAVE_NEON)                   += aarch64
 endif
-# TODO: enable spirv tests once they pass on all Vulkan devices.
-# SWS_UNSTABLE_BACKENDS-$(HAVE_SPIRV_HEADERS_SPIRV_H)  += spirv
-# SWS_UNSTABLE_BACKENDS-$(HAVE_SPIRV_UNIFIED1_SPIRV_H) += spirv
+SWS_UNSTABLE_BACKENDS-$(HAVE_SPIRV_HEADERS_SPIRV_H)  += spirv
+SWS_UNSTABLE_BACKENDS-$(HAVE_SPIRV_UNIFIED1_SPIRV_H) += spirv
 
 # Set -hw default for Vulkan tests.
 fate-sws-unscaled-spirv fate-sws-unstable-spirv: SWS_HW = -hw default
-- 
2.54.0


>From a62ed056d024d41cc5b2e62f26bd2c98c5e1e3eb Mon Sep 17 00:00:00 2001
From: Ramiro Polla <[email protected]>
Date: Mon, 19 Oct 2026 14:14:12 +0200
Subject: [PATCH 3/3] swscale: gate Vulkan support on the SPIR-V backend being
 available

If Vulkan was enabled but no SPIR-V headers were found, the Vulkan code
in swscale was still compiled, but no backend was exported. Vulkan
frames were still reported as supported by sws_test_hw_format().

Add a swscale_vulkan configure symbol, enabled when Vulkan and either
SPIR-V header are available, and use it for all Vulkan code in swscale
and for the spirv FATE tests.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
---
 configure                  | 3 +++
 libswscale/format.c        | 2 +-
 libswscale/graph.c         | 8 ++++----
 libswscale/ops.c           | 4 ++--
 libswscale/swscale.c       | 4 ++--
 libswscale/utils.c         | 2 +-
 libswscale/vulkan/Makefile | 2 +-
 libswscale/vulkan/ops.c    | 9 ---------
 tests/fate/libswscale.mak  | 3 +--
 9 files changed, 15 insertions(+), 22 deletions(-)

diff --git a/configure b/configure
index d2a69d7783..7b0f157b8e 100755
--- a/configure
+++ b/configure
@@ -2794,6 +2794,7 @@ CONFIG_EXTRA="
     snappy
     srtp
     startcode
+    swscale_vulkan
     texturedsp
     texturedspenc
     tpeldsp
@@ -3363,6 +3364,8 @@ vulkan_deps="threads"
 vulkan_deps_any="libdl LoadLibrary"
 spirv_headers_spirv_h_deps="vulkan"
 spirv_unified1_spirv_h_deps="vulkan"
+swscale_vulkan_deps="vulkan"
+swscale_vulkan_if_any="spirv_headers_spirv_h spirv_unified1_spirv_h"
 
 apv_vulkan_hwaccel_deps="vulkan spirv_compiler"
 apv_vulkan_hwaccel_select="apv_decoder"
diff --git a/libswscale/format.c b/libswscale/format.c
index f8c6462982..59b0ec1afd 100644
--- a/libswscale/format.c
+++ b/libswscale/format.c
@@ -643,7 +643,7 @@ int sws_test_hw_format(enum AVPixelFormat format)
 {
     switch (format) {
     case AV_PIX_FMT_NONE: return 1;
-#if CONFIG_VULKAN
+#if CONFIG_SWSCALE_VULKAN
     case AV_PIX_FMT_VULKAN: return 1;
 #endif
     default: return 0;
diff --git a/libswscale/graph.c b/libswscale/graph.c
index 5a5d469a51..664dd1c1c3 100644
--- a/libswscale/graph.c
+++ b/libswscale/graph.c
@@ -39,7 +39,7 @@
 #include "graph.h"
 #include "ops.h"
 #include "ops_dispatch.h"
-#if CONFIG_VULKAN
+#if CONFIG_SWSCALE_VULKAN
 #include "vulkan/ops.h"
 #endif
 
@@ -102,7 +102,7 @@ static int frame_alloc_planes_ref(AVFrame *dst, const 
AVFrame *src,
     return 0;
 }
 
-#if CONFIG_VULKAN
+#if CONFIG_SWSCALE_VULKAN
 static int pass_alloc_output_hw(SwsPass *pass, AVFrame *avframe,
                                 AVBufferRef *dev_ref)
 {
@@ -141,7 +141,7 @@ static int pass_alloc_output(SwsPass *pass)
 
     int ret;
 
-#if CONFIG_VULKAN
+#if CONFIG_SWSCALE_VULKAN
     const SwsGraph *graph = pass->graph;
     if (graph->src.hw_format == AV_PIX_FMT_VULKAN &&
         graph->dst.hw_format == AV_PIX_FMT_VULKAN) {
@@ -166,7 +166,7 @@ static int pass_alloc_output(SwsPass *pass)
         return ret;
     }
 
-#if CONFIG_VULKAN
+#if CONFIG_SWSCALE_VULKAN
 done:
 #endif
     buffer->avframe = avframe;
diff --git a/libswscale/ops.c b/libswscale/ops.c
index c07261c61e..59e874bec8 100644
--- a/libswscale/ops.c
+++ b/libswscale/ops.c
@@ -35,7 +35,7 @@ extern const SwsOpBackend backend_c;
 extern const SwsOpBackend backend_murder;
 extern const SwsOpBackend backend_aarch64;
 extern const SwsOpBackend backend_x86;
-#if HAVE_SPIRV_HEADERS_SPIRV_H || HAVE_SPIRV_UNIFIED1_SPIRV_H
+#if CONFIG_SWSCALE_VULKAN
 extern const SwsOpBackend backend_spirv;
 #endif
 
@@ -47,7 +47,7 @@ const SwsOpBackend * const ff_sws_op_backends[] = {
     &backend_x86,
 #endif
     &backend_c,
-#if HAVE_SPIRV_HEADERS_SPIRV_H || HAVE_SPIRV_UNIFIED1_SPIRV_H
+#if CONFIG_SWSCALE_VULKAN
     &backend_spirv,
 #endif
     NULL
diff --git a/libswscale/swscale.c b/libswscale/swscale.c
index 070b0f5939..80b30bcf69 100644
--- a/libswscale/swscale.c
+++ b/libswscale/swscale.c
@@ -35,7 +35,7 @@
 #include "config.h"
 #include "swscale_internal.h"
 #include "swscale.h"
-#if CONFIG_VULKAN
+#if CONFIG_SWSCALE_VULKAN
 #include "vulkan/ops.h"
 #endif
 
@@ -1542,7 +1542,7 @@ int sws_frame_setup(SwsContext *ctx, const AVFrame *dst, 
const AVFrame *src)
         if (dev_ctx->type != AV_HWDEVICE_TYPE_VULKAN)
             return AVERROR(ENOTSUP);
 
-#if CONFIG_UNSTABLE && CONFIG_VULKAN
+#if CONFIG_UNSTABLE && CONFIG_SWSCALE_VULKAN
         ret = ff_sws_vk_init(ctx, src_hwfc->device_ref);
         if (ret < 0)
             return ret;
diff --git a/libswscale/utils.c b/libswscale/utils.c
index 138c1a4edd..e970b9f035 100644
--- a/libswscale/utils.c
+++ b/libswscale/utils.c
@@ -52,7 +52,7 @@
 #include "graph.h"
 #include "jit.h"
 
-#if CONFIG_VULKAN
+#if CONFIG_SWSCALE_VULKAN
 #include "vulkan/ops.h"
 #endif
 
diff --git a/libswscale/vulkan/Makefile b/libswscale/vulkan/Makefile
index 396cdeb936..c3eef141cb 100644
--- a/libswscale/vulkan/Makefile
+++ b/libswscale/vulkan/Makefile
@@ -1,4 +1,4 @@
 clean::
        $(RM) $(CLEANSUFFIXES:%=libswscale/vulkan/%)
 
-OBJS-$(CONFIG_VULKAN) += vulkan/ops.o vulkan/vulkan.o
+OBJS-$(CONFIG_SWSCALE_VULKAN) += vulkan/ops.o vulkan/vulkan.o
diff --git a/libswscale/vulkan/ops.c b/libswscale/vulkan/ops.c
index a9e45bb116..3f8c34ecda 100644
--- a/libswscale/vulkan/ops.c
+++ b/libswscale/vulkan/ops.c
@@ -27,9 +27,7 @@
 
 #include "ops.h"
 
-#if HAVE_SPIRV_HEADERS_SPIRV_H || HAVE_SPIRV_UNIFIED1_SPIRV_H
 #include "spvasm.h"
-#endif
 
 static void ff_sws_vk_uninit(AVRefStructOpaque opaque, void *obj)
 {
@@ -278,7 +276,6 @@ fail:
     return err;
 }
 
-#if HAVE_SPIRV_HEADERS_SPIRV_H || HAVE_SPIRV_UNIFIED1_SPIRV_H
 struct DitherData {
         int size;
         int arr_1d_id;
@@ -1276,7 +1273,6 @@ static int add_ops_spirv(SwsContext *sws, VulkanPriv *p, 
FFVulkanOpsCtx *s,
 
     return ff_vk_shader_link(&s->vkctx, shd, spvbuf, len, "main");
 }
-#endif
 
 static int compile(SwsContext *sws, const SwsOpList *ops, SwsCompiledOp *out)
 {
@@ -1296,10 +1292,7 @@ static int compile(SwsContext *sws, const SwsOpList 
*ops, SwsCompiledOp *out)
     if (err < 0)
         goto fail;
 
-    err = AVERROR(ENOTSUP);
-#if HAVE_SPIRV_HEADERS_SPIRV_H || HAVE_SPIRV_UNIFIED1_SPIRV_H
     err = add_ops_spirv(sws, p, s, ops, &p->shd);
-#endif
     if (err < 0)
         goto fail;
 
@@ -1326,7 +1319,6 @@ fail:
     return err;
 }
 
-#if HAVE_SPIRV_HEADERS_SPIRV_H || HAVE_SPIRV_UNIFIED1_SPIRV_H
 static int compile_spirv(SwsContext *sws, const SwsOpList *ops,
                          SwsCompiledOp *out)
 {
@@ -1339,4 +1331,3 @@ const SwsOpBackend backend_spirv = {
     .compile   = compile_spirv,
     .hw_format = AV_PIX_FMT_VULKAN,
 };
-#endif
diff --git a/tests/fate/libswscale.mak b/tests/fate/libswscale.mak
index 7357a7d0f4..42501feca6 100644
--- a/tests/fate/libswscale.mak
+++ b/tests/fate/libswscale.mak
@@ -54,8 +54,7 @@ endif
 ifeq ($(ARCH_AARCH64),yes)
 SWS_UNSTABLE_BACKENDS-$(HAVE_NEON)                   += aarch64
 endif
-SWS_UNSTABLE_BACKENDS-$(HAVE_SPIRV_HEADERS_SPIRV_H)  += spirv
-SWS_UNSTABLE_BACKENDS-$(HAVE_SPIRV_UNIFIED1_SPIRV_H) += spirv
+SWS_UNSTABLE_BACKENDS-$(CONFIG_SWSCALE_VULKAN)       += spirv
 
 # Set -hw default for Vulkan tests.
 fate-sws-unscaled-spirv fate-sws-unstable-spirv: SWS_HW = -hw default
-- 
2.54.0

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

Reply via email to