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

Git pushed a commit to branch master
in repository ffmpeg.

commit a1894138327f89bb4293e4b7fddb3c7078495cc4
Author:     Lynne <[email protected]>
AuthorDate: Thu May 21 21:29:48 2026 +0900
Commit:     Lynne <[email protected]>
CommitDate: Fri May 22 14:06:03 2026 +0900

    vf_blackdetect_vulkan: port to compile-time SPIR-V generation
---
 configure                                          |  2 +-
 libavfilter/vf_blackdetect_vulkan.c                | 86 ++++++----------------
 libavfilter/vulkan/Makefile                        |  1 +
 .../{scdet.comp.glsl => blackdetect.comp.glsl}     | 44 +++++------
 4 files changed, 47 insertions(+), 86 deletions(-)

diff --git a/configure b/configure
index 18fe7271aa..57316db04d 100755
--- a/configure
+++ b/configure
@@ -4154,7 +4154,7 @@ ass_filter_deps="libass"
 avgblur_opencl_filter_deps="opencl"
 avgblur_vulkan_filter_deps="vulkan spirv_compiler"
 azmq_filter_deps="libzmq"
-blackdetect_vulkan_filter_deps="vulkan spirv_library"
+blackdetect_vulkan_filter_deps="vulkan spirv_compiler"
 blackframe_filter_deps="gpl"
 blend_vulkan_filter_deps="vulkan spirv_compiler"
 boxblur_filter_deps="gpl"
diff --git a/libavfilter/vf_blackdetect_vulkan.c 
b/libavfilter/vf_blackdetect_vulkan.c
index 279b057148..bd3a92c858 100644
--- a/libavfilter/vf_blackdetect_vulkan.c
+++ b/libavfilter/vf_blackdetect_vulkan.c
@@ -19,7 +19,6 @@
  */
 
 #include <float.h>
-#include "libavutil/vulkan_spirv.h"
 #include "libavutil/opt.h"
 #include "libavutil/timestamp.h"
 #include "vulkan_filter.h"
@@ -27,6 +26,9 @@
 #include "filters.h"
 #include "video.h"
 
+extern const unsigned char ff_blackdetect_comp_spv_data[];
+extern const unsigned int ff_blackdetect_comp_spv_len;
+
 typedef struct BlackDetectVulkanContext {
     FFVulkanContext vkctx;
 
@@ -56,14 +58,8 @@ typedef struct BlackDetectBuf {
 static av_cold int init_filter(AVFilterContext *ctx)
 {
     int err;
-    uint8_t *spv_data;
-    size_t spv_len;
-    void *spv_opaque = NULL;
     BlackDetectVulkanContext *s = ctx->priv;
     FFVulkanContext *vkctx = &s->vkctx;
-    FFVulkanShader *shd;
-    FFVkSPIRVCompiler *spv;
-    FFVulkanDescriptorSetBinding *desc;
     const int plane = s->alpha ? 3 : 0;
 
     const AVPixFmtDescriptor *pixdesc = 
av_pix_fmt_desc_get(s->vkctx.input_format);
@@ -72,12 +68,6 @@ static av_cold int init_filter(AVFilterContext *ctx)
         return AVERROR(ENOTSUP);
     }
 
-    spv = ff_vk_spirv_init();
-    if (!spv) {
-        av_log(ctx, AV_LOG_ERROR, "Unable to initialize SPIR-V compiler!\n");
-        return AVERROR_EXTERNAL;
-    }
-
     s->qf = ff_vk_qf_find(vkctx, VK_QUEUE_COMPUTE_BIT, 0);
     if (!s->qf) {
         av_log(ctx, AV_LOG_ERROR, "Device has no compute queues\n");
@@ -86,73 +76,41 @@ static av_cold int init_filter(AVFilterContext *ctx)
     }
 
     RET(ff_vk_exec_pool_init(vkctx, s->qf, &s->e, s->qf->num*4, 0, 0, 0, 
NULL));
-    RET(ff_vk_shader_init(vkctx, &s->shd, "blackdetect",
-                          VK_SHADER_STAGE_COMPUTE_BIT,
-                          (const char *[]) { "GL_KHR_shader_subgroup_ballot" 
}, 1,
-                          32, 32, 1,
-                          0));
-    shd = &s->shd;
-
-    GLSLC(0, layout(push_constant, std430) uniform pushConstants {            
);
-    GLSLC(1,     float threshold;                                             
);
-    GLSLC(0, };                                                               
);
-
-    ff_vk_shader_add_push_const(shd, 0, sizeof(BlackDetectPushData),
+
+    SPEC_LIST_CREATE(sl, 2, 2*sizeof(uint32_t))
+    SPEC_LIST_ADD(sl, 0, 32, plane);
+    SPEC_LIST_ADD(sl, 1, 32, SLICES);
+
+    ff_vk_shader_load(&s->shd, VK_SHADER_STAGE_COMPUTE_BIT, sl,
+                      (int []) { 32, 32, 1 }, 0);
+
+    ff_vk_shader_add_push_const(&s->shd, 0, sizeof(BlackDetectPushData),
                                 VK_SHADER_STAGE_COMPUTE_BIT);
 
-    desc = (FFVulkanDescriptorSetBinding []) {
-        {
-            .name       = "input_img",
+    const FFVulkanDescriptorSetBinding desc[] = {
+        { /* input_img */
             .type       = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
-            .mem_layout = ff_vk_shader_rep_fmt(s->vkctx.input_format, 
FF_VK_REP_FLOAT),
-            .mem_quali  = "readonly",
-            .dimensions = 2,
-            .elems      = av_pix_fmt_count_planes(s->vkctx.input_format),
             .stages     = VK_SHADER_STAGE_COMPUTE_BIT,
-        }, {
-            .name        = "sum_buffer",
+            .elems      = av_pix_fmt_count_planes(s->vkctx.input_format),
+        },
+        { /* sum_buffer */
             .type        = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
             .stages      = VK_SHADER_STAGE_COMPUTE_BIT,
-            .buf_content = "uint slice_sum[];",
         }
     };
+    ff_vk_shader_add_descriptor_set(vkctx, &s->shd, desc, 2, 0, 0);
 
-    RET(ff_vk_shader_add_descriptor_set(vkctx, &s->shd, desc, 2, 0, 0));
-
-    GLSLC(0, shared uint wg_sum;                                              
);
-    GLSLC(0,                                                                  
);
-    GLSLC(0, void main()                                                      
);
-    GLSLC(0, {                                                                
);
-    GLSLC(1,     wg_sum = 0u;                                                 
);
-    GLSLC(1,     barrier();                                                   
);
-    GLSLC(0,                                                                  
);
-    GLSLC(1,     const ivec2 pos = ivec2(gl_GlobalInvocationID.xy);           
);
-    GLSLF(1,     if (!IS_WITHIN(pos, imageSize(input_img[%d])))               
,plane);
-    GLSLC(2,         return;                                                  
);
-    GLSLF(1,     float value = imageLoad(input_img[%d], pos).x;               
,plane);
-    GLSLC(1,     uvec4 isblack = subgroupBallot(value <= threshold);          
);
-    GLSLC(1,     if (subgroupElect())                                         
);
-    GLSLC(2,         atomicAdd(wg_sum, subgroupBallotBitCount(isblack));      
);
-    GLSLC(1,     barrier();                                                   
);
-    GLSLC(1,     if (gl_LocalInvocationIndex == 0u)                           
);
-    GLSLF(2,         atomicAdd(slice_sum[gl_WorkGroupID.x %% %du], wg_sum);   
,SLICES);
-    GLSLC(0, }                                                                
);
-
-    RET(spv->compile_shader(vkctx, spv, &s->shd, &spv_data, &spv_len, "main",
-                            &spv_opaque));
-    RET(ff_vk_shader_link(vkctx, &s->shd, spv_data, spv_len, "main"));
+    RET(ff_vk_shader_link(vkctx, &s->shd,
+                          ff_blackdetect_comp_spv_data,
+                          ff_blackdetect_comp_spv_len, "main"));
 
     RET(ff_vk_shader_register_exec(vkctx, &s->e, &s->shd));
 
     s->black_start = AV_NOPTS_VALUE;
     s->initialized = 1;
 
-fail:
-    if (spv_opaque)
-        spv->free_shader(spv, &spv_opaque);
-    if (spv)
-        spv->uninit(&spv);
 
+fail:
     return err;
 }
 
diff --git a/libavfilter/vulkan/Makefile b/libavfilter/vulkan/Makefile
index cd303e535e..2cfe9cfa93 100644
--- a/libavfilter/vulkan/Makefile
+++ b/libavfilter/vulkan/Makefile
@@ -2,6 +2,7 @@ clean::
        $(RM) $(CLEANSUFFIXES:%=libavfilter/vulkan/%)
 
 OBJS-$(CONFIG_AVGBLUR_VULKAN_FILTER) += vulkan/avgblur.comp.spv.o
+OBJS-$(CONFIG_BLACKDETECT_VULKAN_FILTER) += vulkan/blackdetect.comp.spv.o
 OBJS-$(CONFIG_BLEND_VULKAN_FILTER) += vulkan/blend.comp.spv.o
 OBJS-$(CONFIG_BWDIF_VULKAN_FILTER) += vulkan/bwdif.comp.spv.o
 OBJS-$(CONFIG_CHROMABER_VULKAN_FILTER) += vulkan/chromaber.comp.spv.o
diff --git a/libavfilter/vulkan/scdet.comp.glsl 
b/libavfilter/vulkan/blackdetect.comp.glsl
similarity index 57%
copy from libavfilter/vulkan/scdet.comp.glsl
copy to libavfilter/vulkan/blackdetect.comp.glsl
index a38189a759..d0a2a078e0 100644
--- a/libavfilter/vulkan/scdet.comp.glsl
+++ b/libavfilter/vulkan/blackdetect.comp.glsl
@@ -23,40 +23,42 @@
 #extension GL_EXT_shader_image_load_formatted : require
 #extension GL_EXT_scalar_block_layout : require
 #extension GL_EXT_nonuniform_qualifier : require
-#extension GL_KHR_shader_subgroup_arithmetic : require
+#extension GL_KHR_shader_subgroup_ballot : require
 #extension GL_EXT_null_initializer : require
 
-layout (constant_id = 0) const uint planes = 0;
+layout (constant_id = 0) const uint plane = 0;
 layout (constant_id = 1) const uint slices = 0;
 
 layout (local_size_x_id = 253, local_size_y_id = 254, local_size_z_id = 255) 
in;
 
-layout (set = 0, binding = 0) uniform readonly uimage2D prev_img[];
-layout (set = 0, binding = 1) uniform readonly uimage2D cur_img[];
-layout (set = 0, binding = 2, scalar) buffer sad_buffer {
-    uint frame_sad[];
+layout (set = 0, binding = 0) uniform readonly image2D input_img[];
+layout (set = 0, binding = 1, scalar) buffer sum_buffer {
+    uint slice_sum[];
+};
+
+layout (push_constant, scalar) uniform pushConstants {
+    float threshold;
 };
 
 shared uint wg_sum = { };
 
 void main()
 {
-    const uint slice = gl_WorkGroupID.x % slices;
-    const ivec2 pos = ivec2(gl_GlobalInvocationID.xy);
-
-    for (uint i = 0; i < planes; i++) {
-        const ivec2 pos = ivec2(gl_GlobalInvocationID.xy);
-        if (all(lessThan(pos, imageSize(cur_img[i])))) {
-            uvec4 prev = imageLoad(prev_img[i], pos);
-            uvec4 cur  = imageLoad(cur_img[i],  pos);
-            uvec4 sad = abs(ivec4(cur) - ivec4(prev));
-            uint sum = subgroupAdd(sad.x + sad.y + sad.z);
-            if (subgroupElect())
-                atomicAdd(wg_sum, sum);
-        }
-    }
+    ivec2 pos = ivec2(gl_GlobalInvocationID.xy);
+
+    /* oob invocs still must reach the barrier, but mustn't
+     * get counted in, threshold is positive, so the fake value of 0.0 would
+     * otherwise be counted as black */
+    bool in_bounds = all(lessThan(pos, imageSize(input_img[plane])));
+    float value = 0.0f;
+    if (in_bounds)
+        value = imageLoad(input_img[plane], pos).x;
+
+    uvec4 isblack = subgroupBallot(in_bounds && value <= threshold);
+    if (subgroupElect())
+        atomicAdd(wg_sum, subgroupBallotBitCount(isblack));
 
     barrier();
     if (gl_LocalInvocationIndex == 0)
-        atomicAdd(frame_sad[slice], wg_sum);
+        atomicAdd(slice_sum[gl_WorkGroupID.x % slices], wg_sum);
 }

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

Reply via email to