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

Git pushed a commit to branch master
in repository ffmpeg.

commit bd24abfb6cb691c42388c4649fac71589431a01c
Author:     Lynne <[email protected]>
AuthorDate: Mon Feb 23 22:11:44 2026 +0100
Commit:     Lynne <[email protected]>
CommitDate: Thu Feb 26 14:10:22 2026 +0100

    swscale/vulkan: initialize GLSL compilation and shader execution
    
    Sponsored-by: Sovereign Tech Fund
---
 configure                                          |   2 +-
 libswscale/vulkan/Makefile                         |   2 +
 libswscale/vulkan/ops.c                            | 222 ++++++++++++++++++++-
 libswscale/vulkan/ops.h                            |   7 +
 .../vulkan}/vulkan_glslang.c                       |   0
 .../vulkan}/vulkan_shaderc.c                       |   0
 6 files changed, 230 insertions(+), 3 deletions(-)

diff --git a/configure b/configure
index 6d3c36bf61..a64a73eea8 100755
--- a/configure
+++ b/configure
@@ -4289,7 +4289,7 @@ avutil_suggest="clock_gettime ffnvcodec gcrypt libm zlib 
libdrm libmfx opencl op
 swresample_deps="avutil"
 swresample_suggest="libm libsoxr stdatomic"
 swscale_deps="avutil"
-swscale_suggest="libm stdatomic"
+swscale_suggest="libm stdatomic spirv_library"
 shader_compression_suggest="zlib"
 
 avcodec_extralibs="pthreads_extralibs iconv_extralibs dxva2_extralibs 
liblcevc_dec_extralibs lcms2_extralibs"
diff --git a/libswscale/vulkan/Makefile b/libswscale/vulkan/Makefile
index 396cdeb936..e899f35955 100644
--- a/libswscale/vulkan/Makefile
+++ b/libswscale/vulkan/Makefile
@@ -2,3 +2,5 @@ clean::
        $(RM) $(CLEANSUFFIXES:%=libswscale/vulkan/%)
 
 OBJS-$(CONFIG_VULKAN) += vulkan/ops.o vulkan/vulkan.o
+OBJS-$(CONFIG_LIBSHADERC) += vulkan/vulkan_shaderc.o
+OBJS-$(CONFIG_LIBGLSLANG) += vulkan/vulkan_glslang.o
diff --git a/libswscale/vulkan/ops.c b/libswscale/vulkan/ops.c
index 0b39e08830..b77eb924c7 100644
--- a/libswscale/vulkan/ops.c
+++ b/libswscale/vulkan/ops.c
@@ -30,6 +30,10 @@ void ff_sws_vk_uninit(SwsContext *sws)
     if (!s)
         return;
 
+#if CONFIG_LIBSHADERC || CONFIG_LIBGLSLANG
+    if (s->spvc)
+        s->spvc->uninit(&s->spvc);
+#endif
     ff_vk_exec_pool_free(&s->vkctx, &s->e);
     ff_vk_uninit(&s->vkctx);
     av_freep(&c->hw_priv);
@@ -70,23 +74,80 @@ int ff_sws_vk_init(SwsContext *sws, AVBufferRef *dev_ref)
     if (err < 0)
         return err;
 
+#if CONFIG_LIBSHADERC || CONFIG_LIBGLSLANG
+    if (!s->spvc) {
+        s->spvc = ff_vk_spirv_init();
+        if (!s->spvc)
+            return AVERROR(ENOMEM);
+    }
+#endif
+
     return 0;
 }
 
 typedef struct VulkanPriv {
     FFVulkanOpsCtx *s;
     FFVulkanShader shd;
+    enum FFVkShaderRepFormat src_rep;
+    enum FFVkShaderRepFormat dst_rep;
 } VulkanPriv;
 
 static void process(const SwsOpExec *exec, const void *priv,
                     int x_start, int y_start, int x_end, int y_end)
 {
-    const VulkanPriv *p = priv;
+    VulkanPriv *p = (VulkanPriv *)priv;
     FFVkExecContext *ec = ff_vk_exec_get(&p->s->vkctx, &p->s->e);
+    FFVulkanFunctions *vk = &p->s->vkctx.vkfn;
     ff_vk_exec_start(&p->s->vkctx, ec);
 
+    AVFrame *src_f = (AVFrame *)exec->src_frame_ptr;
+    AVFrame *dst_f = (AVFrame *)exec->dst_frame_ptr;
+    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);
+
+    VkImageView src_views[AV_NUM_DATA_POINTERS];
+    VkImageView dst_views[AV_NUM_DATA_POINTERS];
+    ff_vk_create_imageviews(&p->s->vkctx, ec, src_views, src_f, p->src_rep);
+    ff_vk_create_imageviews(&p->s->vkctx, ec, dst_views, dst_f, p->dst_rep);
+
+    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);
+    ff_vk_shader_update_img_array(&p->s->vkctx, ec, &p->shd, dst_f, dst_views,
+                                  0, 1, VK_IMAGE_LAYOUT_GENERAL, 
VK_NULL_HANDLE);
+
+    int nb_img_bar = 0;
+    VkImageMemoryBarrier2 img_bar[8];
+    ff_vk_frame_barrier(&p->s->vkctx, ec, src_f, img_bar, &nb_img_bar,
+                        VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
+                        VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
+                        VK_ACCESS_SHADER_READ_BIT,
+                        VK_IMAGE_LAYOUT_GENERAL,
+                        VK_QUEUE_FAMILY_IGNORED);
+    ff_vk_frame_barrier(&p->s->vkctx, ec, dst_f, img_bar, &nb_img_bar,
+                        VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
+                        VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
+                        VK_ACCESS_SHADER_WRITE_BIT,
+                        VK_IMAGE_LAYOUT_GENERAL,
+                        VK_QUEUE_FAMILY_IGNORED);
+    vk->CmdPipelineBarrier2(ec->buf, &(VkDependencyInfo) {
+        .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
+        .pImageMemoryBarriers = img_bar,
+        .imageMemoryBarrierCount = nb_img_bar,
+    });
+
+    ff_vk_exec_bind_shader(&p->s->vkctx, ec, &p->shd);
+
+    vk->CmdDispatch(ec->buf,
+                    FFALIGN(src_f->width, p->shd.lg_size[0])/p->shd.lg_size[0],
+                    FFALIGN(src_f->height, 
p->shd.lg_size[1])/p->shd.lg_size[1],
+                    1);
 
     ff_vk_exec_submit(&p->s->vkctx, ec);
+    ff_vk_exec_wait(&p->s->vkctx, ec);
 }
 
 static void free_fn(void *priv)
@@ -96,17 +157,174 @@ static void free_fn(void *priv)
     av_free(priv);
 }
 
+#if CONFIG_LIBSHADERC || CONFIG_LIBGLSLANG
+static int add_ops_glsl(VulkanPriv *p, FFVulkanOpsCtx *s,
+                        SwsOpList *ops, FFVulkanShader *shd)
+{
+    int err;
+    uint8_t *spv_data;
+    size_t spv_len;
+    void *spv_opaque = NULL;
+
+    /* Interlaced formats are not currently supported */
+    if (ops->src.interlaced || ops->src.interlaced)
+        return AVERROR(ENOTSUP);
+
+    err = ff_vk_shader_init(&s->vkctx, shd, "sws_pass",
+                            VK_SHADER_STAGE_COMPUTE_BIT,
+                            NULL, 0, 32, 32, 1, 0);
+    if (err < 0)
+        return err;
+
+    int nb_desc = 0;
+    FFVulkanDescriptorSetBinding buf_desc[8];
+
+    for (int n = 0; n < ops->num_ops; n++) {
+        const SwsOp *op = &ops->ops[n];
+        /* Set initial type */
+        if (op->op == SWS_OP_READ || op->op == SWS_OP_WRITE ||
+            op->op == SWS_OP_CLEAR) {
+            if (op->rw.frac)
+                return AVERROR(ENOTSUP);
+        }
+        if (op->op == SWS_OP_READ || op->op == SWS_OP_WRITE) {
+            const char *img_type = op->type == SWS_PIXEL_F32 ? "rgba32f"  :
+                                   op->type == SWS_PIXEL_U32 ? "rgba32ui" :
+                                   op->type == SWS_PIXEL_U16 ? "rgba16ui" :
+                                                               "rgba8ui";
+            buf_desc[nb_desc++] = (FFVulkanDescriptorSetBinding) {
+                .name = op->op == SWS_OP_WRITE ? "dst_img" : "src_img",
+                .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
+                .mem_layout = img_type,
+                .mem_quali = op->op == SWS_OP_WRITE ? "writeonly" : "readonly",
+                .dimensions = 2,
+                .elems = (op->rw.packed ? 1 : op->rw.elems),
+                .stages = VK_SHADER_STAGE_COMPUTE_BIT,
+            };
+            if (op->op == SWS_OP_READ)
+                p->src_rep = op->type == SWS_PIXEL_F32 ? FF_VK_REP_FLOAT :
+                             FF_VK_REP_UINT;
+            else
+                p->dst_rep = op->type == SWS_PIXEL_F32 ? FF_VK_REP_FLOAT :
+                             FF_VK_REP_UINT;
+        }
+    }
+
+    ff_vk_shader_add_descriptor_set(&s->vkctx, shd, buf_desc, nb_desc, 0, 0);
+
+    GLSLC(0, void main()                                                      
);
+    GLSLC(0, {                                                                
);
+    GLSLC(1,     ivec2 pos = ivec2(gl_GlobalInvocationID.xy);                 
);
+    GLSLC(1,     ivec2 size = imageSize(src_img[0]);                          
);
+    GLSLC(1,     if (any(greaterThanEqual(pos, size)))                        
);
+    GLSLC(2,         return;                                                  
);
+    GLSLC(0,                                                                  
);
+    GLSLC(1,     u8vec4 u8;                                                   
);
+    GLSLC(1,     u16vec4 u16;                                                 
);
+    GLSLC(1,     u32vec4 u32;                                                 
);
+    GLSLC(1,     f32vec4 f32;                                                 
);
+    GLSLC(0,                                                                  
);
+
+    const char *type_name = ff_sws_pixel_type_name(ops->ops[0].type);
+    for (int n = 0; n < ops->num_ops; n++) {
+        const SwsOp *op = &ops->ops[n];
+        const char *type_v = op->type == SWS_PIXEL_F32 ? "f32vec4" :
+                             op->type == SWS_PIXEL_U32 ? "u32vec4" :
+                             op->type == SWS_PIXEL_U16 ? "u16vec4" : "u8vec4";
+        const char *type_s = op->type == SWS_PIXEL_F32 ? "float" :
+                             op->type == SWS_PIXEL_U32 ? "uint32_t" :
+                             op->type == SWS_PIXEL_U16 ? "uint16_t" : 
"uint8_t";
+        switch (op->op) {
+        case SWS_OP_READ: {
+            if (op->rw.packed) {
+                GLSLF(1, %s = %s(imageLoad(src_img[0], pos));                  
,
+                      type_name, type_v);
+            } else {
+                for (int i = 0; i < (op->rw.packed ? 1 : op->rw.elems); i++)
+                    GLSLF(1, %s.%c = %s(imageLoad(src_img[%i], pos)[0]);      ,
+                          type_name, "xyzw"[i], type_s, i);
+            }
+            break;
+        }
+        case SWS_OP_WRITE: {
+            if (op->rw.packed) {
+                GLSLF(1, imageStore(dst_img[0], pos, %s(%s));                  
,
+                      type_v, type_name);
+            } else {
+                for (int i = 0; i < (op->rw.packed ? 1 : op->rw.elems); i++)
+                    GLSLF(1, imageStore(dst_img[%i], pos, %s(%s[%i]));         
,
+                          i, type_v, type_name, i);
+            }
+            break;
+        }
+        case SWS_OP_SWIZZLE: {
+            av_bprintf(&shd->src, "    %s = %s.", type_name, type_name);
+            for (int i = 0; i < 4; i++)
+                av_bprintf(&shd->src, "%c", "xyzw"[op->swizzle.in[i]]);
+            av_bprintf(&shd->src, ";\n");
+            break;
+        }
+        case SWS_OP_CLEAR: {
+            for (int i = 0; i < 4; i++) {
+                if (!op->c.q4[i].den)
+                    continue;
+                av_bprintf(&shd->src, "    %s.%c = %s(%i/%i%s);\n", type_name,
+                           "xyzw"[i], type_s, op->c.q4[i].num, op->c.q4[i].den,
+                           op->type == SWS_PIXEL_F32 ? ".0f" : "");
+            }
+            break;
+        }
+        default:
+            return AVERROR(ENOTSUP);
+        }
+    }
+
+    GLSLC(0, }                                                                
);
+
+    err = s->spvc->compile_shader(&s->vkctx, s->spvc, shd,
+                                  &spv_data, &spv_len, "main",
+                                  &spv_opaque);
+    if (err < 0)
+        return err;
+
+    err = ff_vk_shader_link(&s->vkctx, shd, spv_data, spv_len, "main");
+
+    if (spv_opaque)
+        s->spvc->free_shader(s->spvc, &spv_opaque);
+
+    if (err < 0)
+        return err;
+
+    return 0;
+}
+#endif
+
 static int compile(SwsContext *sws, SwsOpList *ops, SwsCompiledOp *out)
 {
+    int err;
     SwsInternal *c = sws_internal(sws);
     FFVulkanOpsCtx *s = c->hw_priv;
     if (!s)
         return AVERROR(ENOTSUP);
 
     VulkanPriv p = {
-        .s = c->hw_priv,
+        .s = s,
     };
 
+#if CONFIG_LIBSHADERC || CONFIG_LIBGLSLANG
+    {
+        err = add_ops_glsl(&p, s, ops, &p.shd);
+        if (err < 0)
+            return err;
+    }
+#else
+    return AVERROR(ENOTSUP);
+#endif
+
+    err = ff_vk_shader_register_exec(&s->vkctx, &s->e, &p.shd);
+    if (err < 0)
+        return err;
+
     *out = (SwsCompiledOp) {
         .slice_align = 0,
         .block_size  = 1,
diff --git a/libswscale/vulkan/ops.h b/libswscale/vulkan/ops.h
index 55aaea12ed..73813bf4fa 100644
--- a/libswscale/vulkan/ops.h
+++ b/libswscale/vulkan/ops.h
@@ -24,10 +24,17 @@
 #include "libavutil/vulkan.h"
 #include "../swscale.h"
 
+#if CONFIG_LIBSHADERC || CONFIG_LIBGLSLANG
+#include "libavutil/vulkan_spirv.h"
+#endif
+
 typedef struct FFVulkanOpsCtx {
     FFVulkanContext vkctx;
     AVVulkanDeviceQueueFamily *qf;
     FFVkExecPool e;
+#if CONFIG_LIBSHADERC || CONFIG_LIBGLSLANG
+    FFVkSPIRVCompiler *spvc;
+#endif
 } FFVulkanOpsCtx;
 
 int ff_sws_vk_init(SwsContext *sws, AVBufferRef *dev_ref);
diff --git a/libavfilter/vulkan_glslang.c b/libswscale/vulkan/vulkan_glslang.c
similarity index 100%
copy from libavfilter/vulkan_glslang.c
copy to libswscale/vulkan/vulkan_glslang.c
diff --git a/libavfilter/vulkan_shaderc.c b/libswscale/vulkan/vulkan_shaderc.c
similarity index 100%
copy from libavfilter/vulkan_shaderc.c
copy to libswscale/vulkan/vulkan_shaderc.c

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

Reply via email to