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

Git pushed a commit to branch master
in repository ffmpeg.

commit fdee87d06d1937cff6eaa5fe120fe74dbb32cebc
Author:     Lynne <[email protected]>
AuthorDate: Wed Feb 4 11:14:21 2026 +0100
Commit:     Lynne <[email protected]>
CommitDate: Thu Feb 19 19:42:28 2026 +0100

    ffv1enc_vulkan: convert RCT search shader to compile-time SPIR-V generation
---
 libavcodec/ffv1_vulkan.h                           |  12 --
 libavcodec/ffv1enc_vulkan.c                        | 198 ++++++++-------------
 libavcodec/vulkan/Makefile                         |   5 +-
 libavcodec/vulkan/ffv1_common.glsl                 |   3 +
 ...t_search.comp => ffv1_enc_rct_search.comp.glsl} |  15 +-
 5 files changed, 91 insertions(+), 142 deletions(-)

diff --git a/libavcodec/ffv1_vulkan.h b/libavcodec/ffv1_vulkan.h
index df7bac45de..5dfd12c3c6 100644
--- a/libavcodec/ffv1_vulkan.h
+++ b/libavcodec/ffv1_vulkan.h
@@ -56,18 +56,6 @@ typedef struct FFv1ShaderParams {
     int micro_version;
 } FFv1ShaderParams;
 
-typedef struct FFv1VkRCTParameters {
-    int fmt_lut[4];
-    int offset;
-    uint8_t bits;
-    uint8_t planar_rgb;
-    uint8_t color_planes;
-    uint8_t transparency;
-    uint8_t version;
-    uint8_t micro_version;
-    uint8_t padding[2];
-} FFv1VkRCTParameters;
-
 typedef struct FFv1VkResetParameters {
     uint32_t context_count[MAX_QUANT_TABLES];
     VkDeviceAddress slice_state;
diff --git a/libavcodec/ffv1enc_vulkan.c b/libavcodec/ffv1enc_vulkan.c
index 3f3da6bbae..933f2e6609 100644
--- a/libavcodec/ffv1enc_vulkan.c
+++ b/libavcodec/ffv1enc_vulkan.c
@@ -111,10 +111,12 @@ extern const char *ff_source_rangecoder_comp;
 extern const char *ff_source_ffv1_vlc_comp;
 extern const char *ff_source_ffv1_common_comp;
 extern const char *ff_source_ffv1_reset_comp;
-extern const char *ff_source_ffv1_rct_search_comp;
 extern const char *ff_source_ffv1_enc_setup_comp;
 extern const char *ff_source_ffv1_enc_comp;
 
+extern const unsigned char ff_ffv1_enc_rct_search_comp_spv_data[];
+extern const unsigned int ff_ffv1_enc_rct_search_comp_spv_len;
+
 typedef struct FFv1VkParameters {
     VkDeviceAddress slice_state;
     VkDeviceAddress scratch_data;
@@ -192,63 +194,31 @@ static void add_push_data(FFVulkanShader *shd)
                                 VK_SHADER_STAGE_COMPUTE_BIT);
 }
 
-typedef struct FFv1VkRCTSearchParameters {
-    int fmt_lut[4];
-    int rct_offset;
-    uint8_t planar_rgb;
-    uint8_t transparency;
-    uint8_t key_frame;
-    uint8_t force_pcm;
-    uint8_t version;
-    uint8_t micro_version;
-    uint8_t padding[2];
-} FFv1VkRCTSearchParameters;
-
 static int run_rct_search(AVCodecContext *avctx, FFVkExecContext *exec,
                           AVFrame *enc_in, VkImageView *enc_in_views,
-                          FFVkBuffer *slice_data_buf, uint32_t slice_data_size)
+                          FFVkBuffer *slice_data_buf, uint32_t slice_data_size,
+                          FFv1ShaderParams *pd)
 {
     VulkanEncodeFFv1Context *fv = avctx->priv_data;
     FFV1Context *f = &fv->ctx;
     FFVulkanFunctions *vk = &fv->s.vkfn;
-    AVHWFramesContext *src_hwfc = (AVHWFramesContext 
*)enc_in->hw_frames_ctx->data;
-    FFv1VkRCTSearchParameters pd;
 
     /* Update descriptors */
     ff_vk_shader_update_desc_buffer(&fv->s, exec, &fv->rct_search,
-                                    0, 0, 0,
+                                    1, 0, 0,
                                     slice_data_buf,
                                     0, slice_data_size*f->slice_count,
                                     VK_FORMAT_UNDEFINED);
     ff_vk_shader_update_img_array(&fv->s, exec, &fv->rct_search,
                                   enc_in, enc_in_views,
-                                  0, 1,
+                                  1, 1,
                                   VK_IMAGE_LAYOUT_GENERAL,
                                   VK_NULL_HANDLE);
 
     ff_vk_exec_bind_shader(&fv->s, exec, &fv->rct_search);
-
-    pd = (FFv1VkRCTSearchParameters) {
-        .rct_offset = 1 << f->bits_per_raw_sample,
-        .planar_rgb = ff_vk_mt_is_np_rgb(src_hwfc->sw_format) &&
-                      (ff_vk_count_images((AVVkFrame *)enc_in->data[0]) > 1),
-        .transparency = f->transparency,
-        .key_frame = f->key_frame,
-        .force_pcm = fv->force_pcm,
-        .version = f->version,
-        .micro_version = f->micro_version,
-    };
-
-    if (avctx->sw_pix_fmt == AV_PIX_FMT_GBRP10 ||
-        avctx->sw_pix_fmt == AV_PIX_FMT_GBRP12 ||
-        avctx->sw_pix_fmt == AV_PIX_FMT_GBRP14)
-        memcpy(pd.fmt_lut, (int [4]) { 2, 1, 0, 3 }, 4*sizeof(int));
-    else
-        ff_vk_set_perm(avctx->sw_pix_fmt, pd.fmt_lut, 1);
-
     ff_vk_shader_update_push_const(&fv->s, exec, &fv->rct_search,
                                    VK_SHADER_STAGE_COMPUTE_BIT,
-                                   0, sizeof(pd), &pd);
+                                   0, sizeof(FFv1ShaderParams), pd);
 
     vk->CmdDispatch(exec->buf, fv->ctx.num_h_slices, fv->ctx.num_v_slices, 1);
 
@@ -265,7 +235,7 @@ static int vulkan_encode_ffv1_submit_frame(AVCodecContext 
*avctx,
     FFVulkanFunctions *vk = &fv->s.vkfn;
 
     VulkanEncodeFFv1FrameData *fd = exec->opaque;
-    FFv1VkParameters pd;
+    FFv1VkParameters pd_old;
 
     /* Slice data */
     AVBufferRef *slice_data_ref;
@@ -401,6 +371,34 @@ static int vulkan_encode_ffv1_submit_frame(AVCodecContext 
*avctx,
                                     FF_VK_REP_NATIVE));
     }
 
+    /* With everything allocated, setup push data */
+    FFv1ShaderParams pd = {
+        .slice_data = out_data_buf->address,
+        .slice_state = slice_data_buf->address + f->slice_count*256,
+
+        .img_size[0] = fv->s.frames->width,
+        .img_size[1] = fv->s.frames->height,
+
+        .plane_state_size = plane_state_size,
+        .key_frame = f->key_frame,
+        .crcref = f->crcref,
+        .micro_version = f->micro_version,
+    };
+
+    for (int i = 0; i < f->quant_table_count; i++) {
+        pd.context_count[i] = f->context_count[i];
+        pd.extend_lookup[i] = f->quant_tables[i][3][127] ||
+                              f->quant_tables[i][4][127];
+    }
+
+    /* For some reason the C FFv1 encoder/decoder treats these differently */
+    if (avctx->sw_pix_fmt == AV_PIX_FMT_GBRP10 ||
+        avctx->sw_pix_fmt == AV_PIX_FMT_GBRP12 ||
+        avctx->sw_pix_fmt == AV_PIX_FMT_GBRP14)
+        memcpy(pd.fmt_lut, (int [4]) { 2, 1, 0, 3 }, 4*sizeof(int));
+    else
+        ff_vk_set_perm(avctx->sw_pix_fmt, pd.fmt_lut, 1);
+
     /* Setup shader */
     ff_vk_shader_update_desc_buffer(&fv->s, exec, &fv->setup,
                                     1, 0, 0,
@@ -437,7 +435,7 @@ static int vulkan_encode_ffv1_submit_frame(AVCodecContext 
*avctx,
     if (fv->optimize_rct) {
         RET(run_rct_search(avctx, exec,
                            src, src_views,
-                           slice_data_buf, slice_data_size));
+                           slice_data_buf, slice_data_size, &pd));
 
         /* Make sure the writes are visible to the setup shader */
         ff_vk_buf_barrier(buf_bar[nb_buf_bar++], slice_data_buf,
@@ -454,7 +452,7 @@ static int vulkan_encode_ffv1_submit_frame(AVCodecContext 
*avctx,
 
     /* Run setup shader */
     ff_vk_exec_bind_shader(&fv->s, exec, &fv->setup);
-    pd = (FFv1VkParameters) {
+    pd_old = (FFv1VkParameters) {
         .slice_state = slice_data_buf->address + f->slice_count*256,
         .out_data = out_data_buf->address,
         .bits_per_raw_sample = f->bits_per_raw_sample,
@@ -491,16 +489,16 @@ static int vulkan_encode_ffv1_submit_frame(AVCodecContext 
*avctx,
     if (avctx->sw_pix_fmt == AV_PIX_FMT_GBRP10 ||
         avctx->sw_pix_fmt == AV_PIX_FMT_GBRP12 ||
         avctx->sw_pix_fmt == AV_PIX_FMT_GBRP14)
-        memcpy(pd.fmt_lut, (int [4]) { 2, 1, 0, 3 }, 4*sizeof(int));
+        memcpy(pd_old.fmt_lut, (int [4]) { 2, 1, 0, 3 }, 4*sizeof(int));
     else
-        ff_vk_set_perm(avctx->sw_pix_fmt, pd.fmt_lut, 1);
+        ff_vk_set_perm(avctx->sw_pix_fmt, pd_old.fmt_lut, 1);
 
     for (int i = 0; i < f->quant_table_count; i++)
-        pd.extend_lookup[i] = (f->quant_tables[i][3][127] != 0) ||
-                              (f->quant_tables[i][4][127] != 0);
+        pd_old.extend_lookup[i] = (f->quant_tables[i][3][127] != 0) ||
+                                  (f->quant_tables[i][4][127] != 0);
     ff_vk_shader_update_push_const(&fv->s, exec, &fv->setup,
                                    VK_SHADER_STAGE_COMPUTE_BIT,
-                                   0, sizeof(pd), &pd);
+                                   0, sizeof(pd_old), &pd_old);
     vk->CmdDispatch(exec->buf, fv->ctx.num_h_slices, fv->ctx.num_v_slices, 1);
 
     /* Clean up temporary image */
@@ -623,7 +621,7 @@ static int vulkan_encode_ffv1_submit_frame(AVCodecContext 
*avctx,
     ff_vk_exec_bind_shader(&fv->s, exec, &fv->enc);
     ff_vk_shader_update_push_const(&fv->s, exec, &fv->enc,
                                    VK_SHADER_STAGE_COMPUTE_BIT,
-                                   0, sizeof(pd), &pd);
+                                   0, sizeof(pd_old), &pd_old);
     vk->CmdDispatch(exec->buf, fv->ctx.num_h_slices, fv->ctx.num_v_slices, 1);
 
     /* Submit */
@@ -970,102 +968,46 @@ static void define_shared_code(AVCodecContext *avctx, 
FFVulkanShader *shd)
     GLSLD(ff_source_ffv1_common_comp);
 }
 
-static int init_rct_search_shader(AVCodecContext *avctx, FFVkSPIRVCompiler 
*spv)
+static int init_rct_search_shader(AVCodecContext *avctx, VkSpecializationInfo 
*sl)
 {
     int err;
     VulkanEncodeFFv1Context *fv = avctx->priv_data;
-    FFV1Context *f = &fv->ctx;
     FFVulkanShader *shd = &fv->rct_search;
-    FFVulkanDescriptorSetBinding *desc_set;
-
-    uint8_t *spv_data;
-    size_t spv_len;
-    void *spv_opaque = NULL;
-
-    RET(ff_vk_shader_init(&fv->s, shd, "ffv1_rct_search",
-                          VK_SHADER_STAGE_COMPUTE_BIT,
-                          (const char *[]) { "GL_EXT_buffer_reference",
-                                             "GL_EXT_buffer_reference2",
-                                             "GL_EXT_null_initializer" }, 3,
-                          32, 32, 1,
-                          0));
 
-    /* Common codec header */
-    GLSLD(ff_source_common_comp);
+    ff_vk_shader_load(shd, VK_SHADER_STAGE_COMPUTE_BIT, sl,
+                      (uint32_t []) { 32, 32, 1 }, 0);
 
-    GLSLC(0, layout(push_constant, scalar) uniform pushConstants {             
);
-    GLSLC(1,    ivec4 fmt_lut;                                                 
);
-    GLSLC(1,    int rct_offset;                                                
);
-    GLSLC(1,    uint8_t planar_rgb;                                            
);
-    GLSLC(1,    uint8_t transparency;                                          
);
-    GLSLC(1,    uint8_t key_frame;                                             
);
-    GLSLC(1,    uint8_t force_pcm;                                             
);
-    GLSLC(1,    uint8_t version;                                               
);
-    GLSLC(1,    uint8_t micro_version;                                         
);
-    GLSLC(1,    uint8_t padding[3];                                            
);
-    GLSLC(0, };                                                                
);
-    ff_vk_shader_add_push_const(shd, 0, sizeof(FFv1VkResetParameters),
+    ff_vk_shader_add_push_const(shd, 0, sizeof(FFv1ShaderParams),
                                 VK_SHADER_STAGE_COMPUTE_BIT);
 
-    av_bprintf(&shd->src, "#define MAX_QUANT_TABLES %i\n", MAX_QUANT_TABLES);
-    av_bprintf(&shd->src, "#define MAX_CONTEXT_INPUTS %i\n", 
MAX_CONTEXT_INPUTS);
-    av_bprintf(&shd->src, "#define MAX_QUANT_TABLE_SIZE %i\n", 
MAX_QUANT_TABLE_SIZE);
-
-    /* Never used */
-    desc_set = (FFVulkanDescriptorSetBinding []) {
-        {
-            .name        = "rangecoder_static_buf",
-            .type        = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
-            .stages      = VK_SHADER_STAGE_COMPUTE_BIT,
-            .mem_layout  = "scalar",
-            .buf_content = "uint8_t zero_one_state[512];",
-        },
-        {
-            .name        = "quant_buf",
-            .type        = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
-            .stages      = VK_SHADER_STAGE_COMPUTE_BIT,
-            .mem_layout  = "scalar",
-            .buf_content = "int16_t quant_table[MAX_QUANT_TABLES]"
-                           "[MAX_CONTEXT_INPUTS][MAX_QUANT_TABLE_SIZE];",
+    const FFVulkanDescriptorSetBinding desc_set_const[] = {
+        { /* rangecoder_buf */
+            .type   = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
+            .stages = VK_SHADER_STAGE_COMPUTE_BIT,
         },
     };
-    RET(ff_vk_shader_add_descriptor_set(&fv->s, shd, desc_set, 2, 1, 1));
+    ff_vk_shader_add_descriptor_set(&fv->s, shd, desc_set_const, 1, 1, 0);
 
-    define_shared_code(avctx, shd);
-
-    desc_set = (FFVulkanDescriptorSetBinding []) {
-        {
-            .name        = "slice_data_buf",
-            .type        = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
-            .stages      = VK_SHADER_STAGE_COMPUTE_BIT,
-            .buf_content = "SliceContext slice_ctx",
-            .buf_elems   = f->max_slice_count,
+    const FFVulkanDescriptorSetBinding desc_set[] = {
+        { /* slice_data_buf */
+            .type   = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
+            .stages = VK_SHADER_STAGE_COMPUTE_BIT,
         },
-        {
-            .name       = "src",
-            .type       = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
-            .dimensions = 2,
-            .mem_layout = ff_vk_shader_rep_fmt(fv->s.frames->sw_format,
-                                               FF_VK_REP_NATIVE),
-            .elems      = av_pix_fmt_count_planes(fv->s.frames->sw_format),
-            .mem_quali  = "readonly",
-            .stages     = VK_SHADER_STAGE_COMPUTE_BIT,
+        { /* src */
+            .type   = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
+            .stages = VK_SHADER_STAGE_COMPUTE_BIT,
+            .elems  = av_pix_fmt_count_planes(fv->s.frames->sw_format),
         },
     };
-    RET(ff_vk_shader_add_descriptor_set(&fv->s, shd, desc_set, 2, 0, 0));
-
-    GLSLD(ff_source_ffv1_rct_search_comp);
+    ff_vk_shader_add_descriptor_set(&fv->s, shd, desc_set, 2, 0, 0);
 
-    RET(spv->compile_shader(&fv->s, spv, shd, &spv_data, &spv_len, "main",
-                            &spv_opaque));
-    RET(ff_vk_shader_link(&fv->s, shd, spv_data, spv_len, "main"));
+    RET(ff_vk_shader_link(&fv->s, shd,
+                          ff_ffv1_enc_rct_search_comp_spv_data,
+                          ff_ffv1_enc_rct_search_comp_spv_len, "main"));
 
     RET(ff_vk_shader_register_exec(&fv->s, &fv->exec_pool, shd));
 
 fail:
-    if (spv_opaque)
-        spv->free_shader(spv, &spv_opaque);
-
     return err;
 }
 
@@ -1575,8 +1517,14 @@ static av_cold int 
vulkan_encode_ffv1_init(AVCodecContext *avctx)
     /* Init rct search shader */
     fv->optimize_rct = fv->is_rgb && f->version >= 4 &&
                        !fv->force_pcm && fv->optimize_rct;
+
+    /* Init shader specialization consts */
+    SPEC_LIST_CREATE(sl, 16, 16*sizeof(uint32_t))
+    ff_ffv1_vk_set_common_sl(avctx, f, sl, fv->s.frames->sw_format);
+    SPEC_LIST_ADD(sl, 15, 32, fv->force_pcm);
+
     if (fv->optimize_rct) {
-        err = init_rct_search_shader(avctx, spv);
+        err = init_rct_search_shader(avctx, sl);
         if (err < 0) {
             spv->uninit(&spv);
             return err;
diff --git a/libavcodec/vulkan/Makefile b/libavcodec/vulkan/Makefile
index a9ff44c52d..79b5facc51 100644
--- a/libavcodec/vulkan/Makefile
+++ b/libavcodec/vulkan/Makefile
@@ -4,8 +4,9 @@ clean::
 OBJS-$(CONFIG_FFV1_VULKAN_ENCODER)  +=  vulkan/common.o \
                                        vulkan/rangecoder.o vulkan/ffv1_vlc.o \
                                        vulkan/ffv1_common.o 
vulkan/ffv1_reset.o \
-                                       vulkan/ffv1_enc_setup.o 
vulkan/ffv1_enc.o \
-                                       vulkan/ffv1_rct_search.o
+                                       vulkan/ffv1_enc_setup.o 
vulkan/ffv1_enc.o
+
+OBJS-$(CONFIG_FFV1_VULKAN_ENCODER) += vulkan/ffv1_enc_rct_search.comp.spv.o
 
 OBJS-$(CONFIG_FFV1_VULKAN_HWACCEL) += vulkan/ffv1_dec_setup.comp.spv.o \
                                       vulkan/ffv1_dec_reset.comp.spv.o \
diff --git a/libavcodec/vulkan/ffv1_common.glsl 
b/libavcodec/vulkan/ffv1_common.glsl
index d77f2df96e..e835cc7c9f 100644
--- a/libavcodec/vulkan/ffv1_common.glsl
+++ b/libavcodec/vulkan/ffv1_common.glsl
@@ -52,6 +52,9 @@ layout (constant_id = 13) const int chroma_shift_x = 0;
 layout (constant_id = 14) const int chroma_shift_y = 0;
 const ivec2 chroma_shift = ivec2(chroma_shift_x, chroma_shift_y);
 
+/* Encoder-only */
+layout (constant_id = 15) const bool force_pcm = false;
+
 layout (push_constant, scalar) uniform pushConstants {
     u8buf slice_data;
     u8buf slice_state;
diff --git a/libavcodec/vulkan/ffv1_rct_search.comp 
b/libavcodec/vulkan/ffv1_enc_rct_search.comp.glsl
similarity index 94%
rename from libavcodec/vulkan/ffv1_rct_search.comp
rename to libavcodec/vulkan/ffv1_enc_rct_search.comp.glsl
index 055bde46c4..66fc73a8e5 100644
--- a/libavcodec/vulkan/ffv1_rct_search.comp
+++ b/libavcodec/vulkan/ffv1_enc_rct_search.comp.glsl
@@ -20,13 +20,21 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
+#pragma shader_stage(compute)
+#extension GL_GOOGLE_include_directive : require
+
+#define ENCODE
+#include "common.comp"
+#include "ffv1_common.glsl"
+
+layout (set = 1, binding = 1) uniform uimage2D src[];
+
 ivec3 load_components(ivec2 pos)
 {
     ivec3 pix = ivec3(imageLoad(src[0], pos));
-    if (planar_rgb != 0) {
+    if (planar_rgb)
         for (int i = 1; i < 3; i++)
             pix[i] = int(imageLoad(src[i], pos)[0]);
-    }
 
     return ivec3(pix[fmt_lut[0]], pix[fmt_lut[1]], pix[fmt_lut[2]]);
 }
@@ -132,8 +140,9 @@ void coeff_search(inout SliceContext sc)
 
 void main(void)
 {
-    if (force_pcm == 1)
+    if (force_pcm)
         return;
+
     const uint slice_idx = gl_WorkGroupID.y*gl_NumWorkGroups.x + 
gl_WorkGroupID.x;
     coeff_search(slice_ctx[slice_idx]);
 }

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

Reply via email to