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

These are all of the mostly cosmetic / trivial changes needed for the second 
part of my refactor of this file, aimed at replacing the SwsOps usage by SwsUOp.

Disclaimer: I used Claude Opus 5.5 heavily to do the actual refactoring, but 
the direction/guidance was mine. I have individually reviewed and signed off 
every single commit.


>From abfbefc662a5bda06aa060579f6a459a56f9630c Mon Sep 17 00:00:00 2001
From: Niklas Haas <[email protected]>
Date: Tue, 20 Oct 2026 01:47:48 +0200
Subject: [PATCH 01/17] swscale/vulkan/ops: fix error return in
 create_filter_buf()

Failures were silently returning 0, leaving behind an unallocated buffer.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Signed-off-by: Niklas Haas <[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 87c622c8619..d393b93fc46 100644
--- a/libswscale/vulkan/ops.c
+++ b/libswscale/vulkan/ops.c
@@ -201,7 +201,7 @@ static int create_filter_buf(FFVulkanOpsCtx *s, VulkanPriv 
*p,
 
 fail:
     ff_vk_free_buf(&p->s->vkctx, buf);
-    return 0;
+    return err;
 }
 
 static int create_dither_buf(FFVulkanOpsCtx *s, VulkanPriv *p,
-- 
2.54.0


>From 6bd6273f5a6498196d6dc7acd24093df051ff600 Mon Sep 17 00:00:00 2001
From: Niklas Haas <[email protected]>
Date: Tue, 20 Oct 2026 02:04:12 +0200
Subject: [PATCH 02/17] swscale/vulkan/ops: don't declare unused capabilities

The shader only uses 32-bit integer types and never accesses 8-bit storage
buffers, so the Int8, Int16 and StorageBuffer8BitAccess capabilities are
not needed. Declaring them requires the device to support the
corresponding features.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Signed-off-by: Niklas Haas <[email protected]>
---
 libswscale/vulkan/ops.c | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/libswscale/vulkan/ops.c b/libswscale/vulkan/ops.c
index d393b93fc46..0eafb94ae03 100644
--- a/libswscale/vulkan/ops.c
+++ b/libswscale/vulkan/ops.c
@@ -383,12 +383,9 @@ static void define_shader_header(SwsContext *sws, 
FFVulkanShader *shd,
     spi_OpCapability(spi, SpvCapabilityShader); /* Shader type */
 
     /* Declare required capabilities */
-    spi_OpCapability(spi, SpvCapabilityInt16);
-    spi_OpCapability(spi, SpvCapabilityInt8);
     spi_OpCapability(spi, SpvCapabilityImageQuery);
     spi_OpCapability(spi, SpvCapabilityStorageImageReadWithoutFormat);
     spi_OpCapability(spi, SpvCapabilityStorageImageWriteWithoutFormat);
-    spi_OpCapability(spi, SpvCapabilityStorageBuffer8BitAccess);
     /* Import the GLSL set of functions (used for min/max) */
     id->glfn = spi_OpExtInstImport(spi, "GLSL.std.450");
 
-- 
2.54.0


>From 82e46057a9da4a8980310b8efc876a549d03d4a0 Mon Sep 17 00:00:00 2001
From: Niklas Haas <[email protected]>
Date: Tue, 20 Oct 2026 02:08:41 +0200
Subject: [PATCH 03/17] swscale/vulkan/ops: track entrypoint interface
 variables by name

Instead of hard-coding the layout of the in_vars[] array, give the fixed
variables names and build the entrypoint interface list by appending.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Signed-off-by: Niklas Haas <[email protected]>
---
 libswscale/vulkan/ops.c | 50 +++++++++++++++++++++--------------------
 1 file changed, 26 insertions(+), 24 deletions(-)

diff --git a/libswscale/vulkan/ops.c b/libswscale/vulkan/ops.c
index 0eafb94ae03..63acf0a5ce3 100644
--- a/libswscale/vulkan/ops.c
+++ b/libswscale/vulkan/ops.c
@@ -308,7 +308,13 @@ struct FilterData {
 };
 
 typedef struct SPIRVIDs {
-    int in_vars[3 + MAX_DATA_BUFS + 1];
+    /* Entrypoint interface variables */
+    int iface[3 + MAX_DATA_BUFS + 1];
+    int nb_iface;
+
+    int gid_var;
+    int in_img_var;
+    int out_img_var;
 
     int glfn;
     int ep;
@@ -394,9 +400,7 @@ static void define_shader_header(SwsContext *sws, 
FFVulkanShader *shd,
 
     /* Entrypoint */
     id->ep = spi_OpEntryPoint(spi, SpvExecutionModelGLCompute, "main",
-                                id->in_vars,
-                                3 + id->nb_dither_bufs + id->nb_filter_bufs +
-                                (id->interlaced ? 1 : 0));
+                                id->iface, id->nb_iface);
     spi_OpExecutionMode(spi, id->ep, SpvExecutionModeLocalSize,
                         shd->lg_size, 3);
 
@@ -407,18 +411,18 @@ static void define_shader_header(SwsContext *sws, 
FFVulkanShader *shd,
     }
 
     /* gl_GlobalInvocationID descriptor decorations */
-    spi_OpDecorate(spi, id->in_vars[0], SpvDecorationBuiltIn,
+    spi_OpDecorate(spi, id->gid_var, SpvDecorationBuiltIn,
                    SpvBuiltInGlobalInvocationId);
 
     /* Input image descriptor decorations */
-    spi_OpDecorate(spi, id->in_vars[1], SpvDecorationNonWritable);
-    spi_OpDecorate(spi, id->in_vars[1], SpvDecorationDescriptorSet, 0);
-    spi_OpDecorate(spi, id->in_vars[1], SpvDecorationBinding, 0);
+    spi_OpDecorate(spi, id->in_img_var, SpvDecorationNonWritable);
+    spi_OpDecorate(spi, id->in_img_var, SpvDecorationDescriptorSet, 0);
+    spi_OpDecorate(spi, id->in_img_var, SpvDecorationBinding, 0);
 
     /* Output image descriptor decorations */
-    spi_OpDecorate(spi, id->in_vars[2], SpvDecorationNonReadable);
-    spi_OpDecorate(spi, id->in_vars[2], SpvDecorationDescriptorSet, 0);
-    spi_OpDecorate(spi, id->in_vars[2], SpvDecorationBinding, 1);
+    spi_OpDecorate(spi, id->out_img_var, SpvDecorationNonReadable);
+    spi_OpDecorate(spi, id->out_img_var, SpvDecorationDescriptorSet, 0);
+    spi_OpDecorate(spi, id->out_img_var, SpvDecorationBinding, 1);
 
     for (int i = 0; i < id->nb_dither_bufs; i++) {
         spi_OpDecorate(spi, id->dither[i].arr_1d_id, SpvDecorationArrayStride,
@@ -734,13 +738,13 @@ static void define_shader_bindings(const SwsOpList *ops, 
SPICtx *spi, SPIRVIDs *
     }
 
     /* Define inputs */
-    spi_OpVariable(spi, id->in_vars[0], id->u32vec3_tptr,
+    spi_OpVariable(spi, id->gid_var, id->u32vec3_tptr,
                    SpvStorageClassInput, 0);
     if (op_r) {
-        spi_OpVariable(spi, id->in_vars[1], id->in_img_tptr,
+        spi_OpVariable(spi, id->in_img_var, id->in_img_tptr,
                        SpvStorageClassUniformConstant, 0);
     }
-    spi_OpVariable(spi, id->in_vars[2], id->out_img_tptr,
+    spi_OpVariable(spi, id->out_img_var, id->out_img_tptr,
                    SpvStorageClassUniformConstant, 0);
 
     if (id->interlaced) {
@@ -997,9 +1001,9 @@ static int add_ops_spirv(SwsContext *sws, VulkanPriv *p, 
FFVulkanOpsCtx *s,
         return err;
 
     /* Entrypoint inputs; gl_GlobalInvocationID, input and output images, 
dither */
-    id->in_vars[0] = spi_get_id(spi);
-    id->in_vars[1] = spi_get_id(spi);
-    id->in_vars[2] = spi_get_id(spi);
+    id->gid_var     = id->iface[id->nb_iface++] = spi_get_id(spi);
+    id->in_img_var  = id->iface[id->nb_iface++] = spi_get_id(spi);
+    id->out_img_var = id->iface[id->nb_iface++] = spi_get_id(spi);
 
     /* Create dither and filter buffer descriptor set. Both are collected in
      * op order, so the bindings match the buffer order from create_bufs().*/
@@ -1041,7 +1045,7 @@ static int add_ops_spirv(SwsContext *sws, VulkanPriv *p, 
FFVulkanOpsCtx *s,
             continue;
         }
 
-        id->in_vars[3 + nb_data_bufs] = var_id;
+        id->iface[id->nb_iface++] = var_id;
         desc_set[nb_data_bufs++] = (FFVulkanDescriptorSetBinding) {
             .type        = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
             .stages      = VK_SHADER_STAGE_COMPUTE_BIT,
@@ -1053,9 +1057,7 @@ static int add_ops_spirv(SwsContext *sws, VulkanPriv *p, 
FFVulkanOpsCtx *s,
 
     if (id->interlaced) {
         id->push_const_struct_id = spi_get_id(spi);
-        id->push_const_var_id = spi_get_id(spi);
-        id->in_vars[3 + id->nb_dither_bufs + id->nb_filter_bufs] =
-            id->push_const_var_id;
+        id->push_const_var_id = id->iface[id->nb_iface++] = spi_get_id(spi);
     }
 
     /* Define shader header sections */
@@ -1072,7 +1074,7 @@ static int add_ops_spirv(SwsContext *sws, VulkanPriv *p, 
FFVulkanOpsCtx *s,
     for (int i = 0; i < in_img_count; i++) {
         /* Deref array and then the pointer */
         int img = spi_OpAccessChain(spi, id->in_img_sptr,
-                                    id->in_vars[1], id->u32_cid[i]);
+                                    id->in_img_var, id->u32_cid[i]);
         in_img[i] = spi_OpLoad(spi, id->in_img_type, img,
                                SpvMemoryAccessMaskNone, 0);
     }
@@ -1081,13 +1083,13 @@ static int add_ops_spirv(SwsContext *sws, VulkanPriv 
*p, FFVulkanOpsCtx *s,
     int out_img[4] = { 0 };
     for (int i = 0; i < out_img_count; i++) {
         int img = spi_OpAccessChain(spi, id->out_img_sptr,
-                                    id->in_vars[2], id->u32_cid[i]);
+                                    id->out_img_var, id->u32_cid[i]);
         out_img[i] = spi_OpLoad(spi, id->out_img_type, img,
                                 SpvMemoryAccessMaskNone, 0);
     }
 
     /* Load gl_GlobalInvocationID */
-    int gid = spi_OpLoad(spi, id->u32vec3_type, id->in_vars[0],
+    int gid = spi_OpLoad(spi, id->u32vec3_type, id->gid_var,
                          SpvMemoryAccessMaskNone, 0);
 
     /* ivec2(gl_GlobalInvocationID.xy) */
-- 
2.54.0


>From 2acb7c93678c06c2c9a81cbaf0e8fb342fbc0e98 Mon Sep 17 00:00:00 2001
From: Niklas Haas <[email protected]>
Date: Tue, 20 Oct 2026 02:12:31 +0200
Subject: [PATCH 04/17] swscale/vulkan/ops: don't reference the input image in
 passes without reads

The input image variable was only defined when the pass contains a read,
but was unconditionally decorated and listed in the entrypoint interface,
referencing an undefined ID and producing invalid SPIR-V.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Signed-off-by: Niklas Haas <[email protected]>
---
 libswscale/vulkan/ops.c | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/libswscale/vulkan/ops.c b/libswscale/vulkan/ops.c
index 63acf0a5ce3..6f9f96698c2 100644
--- a/libswscale/vulkan/ops.c
+++ b/libswscale/vulkan/ops.c
@@ -415,9 +415,11 @@ static void define_shader_header(SwsContext *sws, 
FFVulkanShader *shd,
                    SpvBuiltInGlobalInvocationId);
 
     /* Input image descriptor decorations */
-    spi_OpDecorate(spi, id->in_img_var, SpvDecorationNonWritable);
-    spi_OpDecorate(spi, id->in_img_var, SpvDecorationDescriptorSet, 0);
-    spi_OpDecorate(spi, id->in_img_var, SpvDecorationBinding, 0);
+    if (id->in_img_var) {
+        spi_OpDecorate(spi, id->in_img_var, SpvDecorationNonWritable);
+        spi_OpDecorate(spi, id->in_img_var, SpvDecorationDescriptorSet, 0);
+        spi_OpDecorate(spi, id->in_img_var, SpvDecorationBinding, 0);
+    }
 
     /* Output image descriptor decorations */
     spi_OpDecorate(spi, id->out_img_var, SpvDecorationNonReadable);
@@ -1002,7 +1004,8 @@ static int add_ops_spirv(SwsContext *sws, VulkanPriv *p, 
FFVulkanOpsCtx *s,
 
     /* Entrypoint inputs; gl_GlobalInvocationID, input and output images, 
dither */
     id->gid_var     = id->iface[id->nb_iface++] = spi_get_id(spi);
-    id->in_img_var  = id->iface[id->nb_iface++] = spi_get_id(spi);
+    if (op_r)
+        id->in_img_var = id->iface[id->nb_iface++] = spi_get_id(spi);
     id->out_img_var = id->iface[id->nb_iface++] = spi_get_id(spi);
 
     /* Create dither and filter buffer descriptor set. Both are collected in
-- 
2.54.0


>From 7fdd9b1e771a76605ad09e91cdc720b211aada2e Mon Sep 17 00:00:00 2001
From: Niklas Haas <[email protected]>
Date: Tue, 20 Oct 2026 02:12:55 +0200
Subject: [PATCH 05/17] swscale/vulkan/ops: reject filtered reads with
 non-float output

The filtered read always accumulates and returns floats, so any other
output type would be silently misinterpreted by the following ops.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Signed-off-by: Niklas Haas <[email protected]>
---
 libswscale/vulkan/ops.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/libswscale/vulkan/ops.c b/libswscale/vulkan/ops.c
index 6f9f96698c2..9b4d6e288f7 100644
--- a/libswscale/vulkan/ops.c
+++ b/libswscale/vulkan/ops.c
@@ -1179,6 +1179,8 @@ static int add_ops_spirv(SwsContext *sws, VulkanPriv *p, 
FFVulkanOpsCtx *s,
                 return AVERROR(ENOTSUP);
             } else if (op->rw.filter.op) {
                 av_assert0(op->rw.mode != SWS_RW_PALETTE);
+                if (op->rw.filter.type != SWS_PIXEL_F32)
+                    return AVERROR(ENOTSUP);
                 data = read_filtered(spi, id, ops, op,
                                      &id->filt[nb_filter_used++],
                                      in_img, gid, gi2);
-- 
2.54.0


>From c53c79f4da3c09840b6b65f2ad332a548f6b580b Mon Sep 17 00:00:00 2001
From: Niklas Haas <[email protected]>
Date: Tue, 20 Oct 2026 02:13:32 +0200
Subject: [PATCH 06/17] swscale/vulkan/ops: cosmetic fixes

Fix indentation and alignment of continuation lines.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Signed-off-by: Niklas Haas <[email protected]>
---
 libswscale/vulkan/ops.c | 40 ++++++++++++++++++++--------------------
 1 file changed, 20 insertions(+), 20 deletions(-)

diff --git a/libswscale/vulkan/ops.c b/libswscale/vulkan/ops.c
index 9b4d6e288f7..37f29dda70f 100644
--- a/libswscale/vulkan/ops.c
+++ b/libswscale/vulkan/ops.c
@@ -279,14 +279,14 @@ fail:
 }
 
 struct DitherData {
-        int size;
-        int arr_1d_id;
-        int arr_2d_id;
-        int struct_id;
-        int struct_ptr_id;
-        int id;
-        int mask_id;
-        int binding;
+    int size;
+    int arr_1d_id;
+    int arr_2d_id;
+    int struct_id;
+    int struct_ptr_id;
+    int id;
+    int mask_id;
+    int binding;
 };
 
 struct FilterData {
@@ -400,7 +400,7 @@ static void define_shader_header(SwsContext *sws, 
FFVulkanShader *shd,
 
     /* Entrypoint */
     id->ep = spi_OpEntryPoint(spi, SpvExecutionModelGLCompute, "main",
-                                id->iface, id->nb_iface);
+                              id->iface, id->nb_iface);
     spi_OpExecutionMode(spi, id->ep, SpvExecutionModeLocalSize,
                         shd->lg_size, 3);
 
@@ -654,7 +654,7 @@ static void define_shader_bindings(const SwsOpList *ops, 
SPICtx *spi, SPIRVIDs *
                                    int in_img_count, int out_img_count)
 {
     id->dither_ptr_elem_id = spi_OpTypePointer(spi, SpvStorageClassUniform,
-                                                 id->f32_type);
+                                               id->f32_type);
 
     struct DitherData *dither = id->dither;
     for (int i = 0; i < id->nb_dither_bufs; i++) {
@@ -714,12 +714,12 @@ static void define_shader_bindings(const SwsOpList *ops, 
SPICtx *spi, SPIRVIDs *
         int match = ((op_w->type == SWS_PIXEL_F32) ==
                      (op_r->type == SWS_PIXEL_F32));
         id->in_img_type = match ? id->out_img_type :
-                            spi_OpTypeImage(spi,
-                                            op_r->type == SWS_PIXEL_F32 ?
-                                            id->f32_type : id->u32_type,
-                                            2, 0, 0, 0, 2, 
SpvImageFormatUnknown);
+                          spi_OpTypeImage(spi,
+                                          op_r->type == SWS_PIXEL_F32 ?
+                                          id->f32_type : id->u32_type,
+                                          2, 0, 0, 0, 2, 
SpvImageFormatUnknown);
         id->in_img_array_id = spi_OpTypeArray(spi, id->in_img_type, 
spi_get_id(spi),
-                                          id->u32_cid[in_img_count]);
+                                              id->u32_cid[in_img_count]);
     }
 
     /* Pointer types for images */
@@ -733,10 +733,10 @@ static void define_shader_bindings(const SwsOpList *ops, 
SPICtx *spi, SPIRVIDs *
     id->in_img_tptr = 0;
     id->in_img_sptr = 0;
     if (op_r) {
-        id->in_img_tptr= spi_OpTypePointer(spi, SpvStorageClassUniformConstant,
-                                           id->in_img_array_id);
-        id->in_img_sptr= spi_OpTypePointer(spi, SpvStorageClassUniformConstant,
-                                           id->in_img_type);
+        id->in_img_tptr = spi_OpTypePointer(spi, 
SpvStorageClassUniformConstant,
+                                            id->in_img_array_id);
+        id->in_img_sptr = spi_OpTypePointer(spi, 
SpvStorageClassUniformConstant,
+                                            id->in_img_type);
     }
 
     /* Define inputs */
@@ -1298,7 +1298,7 @@ static int add_ops_spirv(SwsContext *sws, VulkanPriv *p, 
FFVulkanOpsCtx *s,
         }
         case SWS_OP_LINEAR: {
             if (op->type != SWS_PIXEL_F32)
-                 return AVERROR(ENOTSUP);
+                return AVERROR(ENOTSUP);
             if (sws->flags & SWS_BITEXACT)
                 data = insert_bitexact_linear(op, spi, id, data, 
nb_linear_ops, nb_const_ids);
             else
-- 
2.54.0


>From e162313e5e561d5885f6a3b6f7d57b9f3d6f1d86 Mon Sep 17 00:00:00 2001
From: Niklas Haas <[email protected]>
Date: Tue, 20 Oct 2026 02:14:12 +0200
Subject: [PATCH 07/17] swscale/vulkan/ops: remove unused filter code paths

Filters are only ever merged into planar reads, so the packed filtered
read path and the buffers for filtered writes can never be used.

Standalone filter ops do reach the backend, since compile_subpass() first
tries to compile the unsplit op list. However, code generation has never
supported them and fails with ENOTSUP, after which the list is split at the
filter. The filter buffers allocated and uploaded for them were thus wasted
on every such attempt, and were not accounted for in the descriptor set
bindings either.

Implementing in-line filtering in the future (e.g. via shared memory) would
need its own buffer setup and code generation regardless, since the taps
would no longer be read directly from the source image.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Signed-off-by: Niklas Haas <[email protected]>
---
 libswscale/vulkan/ops.c | 53 +++++++++++------------------------------
 1 file changed, 14 insertions(+), 39 deletions(-)

diff --git a/libswscale/vulkan/ops.c b/libswscale/vulkan/ops.c
index 37f29dda70f..b83d11681cc 100644
--- a/libswscale/vulkan/ops.c
+++ b/libswscale/vulkan/ops.c
@@ -252,15 +252,7 @@ static int create_bufs(FFVulkanOpsCtx *s, VulkanPriv *p, 
const SwsOpList *ops)
             if (err < 0)
                 goto fail;
             p->nb_data_bufs++;
-        } else if (op->op == SWS_OP_FILTER_H || op->op == SWS_OP_FILTER_V) {
-            av_assert0(p->nb_data_bufs + 1 <= FF_ARRAY_ELEMS(p->data_bufs));
-            err = create_filter_buf(s, p, op->filter.kernel,
-                                    &p->data_bufs[p->nb_data_bufs]);
-            if (err < 0)
-                goto fail;
-            p->nb_data_bufs++;
-        } else if ((op->op == SWS_OP_READ ||
-                    op->op == SWS_OP_WRITE) && op->rw.filter.op) {
+        } else if (op->op == SWS_OP_READ && op->rw.filter.op) {
             av_assert0(p->nb_data_bufs + 1 <= FF_ARRAY_ELEMS(p->data_bufs));
             err = create_filter_buf(s, p, op->rw.filter.kernel,
                                     &p->data_bufs[p->nb_data_bufs]);
@@ -848,12 +840,7 @@ static int read_filtered(SPICtx *spi, SPIRVIDs *id, const 
SwsOpList *ops,
     }
 
     /* Accumulators, initialized to zero */
-    int acc_s[4] = { id->f32_0, id->f32_0, id->f32_0, id->f32_0 };
-    int acc_v = id->f32_0;
-    if (op->rw.mode == SWS_RW_PACKED)
-        acc_v = spi_OpCompositeConstruct(spi, id->f32vec4_type,
-                                         id->f32_0, id->f32_0,
-                                         id->f32_0, id->f32_0);
+    int acc[4] = { id->f32_0, id->f32_0, id->f32_0, id->f32_0 };
 
     for (int t = 0; t < f->filter_size; t++) {
         /* float w = filter_w[axis][t]; */
@@ -875,35 +862,23 @@ static int read_filtered(SPICtx *spi, SPIRVIDs *id, const 
SwsOpList *ops,
             spi_OpCompositeConstruct(spi, id->i32vec2_type, c, pos_y) :
             spi_OpCompositeConstruct(spi, id->i32vec2_type, pos_x, c);
 
-        if (op->rw.mode == SWS_RW_PACKED) {
+        for (int e = 0; e < op->rw.elems; e++) {
             int px = spi_OpImageRead(spi, read_vtype,
-                                     in_img[ops->plane_src[0]], coord,
+                                     in_img[ops->plane_src[e]], coord,
                                      SpvImageOperandsMaskNone);
-            if (!src_float)
-                px = spi_OpConvertUToF(spi, id->f32vec4_type, px);
-            px = spi_OpVectorTimesScalar(spi, id->f32vec4_type, px, w);
-            acc_v = spi_OpFAdd(spi, id->f32vec4_type, acc_v, px);
-        } else {
-            for (int e = 0; e < op->rw.elems; e++) {
-                int px = spi_OpImageRead(spi, read_vtype,
-                                         in_img[ops->plane_src[e]], coord,
-                                         SpvImageOperandsMaskNone);
-                if (src_float) {
-                    px = spi_OpCompositeExtract(spi, id->f32_type, px, 0);
-                } else {
-                    px = spi_OpCompositeExtract(spi, id->u32_type, px, 0);
-                    px = spi_OpConvertUToF(spi, id->f32_type, px);
-                }
-                px = spi_OpFMul(spi, id->f32_type, w, px);
-                acc_s[e] = spi_OpFAdd(spi, id->f32_type, acc_s[e], px);
+            if (src_float) {
+                px = spi_OpCompositeExtract(spi, id->f32_type, px, 0);
+            } else {
+                px = spi_OpCompositeExtract(spi, id->u32_type, px, 0);
+                px = spi_OpConvertUToF(spi, id->f32_type, px);
             }
+            px = spi_OpFMul(spi, id->f32_type, w, px);
+            acc[e] = spi_OpFAdd(spi, id->f32_type, acc[e], px);
         }
     }
 
-    if (op->rw.mode == SWS_RW_PACKED)
-        return acc_v;
     return spi_OpCompositeConstruct(spi, id->f32vec4_type,
-                                    acc_s[0], acc_s[1], acc_s[2], acc_s[3]);
+                                    acc[0], acc[1], acc[2], acc[3]);
 }
 
 /* Sub-packed formats are accessed as a single raw word per pixel, which is
@@ -1178,8 +1153,8 @@ static int add_ops_spirv(SwsContext *sws, VulkanPriv *p, 
FFVulkanOpsCtx *s,
             if (op->rw.frac) {
                 return AVERROR(ENOTSUP);
             } else if (op->rw.filter.op) {
-                av_assert0(op->rw.mode != SWS_RW_PALETTE);
-                if (op->rw.filter.type != SWS_PIXEL_F32)
+                if (op->rw.mode != SWS_RW_PLANAR ||
+                    op->rw.filter.type != SWS_PIXEL_F32)
                     return AVERROR(ENOTSUP);
                 data = read_filtered(spi, id, ops, op,
                                      &id->filt[nb_filter_used++],
-- 
2.54.0


>From 83923762612940904112ce5d5ced018e71f55651 Mon Sep 17 00:00:00 2001
From: Niklas Haas <[email protected]>
Date: Tue, 20 Oct 2026 02:14:43 +0200
Subject: [PATCH 08/17] swscale/vulkan/ops: remove duplicate float zero
 constant

Since the float placeholder value was changed to 0.0, f32_p and f32_0 are
the same constant.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Signed-off-by: Niklas Haas <[email protected]>
---
 libswscale/vulkan/ops.c | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/libswscale/vulkan/ops.c b/libswscale/vulkan/ops.c
index b83d11681cc..599fd224b20 100644
--- a/libswscale/vulkan/ops.c
+++ b/libswscale/vulkan/ops.c
@@ -332,7 +332,6 @@ typedef struct SPIRVIDs {
 
     /* Constants */
     int u32_p;
-    int f32_p;
     int f32_0;
     int u32_cid[5];
 
@@ -500,7 +499,6 @@ static void define_shader_consts(SwsContext *sws, const 
SwsOpList *ops,
 
     /* Constants */
     id->u32_p = spi_OpUndef(spi, u32_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);
@@ -1123,8 +1121,8 @@ static int add_ops_spirv(SwsContext *sws, VulkanPriv *p, 
FFVulkanOpsCtx *s,
     int data;
     if (ops->ops[0].type == SWS_PIXEL_F32)
         data = spi_OpCompositeConstruct(spi, id->f32vec4_type,
-                                        id->f32_p, id->f32_p,
-                                        id->f32_p, id->f32_p);
+                                        id->f32_0, id->f32_0,
+                                        id->f32_0, id->f32_0);
     else
         data = spi_OpCompositeConstruct(spi, id->u32vec4_type,
                                         id->u32_p, id->u32_p,
@@ -1146,7 +1144,7 @@ static int add_ops_spirv(SwsContext *sws, VulkanPriv *p, 
FFVulkanOpsCtx *s,
         int type_s = cur_type == SWS_PIXEL_F32 ?
                      id->f32_type : id->u32_type;
         int uid = cur_type == SWS_PIXEL_F32 ?
-                  id->f32_p : id->u32_p;
+                  id->f32_0 : id->u32_p;
 
         switch (op->op) {
         case SWS_OP_READ:
-- 
2.54.0


>From c1bcc61a9ccd167c22f0211dfcbbcf6d9ee3a7b8 Mon Sep 17 00:00:00 2001
From: Niklas Haas <[email protected]>
Date: Tue, 20 Oct 2026 02:15:08 +0200
Subject: [PATCH 09/17] swscale/vulkan/ops: don't pass VulkanPriv to buffer
 creation helpers

Only its FFVulkanOpsCtx was used, which is already passed separately.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Signed-off-by: Niklas Haas <[email protected]>
---
 libswscale/vulkan/ops.c | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/libswscale/vulkan/ops.c b/libswscale/vulkan/ops.c
index 599fd224b20..c1e0725b8d2 100644
--- a/libswscale/vulkan/ops.c
+++ b/libswscale/vulkan/ops.c
@@ -169,8 +169,8 @@ static void free_fn(void *priv)
     av_free(priv);
 }
 
-static int create_filter_buf(FFVulkanOpsCtx *s, VulkanPriv *p,
-                             const SwsFilterWeights *wd, FFVkBuffer *buf)
+static int create_filter_buf(FFVulkanOpsCtx *s, const SwsFilterWeights *wd,
+                             FFVkBuffer *buf)
 {
     int err;
 
@@ -200,12 +200,12 @@ static int create_filter_buf(FFVulkanOpsCtx *s, 
VulkanPriv *p,
     return 0;
 
 fail:
-    ff_vk_free_buf(&p->s->vkctx, buf);
+    ff_vk_free_buf(&s->vkctx, buf);
     return err;
 }
 
-static int create_dither_buf(FFVulkanOpsCtx *s, VulkanPriv *p,
-                             const SwsDitherOp *dd, FFVkBuffer *buf)
+static int create_dither_buf(FFVulkanOpsCtx *s, const SwsDitherOp *dd,
+                             FFVkBuffer *buf)
 {
     int err;
 
@@ -235,7 +235,7 @@ static int create_dither_buf(FFVulkanOpsCtx *s, VulkanPriv 
*p,
     return 0;
 
 fail:
-    ff_vk_free_buf(&p->s->vkctx, buf);
+    ff_vk_free_buf(&s->vkctx, buf);
     return err;
 }
 
@@ -247,14 +247,14 @@ static int create_bufs(FFVulkanOpsCtx *s, VulkanPriv *p, 
const SwsOpList *ops)
         const SwsOp *op = &ops->ops[n];
         if (op->op == SWS_OP_DITHER) {
             av_assert0(p->nb_data_bufs + 1 <= FF_ARRAY_ELEMS(p->data_bufs));
-            err = create_dither_buf(s, p, &op->dither,
+            err = create_dither_buf(s, &op->dither,
                                     &p->data_bufs[p->nb_data_bufs]);
             if (err < 0)
                 goto fail;
             p->nb_data_bufs++;
         } else if (op->op == SWS_OP_READ && op->rw.filter.op) {
             av_assert0(p->nb_data_bufs + 1 <= FF_ARRAY_ELEMS(p->data_bufs));
-            err = create_filter_buf(s, p, op->rw.filter.kernel,
+            err = create_filter_buf(s, op->rw.filter.kernel,
                                     &p->data_bufs[p->nb_data_bufs]);
             if (err < 0)
                 goto fail;
-- 
2.54.0


>From 21fb70760ef78ab5aa61698aba0dea0a50d4eb3d Mon Sep 17 00:00:00 2001
From: Niklas Haas <[email protected]>
Date: Tue, 20 Oct 2026 02:15:21 +0200
Subject: [PATCH 10/17] swscale/vulkan/ops: remove trivial compile() wrapper

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Signed-off-by: Niklas Haas <[email protected]>
---
 libswscale/vulkan/ops.c | 9 ++-------
 1 file changed, 2 insertions(+), 7 deletions(-)

diff --git a/libswscale/vulkan/ops.c b/libswscale/vulkan/ops.c
index c1e0725b8d2..0e50c640594 100644
--- a/libswscale/vulkan/ops.c
+++ b/libswscale/vulkan/ops.c
@@ -1317,7 +1317,8 @@ static int add_ops_spirv(SwsContext *sws, VulkanPriv *p, 
FFVulkanOpsCtx *s,
     return ff_vk_shader_link(&s->vkctx, shd, spvbuf, len, "main");
 }
 
-static int compile(SwsContext *sws, const SwsOpList *ops, SwsCompiledOp *out)
+static int compile_spirv(SwsContext *sws, const SwsOpList *ops,
+                         SwsCompiledOp *out)
 {
     int err;
     SwsInternal *c = sws_internal(sws);
@@ -1362,12 +1363,6 @@ fail:
     return err;
 }
 
-static int compile_spirv(SwsContext *sws, const SwsOpList *ops,
-                         SwsCompiledOp *out)
-{
-    return compile(sws, ops, out);
-}
-
 const SwsOpBackend backend_spirv = {
     .name      = "spirv",
     .flags     = SWS_BACKEND_SPIRV,
-- 
2.54.0


>From 16d4bb22af5a0f6895633f98a9906371c89e0428 Mon Sep 17 00:00:00 2001
From: Niklas Haas <[email protected]>
Date: Tue, 20 Oct 2026 02:15:31 +0200
Subject: [PATCH 11/17] swscale/vulkan/ops: drop ff_ prefix from static
 function

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Signed-off-by: Niklas Haas <[email protected]>
---
 libswscale/vulkan/ops.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libswscale/vulkan/ops.c b/libswscale/vulkan/ops.c
index 0e50c640594..49bf997d66b 100644
--- a/libswscale/vulkan/ops.c
+++ b/libswscale/vulkan/ops.c
@@ -29,7 +29,7 @@
 
 #include "spvasm.h"
 
-static void ff_sws_vk_uninit(AVRefStructOpaque opaque, void *obj)
+static void vk_ops_ctx_uninit(AVRefStructOpaque opaque, void *obj)
 {
     FFVulkanOpsCtx *s = obj;
 
@@ -43,7 +43,7 @@ int ff_sws_vk_init(SwsContext *sws, AVBufferRef *dev_ref)
 
     if (!c->hw_priv) {
         c->hw_priv = av_refstruct_alloc_ext(sizeof(FFVulkanOpsCtx), 0, NULL,
-                                            ff_sws_vk_uninit);
+                                            vk_ops_ctx_uninit);
         if (!c->hw_priv)
             return AVERROR(ENOMEM);
     }
-- 
2.54.0


>From 1fa06c399a0d3085a8c5cf5e1f37e4576a2ddad6 Mon Sep 17 00:00:00 2001
From: Niklas Haas <[email protected]>
Date: Tue, 20 Oct 2026 02:15:34 +0200
Subject: [PATCH 12/17] swscale/vulkan/ops: simplify device reinit check in
 ff_sws_vk_init()

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Signed-off-by: Niklas Haas <[email protected]>
---
 libswscale/vulkan/ops.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/libswscale/vulkan/ops.c b/libswscale/vulkan/ops.c
index 49bf997d66b..cb8cb09c6be 100644
--- a/libswscale/vulkan/ops.c
+++ b/libswscale/vulkan/ops.c
@@ -49,11 +49,11 @@ int ff_sws_vk_init(SwsContext *sws, AVBufferRef *dev_ref)
     }
 
     FFVulkanOpsCtx *s = c->hw_priv;
-    if (s->vkctx.device_ref && s->vkctx.device_ref->data != dev_ref->data) {
+    if (s->vkctx.device_ref) {
+        if (s->vkctx.device_ref->data == dev_ref->data)
+            return 0;
         /* Reinitialize with new context */
         ff_vk_uninit(&s->vkctx);
-    } else if (s->vkctx.device_ref && s->vkctx.device_ref->data == 
dev_ref->data) {
-        return 0;
     }
 
     err = ff_vk_init(&s->vkctx, sws, dev_ref, NULL);
-- 
2.54.0


>From 833aff6cad05f9dffdf18bcddc86941cb2802483 Mon Sep 17 00:00:00 2001
From: Niklas Haas <[email protected]>
Date: Tue, 20 Oct 2026 02:16:04 +0200
Subject: [PATCH 13/17] swscale/vulkan/ops: use separate arrays for each
 descriptor set

The image descriptor array was reused for the buffer descriptors.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Signed-off-by: Niklas Haas <[email protected]>
---
 libswscale/vulkan/ops.c | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/libswscale/vulkan/ops.c b/libswscale/vulkan/ops.c
index cb8cb09c6be..c07a4b9540f 100644
--- a/libswscale/vulkan/ops.c
+++ b/libswscale/vulkan/ops.c
@@ -956,7 +956,7 @@ static int add_ops_spirv(SwsContext *sws, VulkanPriv *p, 
FFVulkanOpsCtx *s,
     if (err < 0)
         return err;
 
-    FFVulkanDescriptorSetBinding desc_set[MAX_DATA_BUFS] = {
+    FFVulkanDescriptorSetBinding img_desc[2] = {
         {
             .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
             .stages = VK_SHADER_STAGE_COMPUTE_BIT,
@@ -968,7 +968,7 @@ static int add_ops_spirv(SwsContext *sws, VulkanPriv *p, 
FFVulkanOpsCtx *s,
             .elems = 4,
         },
     };
-    ff_vk_shader_add_descriptor_set(&s->vkctx, shd, desc_set, 2, 0);
+    ff_vk_shader_add_descriptor_set(&s->vkctx, shd, img_desc, 2, 0);
 
     /* Create dither buffers */
     err = create_bufs(s, p, ops);
@@ -985,6 +985,7 @@ static int add_ops_spirv(SwsContext *sws, VulkanPriv *p, 
FFVulkanOpsCtx *s,
      * op order, so the bindings match the buffer order from create_bufs().*/
     id->nb_dither_bufs = 0;
     id->nb_filter_bufs = 0;
+    FFVulkanDescriptorSetBinding buf_desc[MAX_DATA_BUFS];
     int nb_data_bufs = 0;
     for (int n = 0; n < ops->num_ops; n++) {
         const SwsOp *op = &ops->ops[n];
@@ -1022,13 +1023,13 @@ static int add_ops_spirv(SwsContext *sws, VulkanPriv 
*p, FFVulkanOpsCtx *s,
         }
 
         id->iface[id->nb_iface++] = var_id;
-        desc_set[nb_data_bufs++] = (FFVulkanDescriptorSetBinding) {
+        buf_desc[nb_data_bufs++] = (FFVulkanDescriptorSetBinding) {
             .type        = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
             .stages      = VK_SHADER_STAGE_COMPUTE_BIT,
         };
     }
     if (nb_data_bufs)
-        ff_vk_shader_add_descriptor_set(&s->vkctx, shd, desc_set,
+        ff_vk_shader_add_descriptor_set(&s->vkctx, shd, buf_desc,
                                         nb_data_bufs, 1);
 
     if (id->interlaced) {
-- 
2.54.0


>From 956772b957ba9a48fc4caedc971396e511ee032e Mon Sep 17 00:00:00 2001
From: Niklas Haas <[email protected]>
Date: Tue, 20 Oct 2026 02:18:03 +0200
Subject: [PATCH 14/17] swscale/vulkan/ops: store constant and buffer IDs per
 op

Constants and buffers were collected into flat arrays and consumed via
running counters, which had to be kept in sync by hand between the
constant definition pass, the decoration pass and the code generation
loop. Store them in a struct indexed by the op instead.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Signed-off-by: Niklas Haas <[email protected]>
---
 libswscale/vulkan/ops.c | 201 +++++++++++++++++-----------------------
 1 file changed, 86 insertions(+), 115 deletions(-)

diff --git a/libswscale/vulkan/ops.c b/libswscale/vulkan/ops.c
index c07a4b9540f..ebf4d74516c 100644
--- a/libswscale/vulkan/ops.c
+++ b/libswscale/vulkan/ops.c
@@ -76,6 +76,7 @@ AVBufferRef *ff_sws_vk_device_ref(SwsContext *sws)
     return s ? s->vkctx.device_ref : NULL;
 }
 
+#define MAX_OPS 32
 #define MAX_DITHER_BUFS 4
 #define MAX_FILT_BUFS 4
 #define MAX_DATA_BUFS (MAX_DITHER_BUFS + MAX_FILT_BUFS*4)
@@ -299,6 +300,26 @@ struct FilterData {
     int tap_const_base;
 };
 
+typedef struct LinearIDs {
+    int m[4][4];  /* matrix coefficients */
+    int mat;      /* full matrix, only valid without SWS_BITEXACT */
+    int off[4];   /* offset coefficients */
+    int off_vec;
+    int deco_off; /* space reserved for NoContraction decorations */
+    int nb_deco;
+} LinearIDs;
+
+/* Constants and buffers used by a single op */
+typedef struct OpIDs {
+    union {
+        int vec;                          /* LSHIFT, RSHIFT, SCALE */
+        int comp[4];                      /* CLEAR, MIN, MAX, DITHER */
+        struct { int shift, mask; } pack; /* PACK, UNPACK */
+        LinearIDs lin;                    /* LINEAR */
+    };
+    int buf; /* index into dither[] or filt[] */
+} OpIDs;
+
 typedef struct SPIRVIDs {
     /* Entrypoint interface variables */
     int iface[3 + MAX_DATA_BUFS + 1];
@@ -335,12 +356,7 @@ typedef struct SPIRVIDs {
     int f32_0;
     int u32_cid[5];
 
-    int const_ids[128];
-    int nb_const_ids;
-
-    int linear_deco_off[16];
-    int linear_deco_ops[16];
-    int nb_linear_ops;
+    OpIDs op[MAX_OPS];
 
     struct DitherData dither[MAX_DITHER_BUFS];
     int dither_ptr_elem_id;
@@ -453,7 +469,6 @@ static void define_shader_header(SwsContext *sws, 
FFVulkanShader *shd,
         const SwsOp *op = &ops->ops[n];
         if (op->op != SWS_OP_LINEAR)
             continue;
-        av_assert0((id->nb_linear_ops + 1) <= 
FF_ARRAY_ELEMS(id->linear_deco_off));
 
         int nb_ops = 0;
         for (int j = 0; j < 4; j++) {
@@ -466,9 +481,9 @@ static void define_shader_header(SwsContext *sws, 
FFVulkanShader *shd,
             }
         }
 
-        id->linear_deco_off[id->nb_linear_ops] = spi_reserve(spi, nb_ops*4*3);
-        id->linear_deco_ops[id->nb_linear_ops] = nb_ops;
-        id->nb_linear_ops++;
+        LinearIDs *lin = &id->op[n].lin;
+        lin->deco_off = spi_reserve(spi, nb_ops*4*3);
+        lin->nb_deco  = nb_ops;
     }
 }
 
@@ -504,12 +519,9 @@ static void define_shader_consts(SwsContext *sws, const 
SwsOpList *ops,
         id->u32_cid[i] = spi_OpConstantUInt(spi, u32_type, i);
 
     /* Operation constants */
-    id->nb_const_ids = 0;
     for (int n = 0; n < ops->num_ops; n++) {
-        /* Make sure there's always enough space for the maximum number of
-         * constants a single operation needs (currently linear, 31 consts). */
-        av_assert0((id->nb_const_ids + 31) <= FF_ARRAY_ELEMS(id->const_ids));
         const SwsOp *op = &ops->ops[n];
+        OpIDs *oid = &id->op[n];
         switch (op->op) {
         case SWS_OP_CLEAR:
             for (int i = 0; i < 4; i++) {
@@ -518,12 +530,10 @@ static void define_shader_consts(SwsContext *sws, const 
SwsOpList *ops,
                 AVRational64 cv = op->clear.value[i];
                 if (op->type == SWS_PIXEL_F32) {
                     float q = (float)cv.num/cv.den;
-                    id->const_ids[id->nb_const_ids++] =
-                        spi_OpConstantFloat(spi, f32_type, q);
+                    oid->comp[i] = spi_OpConstantFloat(spi, f32_type, q);
                 } else {
                     av_assert0(cv.den == 1);
-                    id->const_ids[id->nb_const_ids++] =
-                        spi_OpConstantUInt(spi, u32_type, cv.num);
+                    oid->comp[i] = spi_OpConstantUInt(spi, u32_type, cv.num);
                 }
             }
             break;
@@ -534,22 +544,19 @@ static void define_shader_consts(SwsContext *sws, const 
SwsOpList *ops,
             ff_sws_pack_op_decode(op, mask, shift);
             for (int i = 0; i < 4; i++)
                 tmp[i] = spi_OpConstantUInt(spi, u32_type, shift[i]);
-            id->const_ids[id->nb_const_ids++] =
-                spi_OpConstantComposite(spi, id->u32vec4_type,
-                                        tmp[0], tmp[1], tmp[2], tmp[3]);
+            oid->pack.shift = spi_OpConstantComposite(spi, id->u32vec4_type,
+                                                      tmp[0], tmp[1], tmp[2], 
tmp[3]);
             for (int i = 0; i < 4; i++)
                 tmp[i] = spi_OpConstantUInt(spi, u32_type, mask[i]);
-            id->const_ids[id->nb_const_ids++] =
-                spi_OpConstantComposite(spi, id->u32vec4_type,
-                                        tmp[0], tmp[1], tmp[2], tmp[3]);
+            oid->pack.mask = spi_OpConstantComposite(spi, id->u32vec4_type,
+                                                     tmp[0], tmp[1], tmp[2], 
tmp[3]);
             break;
         }
         case SWS_OP_LSHIFT:
         case SWS_OP_RSHIFT: {
             int tmp = spi_OpConstantUInt(spi, u32_type, op->shift.amount);
-            tmp = spi_OpConstantComposite(spi, id->u32vec4_type,
-                                          tmp, tmp, tmp, tmp);
-            id->const_ids[id->nb_const_ids++] = tmp;
+            oid->vec = spi_OpConstantComposite(spi, id->u32vec4_type,
+                                               tmp, tmp, tmp, tmp);
             break;
         }
         case SWS_OP_SCALE: {
@@ -565,7 +572,7 @@ static void define_shader_consts(SwsContext *sws, const 
SwsOpList *ops,
                 tmp = spi_OpConstantComposite(spi, id->u32vec4_type,
                                               tmp, tmp, tmp, tmp);
             }
-            id->const_ids[id->nb_const_ids++] = tmp;
+            oid->vec = tmp;
             break;
         }
         case SWS_OP_MIN:
@@ -582,55 +589,43 @@ static void define_shader_consts(SwsContext *sws, const 
SwsOpList *ops,
                     av_assert0(cl.den == 1);
                     tmp = spi_OpConstantUInt(spi, u32_type, cl.num);
                 }
-                id->const_ids[id->nb_const_ids++] = tmp;
+                oid->comp[i] = tmp;
             }
             break;
         case SWS_OP_DITHER:
             for (int i = 0; i < 4; i++) {
                 if (op->dither.y_offset[i] < 0)
                     continue;
-                int tmp = spi_OpConstantUInt(spi, u32_type, 
op->dither.y_offset[i]);
-                id->const_ids[id->nb_const_ids++] = tmp;
+                oid->comp[i] = spi_OpConstantUInt(spi, u32_type,
+                                                  op->dither.y_offset[i]);
             }
             break;
         case SWS_OP_LINEAR: {
-            int tmp;
+            LinearIDs *lin = &oid->lin;
+            int vec[4], tmp[4];
             float val;
             for (int i = 0; i < 4; i++) {
                 for (int j = 0; j < 4; j++) {
                     int k = sws->flags & SWS_BITEXACT ? i : j;
                     int l = sws->flags & SWS_BITEXACT ? j : i;
                     val = op->lin.m[k][l].num/(float)op->lin.m[k][l].den;
-                    id->const_ids[id->nb_const_ids++] =
-                        spi_OpConstantFloat(spi, f32_type, val);
+                    tmp[j] = lin->m[k][l] = spi_OpConstantFloat(spi, f32_type, 
val);
                 }
-                tmp = spi_OpConstantComposite(spi, id->f32vec4_type,
-                                              id->const_ids[id->nb_const_ids - 
4],
-                                              id->const_ids[id->nb_const_ids - 
3],
-                                              id->const_ids[id->nb_const_ids - 
2],
-                                              id->const_ids[id->nb_const_ids - 
1]);
-                id->const_ids[id->nb_const_ids++] = tmp;
+                vec[i] = spi_OpConstantComposite(spi, id->f32vec4_type,
+                                                 tmp[0], tmp[1], tmp[2], 
tmp[3]);
             }
 
-            tmp = spi_OpConstantComposite(spi, id->f32mat4_type,
-                                          id->const_ids[id->nb_const_ids - 5*4 
+ 4],
-                                          id->const_ids[id->nb_const_ids - 5*3 
+ 4],
-                                          id->const_ids[id->nb_const_ids - 5*2 
+ 4],
-                                          id->const_ids[id->nb_const_ids - 5*1 
+ 4]);
-            id->const_ids[id->nb_const_ids++] = tmp;
+            lin->mat = spi_OpConstantComposite(spi, id->f32mat4_type,
+                                               vec[0], vec[1], vec[2], vec[3]);
 
             for (int i = 0; i < 4; i++) {
                 val = op->lin.m[i][4].num/(float)op->lin.m[i][4].den;
-                id->const_ids[id->nb_const_ids++] =
-                    spi_OpConstantFloat(spi, f32_type, val);
+                lin->off[i] = spi_OpConstantFloat(spi, f32_type, val);
             }
 
-            tmp = spi_OpConstantComposite(spi, id->f32vec4_type,
-                                          id->const_ids[id->nb_const_ids - 4],
-                                          id->const_ids[id->nb_const_ids - 3],
-                                          id->const_ids[id->nb_const_ids - 2],
-                                          id->const_ids[id->nb_const_ids - 1]);
-            id->const_ids[id->nb_const_ids++] = tmp;
+            lin->off_vec = spi_OpConstantComposite(spi, id->f32vec4_type,
+                                                   lin->off[0], lin->off[1],
+                                                   lin->off[2], lin->off[3]);
             break;
         }
         default:
@@ -750,18 +745,15 @@ static void define_shader_bindings(const SwsOpList *ops, 
SPICtx *spi, SPIRVIDs *
     }
 }
 
-static int insert_vmat_linear(const SwsOp *op, SPICtx *spi, SPIRVIDs *id,
-                              int data, int const_off)
+static int insert_vmat_linear(SPICtx *spi, SPIRVIDs *id, const LinearIDs *lin,
+                              int data)
 {
-    data =  spi_OpMatrixTimesVector(spi, id->f32vec4_type,
-                                    id->const_ids[const_off + 4*5],
-                                    data);
-    return spi_OpFAdd(spi, id->f32vec4_type,
-                      id->const_ids[const_off + 4*5 + 1 + 4], data);
+    data = spi_OpMatrixTimesVector(spi, id->f32vec4_type, lin->mat, data);
+    return spi_OpFAdd(spi, id->f32vec4_type, lin->off_vec, data);
 }
 
 static int insert_bitexact_linear(const SwsOp *op, SPICtx *spi, SPIRVIDs *id,
-                                  int data, int linear_ops_idx, int const_off)
+                                  const LinearIDs *lin, int data)
 {
     int type_s = op->type == SWS_PIXEL_F32 ? id->f32_type : id->u32_type;
     int type_v = op->type == SWS_PIXEL_F32 ? id->f32vec4_type : 
id->u32vec4_type;
@@ -773,8 +765,8 @@ static int insert_bitexact_linear(const SwsOp *op, SPICtx 
*spi, SPIRVIDs *id,
     tmp[3] = spi_OpCompositeExtract(spi, type_s, data, 3);
 
     int off = spi_reserve(spi, 0); /* Current offset */
-    spi->off = id->linear_deco_off[linear_ops_idx];
-    for (int i = 0; i < id->linear_deco_ops[linear_ops_idx]; i++)
+    spi->off = lin->deco_off;
+    for (int i = 0; i < lin->nb_deco; i++)
         spi_OpDecorate(spi, spi->id + i, SpvDecorationNoContraction);
     spi->off = off;
 
@@ -782,21 +774,18 @@ static int insert_bitexact_linear(const SwsOp *op, SPICtx 
*spi, SPIRVIDs *id,
     for (int j = 0; j < 4; j++) {
         res[j] = op->type == SWS_PIXEL_F32 ? id->f32_0 : id->u32_cid[0];
         if (op->lin.m[j][0].num)
-            res[j] = spi_OpFMul(spi, type_s, tmp[0],
-                                id->const_ids[const_off + j*5 + 0]);
+            res[j] = spi_OpFMul(spi, type_s, tmp[0], lin->m[j][0]);
 
         if (op->lin.m[j][0].num && op->lin.m[j][4].num)
-            res[j] = spi_OpFAdd(spi, type_s,
-                                id->const_ids[const_off + 4*5 + 1 + j], 
res[j]);
+            res[j] = spi_OpFAdd(spi, type_s, lin->off[j], res[j]);
         else if (op->lin.m[j][4].num)
-            res[j] = id->const_ids[const_off + 4*5 + 1 + j];
+            res[j] = lin->off[j];
 
         for (int i = 1; i < 4; i++) {
             if (!op->lin.m[j][i].num)
                 continue;
 
-            int v = spi_OpFMul(spi, type_s, tmp[i],
-                               id->const_ids[const_off + j*5 + i]);
+            int v = spi_OpFMul(spi, type_s, tmp[i], lin->m[j][i]);
             if (op->lin.m[j][0].num || op->lin.m[j][4].num)
                 res[j] = spi_OpFAdd(spi, type_s, res[j], v);
             else
@@ -932,6 +921,9 @@ static int add_ops_spirv(SwsContext *sws, VulkanPriv *p, 
FFVulkanOpsCtx *s,
     SPIRVIDs spid_data = { 0 }, *id = &spid_data;
     spi_init(spi, spvbuf, sizeof(spvbuf));
 
+    if (ops->num_ops > MAX_OPS)
+        return AVERROR(ENOTSUP);
+
     id->interlaced = ops->src.interlaced || ops->dst.interlaced;
     p->interlaced = id->interlaced;
 
@@ -994,6 +986,7 @@ static int add_ops_spirv(SwsContext *sws, VulkanPriv *p, 
FFVulkanOpsCtx *s,
         if (op->op == SWS_OP_DITHER) {
             if (id->nb_dither_bufs >= MAX_DITHER_BUFS)
                 return AVERROR(ENOTSUP);
+            id->op[n].buf = id->nb_dither_bufs;
             struct DitherData *d = &id->dither[id->nb_dither_bufs++];
             d->size      = 1 << op->dither.size_log2;
             d->arr_1d_id = spi_get_id(spi);
@@ -1006,6 +999,7 @@ static int add_ops_spirv(SwsContext *sws, VulkanPriv *p, 
FFVulkanOpsCtx *s,
             if (id->nb_filter_bufs >= MAX_FILT_BUFS)
                 return AVERROR(ENOTSUP);
             const SwsFilterWeights *wd = op->rw.filter.kernel;
+            id->op[n].buf = id->nb_filter_bufs;
             struct FilterData *f = &id->filt[id->nb_filter_bufs++];
             f->filter       = op->rw.filter.op;
             f->filter_size  = wd->filter_size;
@@ -1129,15 +1123,10 @@ static int add_ops_spirv(SwsContext *sws, VulkanPriv 
*p, FFVulkanOpsCtx *s,
                                         id->u32_p, id->u32_p,
                                         id->u32_p, id->u32_p);
 
-    /* Keep track of which constant/buffer to use */
-    int nb_const_ids = 0;
-    int nb_dither_bufs = 0;
-    int nb_linear_ops = 0;
-    int nb_filter_used = 0;
-
     /* Operations */
     for (int n = 0; n < ops->num_ops; n++) {
         const SwsOp *op = &ops->ops[n];
+        const OpIDs *oid = &id->op[n];
         SwsPixelType cur_type = op->op == SWS_OP_CONVERT ?
                                 op->convert.to : op->type;
         int type_v = cur_type == SWS_PIXEL_F32 ?
@@ -1156,7 +1145,7 @@ static int add_ops_spirv(SwsContext *sws, VulkanPriv *p, 
FFVulkanOpsCtx *s,
                     op->rw.filter.type != SWS_PIXEL_F32)
                     return AVERROR(ENOTSUP);
                 data = read_filtered(spi, id, ops, op,
-                                     &id->filt[nb_filter_used++],
+                                     &id->filt[oid->buf],
                                      in_img, gid, gi2);
             } else if (op->rw.mode == SWS_RW_PACKED) {
                 data = spi_OpImageRead(spi, type_v, in_img[ops->plane_src[0]],
@@ -1194,9 +1183,7 @@ static int add_ops_spirv(SwsContext *sws, VulkanPriv *p, 
FFVulkanOpsCtx *s,
             for (int i = 0; i < 4; i++) {
                 if (!SWS_COMP_TEST(op->clear.mask, i))
                     continue;
-                data = spi_OpCompositeInsert(spi, type_v,
-                                             id->const_ids[nb_const_ids++],
-                                             data, i);
+                data = spi_OpCompositeInsert(spi, type_v, oid->comp[i], data, 
i);
             }
             break;
         case SWS_OP_SWIZZLE:
@@ -1213,20 +1200,16 @@ static int add_ops_spirv(SwsContext *sws, VulkanPriv 
*p, FFVulkanOpsCtx *s,
                 data = spi_OpConvertUToF(spi, type_v, data);
             break;
         case SWS_OP_LSHIFT:
-            data = spi_OpShiftLeftLogical(spi, type_v, data,
-                                          id->const_ids[nb_const_ids++]);
+            data = spi_OpShiftLeftLogical(spi, type_v, data, oid->vec);
             break;
         case SWS_OP_RSHIFT:
-            data = spi_OpShiftRightLogical(spi, type_v, data,
-                                           id->const_ids[nb_const_ids++]);
+            data = spi_OpShiftRightLogical(spi, type_v, data, oid->vec);
             break;
         case SWS_OP_SCALE:
             if (op->type == SWS_PIXEL_F32)
-                data = spi_OpFMul(spi, type_v, data,
-                                  id->const_ids[nb_const_ids++]);
+                data = spi_OpFMul(spi, type_v, data, oid->vec);
             else
-                data = spi_OpIMul(spi, type_v, data,
-                                  id->const_ids[nb_const_ids++]);
+                data = spi_OpIMul(spi, type_v, data, oid->vec);
             break;
         case SWS_OP_MIN:
         case SWS_OP_MAX: {
@@ -1237,30 +1220,25 @@ static int add_ops_spirv(SwsContext *sws, VulkanPriv 
*p, FFVulkanOpsCtx *s,
                 if (!op->clamp.limit[i].den)
                     continue;
                 int tmp = spi_OpCompositeExtract(spi, type_s, data, i);
-                tmp = spi_OpExtInst(spi, type_s, id->glfn, t,
-                                    tmp, id->const_ids[nb_const_ids++]);
+                tmp = spi_OpExtInst(spi, type_s, id->glfn, t, tmp, 
oid->comp[i]);
                 data = spi_OpCompositeInsert(spi, type_v, tmp, data, i);
             }
             break;
         }
         case SWS_OP_DITHER: {
-            int did = nb_dither_bufs++;
+            const struct DitherData *d = &id->dither[oid->buf];
             int x_id = spi_OpCompositeExtract(spi, id->u32_type, gid, 0);
             int y_pos = spi_OpCompositeExtract(spi, id->u32_type, gid, 1);
-            x_id = spi_OpBitwiseAnd(spi, id->u32_type, x_id,
-                                    id->dither[did].mask_id);
+            x_id = spi_OpBitwiseAnd(spi, id->u32_type, x_id, d->mask_id);
             for (int i = 0; i < 4; i++) {
                 if (op->dither.y_offset[i] < 0)
                     continue;
 
-                int y_id = spi_OpIAdd(spi, id->u32_type, y_pos,
-                                      id->const_ids[nb_const_ids++]);
-                y_id = spi_OpBitwiseAnd(spi, id->u32_type, y_id,
-                                        id->dither[did].mask_id);
+                int y_id = spi_OpIAdd(spi, id->u32_type, y_pos, oid->comp[i]);
+                y_id = spi_OpBitwiseAnd(spi, id->u32_type, y_id, d->mask_id);
 
-                int ptr = spi_OpAccessChain(spi, id->dither_ptr_elem_id,
-                                            id->dither[did].id, id->u32_cid[0],
-                                            y_id, x_id);
+                int ptr = spi_OpAccessChain(spi, id->dither_ptr_elem_id, d->id,
+                                            id->u32_cid[0], y_id, x_id);
                 int val = spi_OpLoad(spi, id->f32_type, ptr,
                                      SpvMemoryAccessMaskNone, 0);
 
@@ -1274,26 +1252,19 @@ static int add_ops_spirv(SwsContext *sws, VulkanPriv 
*p, FFVulkanOpsCtx *s,
             if (op->type != SWS_PIXEL_F32)
                 return AVERROR(ENOTSUP);
             if (sws->flags & SWS_BITEXACT)
-                data = insert_bitexact_linear(op, spi, id, data, 
nb_linear_ops, nb_const_ids);
+                data = insert_bitexact_linear(op, spi, id, &oid->lin, data);
             else
-                data = insert_vmat_linear(op, spi, id, data, nb_const_ids);
-            nb_linear_ops++;
-            nb_const_ids += 5*5 + 1;
+                data = insert_vmat_linear(spi, id, &oid->lin, data);
             break;
         }
-        case SWS_OP_UNPACK: {
-            int shift = id->const_ids[nb_const_ids++];
-            int mask  = id->const_ids[nb_const_ids++];
+        case SWS_OP_UNPACK:
             data = spi_OpVectorShuffle(spi, type_v, data, data, 0, 0, 0, 0);
-            data = spi_OpShiftRightLogical(spi, type_v, data, shift);
-            data = spi_OpBitwiseAnd(spi, type_v, data, mask);
+            data = spi_OpShiftRightLogical(spi, type_v, data, oid->pack.shift);
+            data = spi_OpBitwiseAnd(spi, type_v, data, oid->pack.mask);
             break;
-        }
         case SWS_OP_PACK: {
-            int shift = id->const_ids[nb_const_ids++];
-            int mask  = id->const_ids[nb_const_ids++];
-            data = spi_OpBitwiseAnd(spi, type_v, data, mask);
-            data = spi_OpShiftLeftLogical(spi, type_v, data, shift);
+            data = spi_OpBitwiseAnd(spi, type_v, data, oid->pack.mask);
+            data = spi_OpShiftLeftLogical(spi, type_v, data, oid->pack.shift);
             int val = spi_OpCompositeExtract(spi, type_s, data, 0);
             for (int i = 1; i < 4; i++) {
                 int tmp = spi_OpCompositeExtract(spi, type_s, data, i);
-- 
2.54.0


>From 06f14feaffd64825d415cf5b2580ffcee59e46f3 Mon Sep 17 00:00:00 2001
From: Niklas Haas <[email protected]>
Date: Tue, 20 Oct 2026 02:18:36 +0200
Subject: [PATCH 15/17] swscale/vulkan/ops: factor out bit-exact linear op
 count

Move the count of arithmetic instructions emitted by
insert_bitexact_linear() into a helper, and assert that it matches the
number of IDs actually allocated, since the NoContraction decorations
are reserved and written based on this count.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Signed-off-by: Niklas Haas <[email protected]>
---
 libswscale/vulkan/ops.c | 32 +++++++++++++++++++++-----------
 1 file changed, 21 insertions(+), 11 deletions(-)

diff --git a/libswscale/vulkan/ops.c b/libswscale/vulkan/ops.c
index ebf4d74516c..18aa671ed5e 100644
--- a/libswscale/vulkan/ops.c
+++ b/libswscale/vulkan/ops.c
@@ -389,6 +389,22 @@ typedef struct SPIRVIDs {
     int field_i32;
 } SPIRVIDs;
 
+/* Number of arithmetic instructions emitted by insert_bitexact_linear() */
+static int bitexact_linear_nb_ops(const SwsLinearOp *lin)
+{
+    int nb_ops = 0;
+    for (int j = 0; j < 4; j++) {
+        nb_ops += !!lin->m[j][0].num;
+        nb_ops += lin->m[j][0].num && lin->m[j][4].num;
+        for (int i = 1; i < 4; i++) {
+            nb_ops += !!lin->m[j][i].num;
+            nb_ops += lin->m[j][i].num &&
+                      (lin->m[j][0].num || lin->m[j][4].num);
+        }
+    }
+    return nb_ops;
+}
+
 /* Section 1: Function to define all shader header data, and decorations */
 static void define_shader_header(SwsContext *sws, FFVulkanShader *shd,
                                  const SwsOpList *ops, SPICtx *spi, SPIRVIDs 
*id)
@@ -470,17 +486,7 @@ static void define_shader_header(SwsContext *sws, 
FFVulkanShader *shd,
         if (op->op != SWS_OP_LINEAR)
             continue;
 
-        int nb_ops = 0;
-        for (int j = 0; j < 4; j++) {
-            nb_ops += !!op->lin.m[j][0].num;
-            nb_ops += op->lin.m[j][0].num && op->lin.m[j][4].num;
-            for (int i = 1; i < 4; i++) {
-                nb_ops += !!op->lin.m[j][i].num;
-                nb_ops += op->lin.m[j][i].num &&
-                          (op->lin.m[j][0].num || op->lin.m[j][4].num);
-            }
-        }
-
+        const int nb_ops = bitexact_linear_nb_ops(&op->lin);
         LinearIDs *lin = &id->op[n].lin;
         lin->deco_off = spi_reserve(spi, nb_ops*4*3);
         lin->nb_deco  = nb_ops;
@@ -769,6 +775,7 @@ static int insert_bitexact_linear(const SwsOp *op, SPICtx 
*spi, SPIRVIDs *id,
     for (int i = 0; i < lin->nb_deco; i++)
         spi_OpDecorate(spi, spi->id + i, SpvDecorationNoContraction);
     spi->off = off;
+    const int first_id = spi->id;
 
     int res[4];
     for (int j = 0; j < 4; j++) {
@@ -793,6 +800,9 @@ static int insert_bitexact_linear(const SwsOp *op, SPICtx 
*spi, SPIRVIDs *id,
         }
     }
 
+    /* The decorations above assume one ID per arithmetic op */
+    av_assert0(spi->id - first_id == lin->nb_deco);
+
     return spi_OpCompositeConstruct(spi, type_v,
                                     res[0], res[1], res[2], res[3]);
 }
-- 
2.54.0


>From 1ab9b0e186dd01d85d14f544d27edee5366f0e1a Mon Sep 17 00:00:00 2001
From: Niklas Haas <[email protected]>
Date: Tue, 20 Oct 2026 12:01:41 +0200
Subject: [PATCH 16/17] swscale/vulkan/ops: handle errors in process()

Failures from ff_vk_create_imageviews_fmt() and friends were ignored,
leading to descriptors being updated with uninitialized image views.
Discard the execution and bail out instead. SwsPassFunc has no way to
return errors, so just log them for now.

Signed-off-by: Niklas Haas <[email protected]>
---
 libswscale/vulkan/ops.c | 44 ++++++++++++++++++++++++++++++-----------
 1 file changed, 32 insertions(+), 12 deletions(-)

diff --git a/libswscale/vulkan/ops.c b/libswscale/vulkan/ops.c
index 18aa671ed5e..3720faeef7a 100644
--- a/libswscale/vulkan/ops.c
+++ b/libswscale/vulkan/ops.c
@@ -98,23 +98,33 @@ static void process(const SwsFrame *dst, const SwsFrame 
*src, int y, int h,
     VulkanPriv *p = (VulkanPriv *) pass->priv;
     FFVkExecContext *ec = ff_vk_exec_get(&p->s->vkctx, &p->e);
     FFVulkanFunctions *vk = &p->s->vkctx.vkfn;
-    ff_vk_exec_start(&p->s->vkctx, ec);
+    int err = ff_vk_exec_start(&p->s->vkctx, ec);
+    if (err < 0)
+        goto error;
 
     AVFrame *src_f = (AVFrame *) src->avframe;
     AVFrame *dst_f = (AVFrame *) dst->avframe;
-    ff_vk_exec_add_dep_frame(&p->s->vkctx, ec, src_f,
-                             VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
-                             VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT);
-    ff_vk_exec_add_dep_frame(&p->s->vkctx, ec, dst_f,
-                             VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
-                             VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT);
+    err = ff_vk_exec_add_dep_frame(&p->s->vkctx, ec, src_f,
+                                   VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
+                                   VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT);
+    if (err < 0)
+        goto fail;
+    err = ff_vk_exec_add_dep_frame(&p->s->vkctx, ec, dst_f,
+                                   VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
+                                   VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT);
+    if (err < 0)
+        goto fail;
 
     VkImageView src_views[AV_NUM_DATA_POINTERS];
     VkImageView dst_views[AV_NUM_DATA_POINTERS];
-    ff_vk_create_imageviews_fmt(&p->s->vkctx, ec, src_views, src_f,
-                                p->src_view_fmt);
-    ff_vk_create_imageviews_fmt(&p->s->vkctx, ec, dst_views, dst_f,
-                                p->dst_view_fmt);
+    err = ff_vk_create_imageviews_fmt(&p->s->vkctx, ec, src_views, src_f,
+                                      p->src_view_fmt);
+    if (err < 0)
+        goto fail;
+    err = ff_vk_create_imageviews_fmt(&p->s->vkctx, ec, dst_views, dst_f,
+                                      p->dst_view_fmt);
+    if (err < 0)
+        goto fail;
 
     ff_vk_shader_update_img_array(&p->s->vkctx, ec, &p->shd, src_f, src_views,
                                   0, 0, VK_IMAGE_LAYOUT_GENERAL, 
VK_NULL_HANDLE);
@@ -155,8 +165,18 @@ static void process(const SwsFrame *dst, const SwsFrame 
*src, int y, int h,
                     FFALIGN(dst->height, p->shd.lg_size[1])/p->shd.lg_size[1],
                     1);
 
-    ff_vk_exec_submit(&p->s->vkctx, ec);
+    err = ff_vk_exec_submit(&p->s->vkctx, ec);
+    if (err < 0)
+        goto error;
     ff_vk_exec_wait(&p->s->vkctx, ec);
+    return;
+
+fail:
+    ff_vk_exec_discard(&p->s->vkctx, ec);
+error:
+    /* SwsPassFunc has no way to return errors */
+    av_log(&p->s->vkctx, AV_LOG_ERROR, "Vulkan pass failed: %s\n",
+           av_err2str(err));
 }
 
 static void free_fn(void *priv)
-- 
2.54.0


>From 6abbb9137cfb10858d4c969738938571735ac699 Mon Sep 17 00:00:00 2001
From: Niklas Haas <[email protected]>
Date: Tue, 20 Oct 2026 12:02:15 +0200
Subject: [PATCH 17/17] swscale/vulkan/ops: rename process() to spirv_process()

Distinguishes it from the many other process() functions in swscale.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Signed-off-by: Niklas Haas <[email protected]>
---
 libswscale/vulkan/ops.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/libswscale/vulkan/ops.c b/libswscale/vulkan/ops.c
index 3720faeef7a..ac64491703c 100644
--- a/libswscale/vulkan/ops.c
+++ b/libswscale/vulkan/ops.c
@@ -92,8 +92,8 @@ typedef struct VulkanPriv {
     int interlaced;
 } VulkanPriv;
 
-static void process(const SwsFrame *dst, const SwsFrame *src, int y, int h,
-                    const SwsPass *pass)
+static void spirv_process(const SwsFrame *dst, const SwsFrame *src,
+                          int y, int h, const SwsPass *pass)
 {
     VulkanPriv *p = (VulkanPriv *) pass->priv;
     FFVkExecContext *ec = ff_vk_exec_get(&p->s->vkctx, &p->e);
@@ -1353,7 +1353,7 @@ static int compile_spirv(SwsContext *sws, const SwsOpList 
*ops,
 
     *out = (SwsCompiledOp) {
         .opaque      = true,
-        .func_opaque = process,
+        .func_opaque = spirv_process,
         .priv        = p,
         .free        = free_fn,
     };
-- 
2.54.0

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

Reply via email to