* [FFmpeg-devel] [PR] vulkan: convert ProRes, ProRes RAW and 2 filters to compile-time SPIR-V generation (PR #21356)
@ 2026-01-02 14:42 Lynne via ffmpeg-devel
0 siblings, 0 replies; only message in thread
From: Lynne via ffmpeg-devel @ 2026-01-02 14:42 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: Lynne
PR #21356 opened by Lynne
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/21356
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/21356.patch
glslang is slow, difficult to link against, awful, inefficient, awful, not really threadsafe. Same with shaderc, except shaderc is dead-ish.
This makes glsl be treated like any other language that gets compiled, like CUDA and Metal.
>From b344e28b3bfc1ec934fced636d00d2ea0725e276 Mon Sep 17 00:00:00 2001
From: Lynne <dev@lynne.ee>
Date: Fri, 2 Jan 2026 03:15:40 +0100
Subject: [PATCH 01/12] vulkan: switch to static allocation for temporary
descriptor data
Simplifies management, and the hardware is limited to 4 descriptor sets
and whatever bindings.
---
libavutil/vulkan.c | 125 +++++++++------------------------------------
libavutil/vulkan.h | 27 ++++++----
2 files changed, 40 insertions(+), 112 deletions(-)
diff --git a/libavutil/vulkan.c b/libavutil/vulkan.c
index 33d7e8aace..85501c5bbd 100644
--- a/libavutil/vulkan.c
+++ b/libavutil/vulkan.c
@@ -333,13 +333,9 @@ void ff_vk_exec_pool_free(FFVulkanContext *s, FFVkExecPool *pool)
vk->DestroyDescriptorPool(s->hwctx->act_dev, sd->desc_pool,
s->hwctx->alloc);
- av_freep(&sd->desc_set_buf);
- av_freep(&sd->desc_bind);
av_freep(&sd->desc_sets);
}
- av_freep(&pool->reg_shd);
-
for (int i = 0; i < pool->pool_size; i++) {
if (pool->cmd_buf_pools[i])
vk->FreeCommandBuffers(s->hwctx->act_dev, pool->cmd_buf_pools[i],
@@ -1492,21 +1488,11 @@ int ff_vk_host_map_buffer(FFVulkanContext *s, AVBufferRef **dst,
int ff_vk_shader_add_push_const(FFVulkanShader *shd, int offset, int size,
VkShaderStageFlagBits stage)
{
- VkPushConstantRange *pc;
-
- shd->push_consts = av_realloc_array(shd->push_consts,
- sizeof(*shd->push_consts),
- shd->push_consts_num + 1);
- if (!shd->push_consts)
- return AVERROR(ENOMEM);
-
- pc = &shd->push_consts[shd->push_consts_num++];
- memset(pc, 0, sizeof(*pc));
-
+ VkPushConstantRange *pc = &shd->push_consts[shd->push_consts_num++];
+ av_assert1(shd->push_consts_num < FF_VK_MAX_PUSH_CONSTS);
pc->stageFlags = stage;
pc->offset = offset;
pc->size = size;
-
return 0;
}
@@ -2329,11 +2315,6 @@ static int init_descriptors(FFVulkanContext *s, FFVulkanShader *shd)
VkResult ret;
FFVulkanFunctions *vk = &s->vkfn;
- shd->desc_layout = av_malloc_array(shd->nb_descriptor_sets,
- sizeof(*shd->desc_layout));
- if (!shd->desc_layout)
- return AVERROR(ENOMEM);
-
if (!(s->extensions & FF_VK_EXT_DESCRIPTOR_BUFFER)) {
int has_singular = 0;
int max_descriptors = 0;
@@ -2405,11 +2386,6 @@ int ff_vk_shader_link(FFVulkanContext *s, FFVulkanShader *shd,
return err;
if (s->extensions & FF_VK_EXT_DESCRIPTOR_BUFFER) {
- shd->bound_buffer_indices = av_calloc(shd->nb_descriptor_sets,
- sizeof(*shd->bound_buffer_indices));
- if (!shd->bound_buffer_indices)
- return AVERROR(ENOMEM);
-
for (int i = 0; i < shd->nb_descriptor_sets; i++)
shd->bound_buffer_indices[i] = i;
}
@@ -2469,31 +2445,13 @@ int ff_vk_shader_add_descriptor_set(FFVulkanContext *s, FFVulkanShader *shd,
int singular, int print_to_shader_only)
{
int has_sampler = 0;
- FFVulkanDescriptorSet *set;
if (print_to_shader_only)
goto print;
- /* Actual layout allocated for the pipeline */
- set = av_realloc_array(shd->desc_set,
- sizeof(*shd->desc_set),
- shd->nb_descriptor_sets + 1);
- if (!set)
- return AVERROR(ENOMEM);
- shd->desc_set = set;
-
- set = &set[shd->nb_descriptor_sets];
- memset(set, 0, sizeof(*set));
-
- set->binding = av_calloc(nb, sizeof(*set->binding));
- if (!set->binding)
- return AVERROR(ENOMEM);
-
- set->binding_offset = av_calloc(nb, sizeof(*set->binding_offset));
- if (!set->binding_offset) {
- av_freep(&set->binding);
- return AVERROR(ENOMEM);
- }
+ FFVulkanDescriptorSet *set = &shd->desc_set[shd->nb_descriptor_sets++];
+ av_assert1(shd->nb_descriptor_sets < FF_VK_MAX_DESCRIPTOR_SETS);
+ av_assert1(nb < FF_VK_MAX_DESCRIPTOR_BINDINGS);
for (int i = 0; i < nb; i++) {
set->binding[i].binding = i;
@@ -2515,20 +2473,12 @@ int ff_vk_shader_add_descriptor_set(FFVulkanContext *s, FFVulkanShader *shd,
if (!(s->extensions & FF_VK_EXT_DESCRIPTOR_BUFFER)) {
for (int i = 0; i < nb; i++) {
int j;
- VkDescriptorPoolSize *desc_pool_size;
for (j = 0; j < shd->nb_desc_pool_size; j++)
if (shd->desc_pool_size[j].type == desc[i].type)
break;
if (j >= shd->nb_desc_pool_size) {
- desc_pool_size = av_realloc_array(shd->desc_pool_size,
- sizeof(*desc_pool_size),
- shd->nb_desc_pool_size + 1);
- if (!desc_pool_size)
- return AVERROR(ENOMEM);
-
- shd->desc_pool_size = desc_pool_size;
shd->nb_desc_pool_size++;
- memset(&desc_pool_size[j], 0, sizeof(VkDescriptorPoolSize));
+ av_assert1(shd->nb_desc_pool_size < FF_VK_MAX_DESCRIPTOR_TYPES);
}
shd->desc_pool_size[j].type = desc[i].type;
shd->desc_pool_size[j].descriptorCount += FFMAX(desc[i].elems, 1);
@@ -2537,7 +2487,6 @@ int ff_vk_shader_add_descriptor_set(FFVulkanContext *s, FFVulkanShader *shd,
set->singular = singular;
set->nb_bindings = nb;
- shd->nb_descriptor_sets++;
print:
/* Write shader info */
@@ -2604,33 +2553,17 @@ int ff_vk_shader_register_exec(FFVulkanContext *s, FFVkExecPool *pool,
FFVulkanShader *shd)
{
int err;
- FFVulkanShaderData *sd;
if (!shd->nb_descriptor_sets)
return 0;
- sd = av_realloc_array(pool->reg_shd,
- sizeof(*pool->reg_shd),
- pool->nb_reg_shd + 1);
- if (!sd)
- return AVERROR(ENOMEM);
-
- pool->reg_shd = sd;
- sd = &sd[pool->nb_reg_shd++];
- memset(sd, 0, sizeof(*sd));
+ FFVulkanShaderData *sd = &pool->reg_shd[pool->nb_reg_shd++];
+ av_assert1(pool->nb_reg_shd < FF_VK_MAX_SHADERS);
sd->shd = shd;
sd->nb_descriptor_sets = shd->nb_descriptor_sets;
if (s->extensions & FF_VK_EXT_DESCRIPTOR_BUFFER) {
- sd->desc_bind = av_malloc_array(sd->nb_descriptor_sets, sizeof(*sd->desc_bind));
- if (!sd->desc_bind)
- return AVERROR(ENOMEM);
-
- sd->desc_set_buf = av_calloc(sd->nb_descriptor_sets, sizeof(*sd->desc_set_buf));
- if (!sd->desc_set_buf)
- return AVERROR(ENOMEM);
-
for (int i = 0; i < sd->nb_descriptor_sets; i++) {
FFVulkanDescriptorSet *set = &shd->desc_set[i];
FFVulkanDescriptorSetData *sdb = &sd->desc_set_buf[i];
@@ -2717,8 +2650,8 @@ int ff_vk_shader_register_exec(FFVulkanContext *s, FFVkExecPool *pool,
return 0;
}
-static inline FFVulkanShaderData *get_shd_data(FFVkExecContext *e,
- FFVulkanShader *shd)
+static inline const FFVulkanShaderData *get_shd_data(FFVkExecContext *e,
+ FFVulkanShader *shd)
{
for (int i = 0; i < e->parent->nb_reg_shd; i++)
if (e->parent->reg_shd[i].shd == shd)
@@ -2734,7 +2667,7 @@ static inline void update_set_descriptor(FFVulkanContext *s, FFVkExecContext *e,
{
FFVulkanFunctions *vk = &s->vkfn;
FFVulkanDescriptorSet *desc_set = &shd->desc_set[set];
- FFVulkanShaderData *sd = get_shd_data(e, shd);
+ const FFVulkanShaderData *sd = get_shd_data(e, shd);
const size_t exec_offset = desc_set->singular ? 0 : desc_set->aligned_size*e->idx;
void *desc = sd->desc_set_buf[set].desc_mem + /* Base */
@@ -2751,7 +2684,7 @@ static inline void update_set_pool_write(FFVulkanContext *s, FFVkExecContext *e,
{
FFVulkanFunctions *vk = &s->vkfn;
FFVulkanDescriptorSet *desc_set = &shd->desc_set[set];
- FFVulkanShaderData *sd = get_shd_data(e, shd);
+ const FFVulkanShaderData *sd = get_shd_data(e, shd);
if (desc_set->singular) {
for (int i = 0; i < e->parent->pool_size; i++) {
@@ -2931,7 +2864,7 @@ void ff_vk_exec_bind_shader(FFVulkanContext *s, FFVkExecContext *e,
{
FFVulkanFunctions *vk = &s->vkfn;
VkDeviceSize offsets[1024];
- FFVulkanShaderData *sd = get_shd_data(e, shd);
+ const FFVulkanShaderData *sd = get_shd_data(e, shd);
if (s->extensions & FF_VK_EXT_SHADER_OBJECT) {
VkShaderStageFlagBits stages = shd->stage;
@@ -2943,12 +2876,15 @@ void ff_vk_exec_bind_shader(FFVulkanContext *s, FFVkExecContext *e,
if (sd && sd->nb_descriptor_sets) {
if (s->extensions & FF_VK_EXT_DESCRIPTOR_BUFFER) {
for (int i = 0; i < sd->nb_descriptor_sets; i++)
- offsets[i] = shd->desc_set[i].singular ? 0 : shd->desc_set[i].aligned_size*e->idx;
+ offsets[i] = shd->desc_set[i].singular ?
+ 0 : shd->desc_set[i].aligned_size*e->idx;
/* Bind descriptor buffers */
- vk->CmdBindDescriptorBuffersEXT(e->buf, sd->nb_descriptor_sets, sd->desc_bind);
+ vk->CmdBindDescriptorBuffersEXT(e->buf, sd->nb_descriptor_sets,
+ sd->desc_bind);
/* Binding offsets */
- vk->CmdSetDescriptorBufferOffsetsEXT(e->buf, shd->bind_point, shd->pipeline_layout,
+ vk->CmdSetDescriptorBufferOffsetsEXT(e->buf, shd->bind_point,
+ shd->pipeline_layout,
0, sd->nb_descriptor_sets,
shd->bound_buffer_indices, offsets);
} else if (!shd->use_push) {
@@ -2980,25 +2916,10 @@ void ff_vk_shader_free(FFVulkanContext *s, FFVulkanShader *shd)
vk->DestroyPipelineLayout(s->hwctx->act_dev, shd->pipeline_layout,
s->hwctx->alloc);
- for (int i = 0; i < shd->nb_descriptor_sets; i++) {
- FFVulkanDescriptorSet *set = &shd->desc_set[i];
- av_free(set->binding);
- av_free(set->binding_offset);
- }
-
- if (shd->desc_layout) {
- for (int i = 0; i < shd->nb_descriptor_sets; i++)
- if (shd->desc_layout[i])
- vk->DestroyDescriptorSetLayout(s->hwctx->act_dev, shd->desc_layout[i],
- s->hwctx->alloc);
- }
-
- av_freep(&shd->desc_pool_size);
- av_freep(&shd->desc_layout);
- av_freep(&shd->desc_set);
- av_freep(&shd->bound_buffer_indices);
- av_freep(&shd->push_consts);
- shd->push_consts_num = 0;
+ for (int i = 0; i < shd->nb_descriptor_sets; i++)
+ if (shd->desc_layout[i])
+ vk->DestroyDescriptorSetLayout(s->hwctx->act_dev, shd->desc_layout[i],
+ s->hwctx->alloc);
}
void ff_vk_uninit(FFVulkanContext *s)
diff --git a/libavutil/vulkan.h b/libavutil/vulkan.h
index cde2876e46..7c513fb8e2 100644
--- a/libavutil/vulkan.h
+++ b/libavutil/vulkan.h
@@ -71,6 +71,12 @@
#define DUP_SAMPLER(x) { x, x, x, x }
+#define FF_VK_MAX_DESCRIPTOR_SETS 4
+#define FF_VK_MAX_DESCRIPTOR_BINDINGS 16
+#define FF_VK_MAX_DESCRIPTOR_TYPES 16
+#define FF_VK_MAX_PUSH_CONSTS 4
+#define FF_VK_MAX_SHADERS 16
+
typedef struct FFVulkanDescriptorSetBinding {
const char *name;
VkDescriptorType type;
@@ -175,8 +181,9 @@ typedef struct FFVulkanDescriptorSet {
VkDeviceSize aligned_size; /* descriptorBufferOffsetAlignment */
VkBufferUsageFlags usage;
- VkDescriptorSetLayoutBinding *binding;
- VkDeviceSize *binding_offset;
+ VkDescriptorSetLayoutBinding binding[FF_VK_MAX_DESCRIPTOR_BINDINGS];
+ VkDeviceSize binding_offset[FF_VK_MAX_DESCRIPTOR_BINDINGS];
+
int nb_bindings;
/* Descriptor set is shared between all submissions */
@@ -208,20 +215,20 @@ typedef struct FFVulkanShader {
VkPipelineLayout pipeline_layout;
/* Push consts */
- VkPushConstantRange *push_consts;
+ VkPushConstantRange push_consts[FF_VK_MAX_PUSH_CONSTS];
int push_consts_num;
/* Descriptor sets */
- FFVulkanDescriptorSet *desc_set;
+ FFVulkanDescriptorSet desc_set[FF_VK_MAX_DESCRIPTOR_SETS];
int nb_descriptor_sets;
/* Descriptor buffer */
- VkDescriptorSetLayout *desc_layout;
- uint32_t *bound_buffer_indices;
+ VkDescriptorSetLayout desc_layout[FF_VK_MAX_DESCRIPTOR_SETS];
+ uint32_t bound_buffer_indices[FF_VK_MAX_DESCRIPTOR_SETS];
/* Descriptor pool */
int use_push;
- VkDescriptorPoolSize *desc_pool_size;
+ VkDescriptorPoolSize desc_pool_size[FF_VK_MAX_DESCRIPTOR_TYPES];
int nb_desc_pool_size;
} FFVulkanShader;
@@ -237,8 +244,8 @@ typedef struct FFVulkanShaderData {
int nb_descriptor_sets;
/* Descriptor buffer */
- FFVulkanDescriptorSetData *desc_set_buf;
- VkDescriptorBufferBindingInfoEXT *desc_bind;
+ FFVulkanDescriptorSetData desc_set_buf[FF_VK_MAX_DESCRIPTOR_SETS];
+ VkDescriptorBufferBindingInfoEXT desc_bind[FF_VK_MAX_DESCRIPTOR_SETS];
/* Descriptor pools */
VkDescriptorSet *desc_sets;
@@ -263,7 +270,7 @@ typedef struct FFVkExecPool {
size_t qd_size;
/* Registered shaders' data */
- FFVulkanShaderData *reg_shd;
+ FFVulkanShaderData reg_shd[FF_VK_MAX_SHADERS];
int nb_reg_shd;
} FFVkExecPool;
--
2.49.1
>From 76730425be88a70027bb61f7f1aa16d44b4adab7 Mon Sep 17 00:00:00 2001
From: Lynne <dev@lynne.ee>
Date: Fri, 2 Jan 2026 12:30:54 +0100
Subject: [PATCH 02/12] vulkan_filter: don't use lg_size[2] as the number of
workgroup.z
This was put there because who knows why, but it's wrong, this
ends up having double dispatches in the z direction if non-1.
---
libavfilter/vulkan_filter.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/libavfilter/vulkan_filter.c b/libavfilter/vulkan_filter.c
index e049efec03..44a4ce7242 100644
--- a/libavfilter/vulkan_filter.c
+++ b/libavfilter/vulkan_filter.c
@@ -304,7 +304,7 @@ int ff_vk_filter_process_simple(FFVulkanContext *vkctx, FFVkExecPool *e,
vk->CmdDispatch(exec->buf,
FFALIGN(vkctx->output_width, shd->lg_size[0])/shd->lg_size[0],
FFALIGN(vkctx->output_height, shd->lg_size[1])/shd->lg_size[1],
- shd->lg_size[2]);
+ 1);
return ff_vk_exec_submit(vkctx, exec);
fail:
@@ -395,7 +395,7 @@ int ff_vk_filter_process_2pass(FFVulkanContext *vkctx, FFVkExecPool *e,
vk->CmdDispatch(exec->buf,
FFALIGN(vkctx->output_width, shd->lg_size[0])/shd->lg_size[0],
FFALIGN(vkctx->output_height, shd->lg_size[1])/shd->lg_size[1],
- shd->lg_size[2]);
+ 1);
}
return ff_vk_exec_submit(vkctx, exec);
@@ -474,7 +474,7 @@ int ff_vk_filter_process_Nin(FFVulkanContext *vkctx, FFVkExecPool *e,
vk->CmdDispatch(exec->buf,
FFALIGN(vkctx->output_width, shd->lg_size[0])/shd->lg_size[0],
FFALIGN(vkctx->output_height, shd->lg_size[1])/shd->lg_size[1],
- shd->lg_size[2]);
+ 1);
return ff_vk_exec_submit(vkctx, exec);
fail:
--
2.49.1
>From 181aaa780a29275ea20c22e807f2d1cdea0f737c Mon Sep 17 00:00:00 2001
From: Lynne <dev@lynne.ee>
Date: Fri, 2 Jan 2026 09:25:30 +0100
Subject: [PATCH 03/12] configure: rename spirv_compiler to spirv_library
More accurate.
---
configure | 60 +++++++++++++++++++++++++++----------------------------
1 file changed, 30 insertions(+), 30 deletions(-)
diff --git a/configure b/configure
index 301a3e5e3e..7b7fc0938f 100755
--- a/configure
+++ b/configure
@@ -3038,7 +3038,7 @@ exr_decoder_select="bswapdsp"
exr_encoder_deps="zlib"
ffv1_decoder_select="rangecoder"
ffv1_encoder_select="rangecoder"
-ffv1_vulkan_encoder_select="vulkan spirv_compiler"
+ffv1_vulkan_encoder_select="vulkan spirv_library"
ffvhuff_decoder_select="huffyuv_decoder"
ffvhuff_encoder_select="huffyuv_encoder"
fic_decoder_select="golomb"
@@ -3271,9 +3271,9 @@ av1_videotoolbox_hwaccel_deps="videotoolbox"
av1_videotoolbox_hwaccel_select="av1_decoder"
av1_vulkan_hwaccel_deps="vulkan"
av1_vulkan_hwaccel_select="av1_decoder"
-dpx_vulkan_hwaccel_deps="vulkan spirv_compiler"
+dpx_vulkan_hwaccel_deps="vulkan spirv_library"
dpx_vulkan_hwaccel_select="dpx_decoder"
-ffv1_vulkan_hwaccel_deps="vulkan spirv_compiler"
+ffv1_vulkan_hwaccel_deps="vulkan spirv_library"
ffv1_vulkan_hwaccel_select="ffv1_decoder"
h263_vaapi_hwaccel_deps="vaapi"
h263_vaapi_hwaccel_select="h263_decoder"
@@ -3351,9 +3351,9 @@ mpeg4_videotoolbox_hwaccel_deps="videotoolbox"
mpeg4_videotoolbox_hwaccel_select="mpeg4_decoder"
prores_videotoolbox_hwaccel_deps="videotoolbox"
prores_videotoolbox_hwaccel_select="prores_decoder"
-prores_raw_vulkan_hwaccel_deps="vulkan spirv_compiler"
+prores_raw_vulkan_hwaccel_deps="vulkan spirv_library"
prores_raw_vulkan_hwaccel_select="prores_raw_decoder"
-prores_vulkan_hwaccel_deps="vulkan spirv_compiler"
+prores_vulkan_hwaccel_deps="vulkan spirv_library"
prores_vulkan_hwaccel_select="prores_decoder"
vc1_d3d11va_hwaccel_deps="d3d11va"
vc1_d3d11va_hwaccel_select="vc1_decoder"
@@ -3990,19 +3990,19 @@ aresample_filter_deps="swresample"
asr_filter_deps="pocketsphinx"
ass_filter_deps="libass"
avgblur_opencl_filter_deps="opencl"
-avgblur_vulkan_filter_deps="vulkan spirv_compiler"
+avgblur_vulkan_filter_deps="vulkan spirv_library"
azmq_filter_deps="libzmq"
-blackdetect_vulkan_filter_deps="vulkan spirv_compiler"
+blackdetect_vulkan_filter_deps="vulkan spirv_library"
blackframe_filter_deps="gpl"
-blend_vulkan_filter_deps="vulkan spirv_compiler"
+blend_vulkan_filter_deps="vulkan spirv_library"
boxblur_filter_deps="gpl"
boxblur_opencl_filter_deps="opencl gpl"
bs2b_filter_deps="libbs2b"
bwdif_cuda_filter_deps="ffnvcodec"
bwdif_cuda_filter_deps_any="cuda_nvcc cuda_llvm"
-bwdif_vulkan_filter_deps="vulkan spirv_compiler"
-chromaber_vulkan_filter_deps="vulkan spirv_compiler"
-color_vulkan_filter_deps="vulkan spirv_compiler"
+bwdif_vulkan_filter_deps="vulkan spirv_library"
+chromaber_vulkan_filter_deps="vulkan spirv_library"
+color_vulkan_filter_deps="vulkan spirv_library"
colorkey_opencl_filter_deps="opencl"
colormatrix_filter_deps="gpl"
convolution_opencl_filter_deps="opencl"
@@ -4031,7 +4031,7 @@ elbg_filter_deps="avcodec"
eq_filter_deps="gpl"
erosion_opencl_filter_deps="opencl"
find_rect_filter_deps="avcodec avformat gpl"
-flip_vulkan_filter_deps="vulkan spirv_compiler"
+flip_vulkan_filter_deps="vulkan spirv_library"
flite_filter_deps="libflite threads"
framerate_filter_select="scene_sad"
freezedetect_filter_select="scene_sad"
@@ -4040,15 +4040,15 @@ frei0r_filter_deps="frei0r"
frei0r_src_filter_deps="frei0r"
fspp_filter_deps="gpl"
fsync_filter_deps="avformat"
-gblur_vulkan_filter_deps="vulkan spirv_compiler"
-hflip_vulkan_filter_deps="vulkan spirv_compiler"
+gblur_vulkan_filter_deps="vulkan spirv_library"
+hflip_vulkan_filter_deps="vulkan spirv_library"
histeq_filter_deps="gpl"
hqdn3d_filter_deps="gpl"
iccdetect_filter_deps="lcms2"
iccgen_filter_deps="lcms2"
identity_filter_select="scene_sad"
interlace_filter_deps="gpl"
-interlace_vulkan_filter_deps="vulkan spirv_compiler"
+interlace_vulkan_filter_deps="vulkan spirv_library"
kerndeint_filter_deps="gpl"
ladspa_filter_deps="ladspa libdl"
lcevc_filter_deps="liblcevc_dec"
@@ -4065,7 +4065,7 @@ mptestsrc_filter_deps="gpl"
msad_filter_select="scene_sad"
negate_filter_deps="lut_filter"
nlmeans_opencl_filter_deps="opencl"
-nlmeans_vulkan_filter_deps="vulkan spirv_compiler"
+nlmeans_vulkan_filter_deps="vulkan spirv_library"
nnedi_filter_deps="gpl"
ocr_filter_deps="libtesseract"
ocv_filter_deps="libopencv"
@@ -4077,7 +4077,7 @@ overlay_opencl_filter_deps="opencl"
overlay_qsv_filter_deps="libmfx"
overlay_qsv_filter_select="qsvvpp"
overlay_vaapi_filter_deps="vaapi VAProcPipelineCaps_blend_flags"
-overlay_vulkan_filter_deps="vulkan spirv_compiler"
+overlay_vulkan_filter_deps="vulkan spirv_library"
owdenoise_filter_deps="gpl"
pad_opencl_filter_deps="opencl"
pan_filter_deps="swresample"
@@ -4101,7 +4101,7 @@ vpp_amf_filter_deps="amf"
scale_qsv_filter_deps="libmfx"
scale_qsv_filter_select="qsvvpp"
scdet_filter_select="scene_sad"
-scdet_vulkan_filter_deps="vulkan spirv_compiler"
+scdet_vulkan_filter_deps="vulkan spirv_library"
select_filter_select="scene_sad"
sharpness_vaapi_filter_deps="vaapi"
showcqt_filter_deps="avformat swscale"
@@ -4127,11 +4127,11 @@ tonemap_opencl_filter_deps="opencl const_nan"
transpose_opencl_filter_deps="opencl"
transpose_vaapi_filter_deps="vaapi VAProcPipelineCaps_rotation_flags"
transpose_vt_filter_deps="videotoolbox VTPixelRotationSessionCreate"
-transpose_vulkan_filter_deps="vulkan spirv_compiler"
+transpose_vulkan_filter_deps="vulkan spirv_library"
unsharp_opencl_filter_deps="opencl"
uspp_filter_deps="gpl avcodec"
vaguedenoiser_filter_deps="gpl"
-vflip_vulkan_filter_deps="vulkan spirv_compiler"
+vflip_vulkan_filter_deps="vulkan spirv_library"
vidstabdetect_filter_deps="libvidstab"
vidstabtransform_filter_deps="libvidstab"
libvmaf_filter_deps="libvmaf"
@@ -4141,11 +4141,11 @@ zoompan_filter_deps="swscale"
zscale_filter_deps="libzimg const_nan"
scale_vaapi_filter_deps="vaapi"
scale_vt_filter_deps="videotoolbox VTPixelTransferSessionCreate"
-scale_vulkan_filter_deps="vulkan spirv_compiler"
+scale_vulkan_filter_deps="vulkan spirv_library"
vpp_qsv_filter_deps="libmfx"
vpp_qsv_filter_select="qsvvpp"
xfade_opencl_filter_deps="opencl"
-xfade_vulkan_filter_deps="vulkan spirv_compiler"
+xfade_vulkan_filter_deps="vulkan spirv_library"
yadif_cuda_filter_deps="ffnvcodec"
yadif_cuda_filter_deps_any="cuda_nvcc cuda_llvm"
yadif_videotoolbox_filter_deps="metal corevideo videotoolbox"
@@ -4194,11 +4194,11 @@ cws2fws_extralibs="zlib_extralibs"
# libraries, in any order
avcodec_deps="avutil"
-avcodec_suggest="libm stdatomic spirv_compiler"
+avcodec_suggest="libm stdatomic spirv_library"
avdevice_deps="avformat avcodec avutil"
avdevice_suggest="libm stdatomic"
avfilter_deps="avutil"
-avfilter_suggest="libm stdatomic spirv_compiler"
+avfilter_suggest="libm stdatomic spirv_library"
avformat_deps="avcodec avutil"
avformat_suggest="libm network zlib stdatomic"
avutil_suggest="clock_gettime ffnvcodec gcrypt libm libdrm libmfx opencl openssl user32 vaapi vulkan videotoolbox corefoundation corevideo coremedia bcrypt stdatomic"
@@ -6784,14 +6784,14 @@ if test -n "$custom_allocator"; then
add_extralibs "$custom_allocator_extralibs"
fi
-# Unlike other feature flags or libraries, spirv_compiler is not defined
+# Unlike other feature flags or libraries, spirv_library is not defined
# within any of our predefined categories of components.
# It gets defined if either libshaderc or libglslang check succeeds.
# As such, its in a state of neither being explicitly enabled, nor
# explicitly disabled, but even in this state, being mentioned in
# _deps results in it always passing.
# Disable it explicitly to fix this.
-disable spirv_compiler
+disable spirv_library
check_func_headers malloc.h _aligned_malloc && enable aligned_malloc
check_func ${malloc_prefix}memalign && enable memalign
@@ -7159,10 +7159,10 @@ enabled libharfbuzz && require_pkg_config libharfbuzz harfbuzz hb.h hb_buf
if enabled libglslang; then
spvremap="-lSPVRemapper"
require_headers "glslang/build_info.h" && { test_cpp_condition glslang/build_info.h "GLSLANG_VERSION_MAJOR >= 16" && spvremap="" ; }
- check_lib spirv_compiler glslang/Include/glslang_c_interface.h glslang_initialize_process \
+ check_lib spirv_library glslang/Include/glslang_c_interface.h glslang_initialize_process \
-lglslang -lMachineIndependent -lGenericCodeGen \
${spvremap} -lSPIRV -lSPIRV-Tools-opt -lSPIRV-Tools -lstdc++ $libm_extralibs $pthreads_extralibs ||
- require spirv_compiler glslang/Include/glslang_c_interface.h glslang_initialize_process \
+ require spirv_library glslang/Include/glslang_c_interface.h glslang_initialize_process \
-lglslang -lMachineIndependent -lOSDependent -lHLSL -lOGLCompiler -lGenericCodeGen \
${spvremap} -lSPIRV -lSPIRV-Tools-opt -lSPIRV-Tools -lstdc++ $libm_extralibs $pthreads_extralibs ;
fi
@@ -7254,7 +7254,7 @@ enabled librist && require_pkg_config librist "librist >= 0.2.7" libri
enabled librsvg && require_pkg_config librsvg librsvg-2.0 librsvg-2.0/librsvg/rsvg.h rsvg_handle_new_from_data
enabled librtmp && require_pkg_config librtmp librtmp librtmp/rtmp.h RTMP_Socket
enabled librubberband && require_pkg_config librubberband "rubberband >= 1.8.1" rubberband/rubberband-c.h rubberband_new -lstdc++ && append librubberband_extralibs "-lstdc++"
-enabled libshaderc && require_pkg_config spirv_compiler "shaderc >= 2019.1" shaderc/shaderc.h shaderc_compiler_initialize
+enabled libshaderc && require_pkg_config spirv_library "shaderc >= 2019.1" shaderc/shaderc.h shaderc_compiler_initialize
enabled libshine && require_pkg_config libshine shine shine/layer3.h shine_encode_buffer
enabled libsmbclient && { check_pkg_config libsmbclient smbclient libsmbclient.h smbc_init ||
require libsmbclient libsmbclient.h smbc_init -lsmbclient; }
@@ -7631,7 +7631,7 @@ elif enabled vulkan; then
fi
if disabled vulkan; then
- disable libglslang libshaderc spirv_compiler
+ disable libglslang libshaderc spirv_library
else
check_pkg_config_header_only vulkan_1_4 "vulkan >= 1.4.317" "vulkan/vulkan.h" "defined VK_VERSION_1_4" ||
check_cpp_condition vulkan_1_4 "vulkan/vulkan.h" "defined(VK_VERSION_1_5) || (defined(VK_VERSION_1_4) && VK_HEADER_VERSION >= 317)"
--
2.49.1
>From ecb79d449985042fe6102d3ab6cae4f6b323bb68 Mon Sep 17 00:00:00 2001
From: Lynne <dev@lynne.ee>
Date: Fri, 2 Jan 2026 10:13:12 +0100
Subject: [PATCH 04/12] configure/make: support compile-time SPIR-V generation
---
configure | 42 +++++++++++++++++++++++++++++++++++++++---
ffbuild/common.mak | 14 +++++++++++---
2 files changed, 50 insertions(+), 6 deletions(-)
diff --git a/configure b/configure
index 7b7fc0938f..f61e59b8df 100755
--- a/configure
+++ b/configure
@@ -237,7 +237,7 @@ External library support:
--enable-libfreetype enable libfreetype, needed for drawtext filter [no]
--enable-libfribidi enable libfribidi, improves drawtext filter [no]
--enable-libharfbuzz enable libharfbuzz, needed for drawtext filter [no]
- --enable-libglslang enable GLSL->SPIRV compilation via libglslang [no]
+ --enable-libglslang enable runtime GLSL->SPIRV compilation via libglslang [no]
--enable-libgme enable Game Music Emu via libgme [no]
--enable-libgsm enable GSM de/encoding via libgsm [no]
--enable-libiec61883 enable iec61883 via libiec61883 [no]
@@ -272,7 +272,7 @@ External library support:
--enable-librsvg enable SVG rasterization via librsvg [no]
--enable-librubberband enable rubberband needed for rubberband filter [no]
--enable-librtmp enable RTMP[E] support via librtmp [no]
- --enable-libshaderc enable GLSL->SPIRV compilation via libshaderc [no]
+ --enable-libshaderc enable runtime GLSL->SPIRV compilation via libshaderc [no]
--enable-libshine enable fixed-point MP3 encoding via libshine [no]
--enable-libsmbclient enable Samba protocol via libsmbclient [no]
--enable-libsnappy enable Snappy compression, needed for hap encoding [no]
@@ -407,6 +407,7 @@ Toolchain options:
--dep-cc=DEPCC use dependency generator DEPCC [$cc_default]
--nvcc=NVCC use Nvidia CUDA compiler NVCC or clang [$nvcc_default]
--ld=LD use linker LD [$ld_default]
+ --glslc=GLSLC use GLSL compiler GLSLC [$glslc_default]
--metalcc=METALCC use metal compiler METALCC [$metalcc_default]
--metallib=METALLIB use metal linker METALLIB [$metallib_default]
--pkg-config=PKGCONFIG use pkg-config tool PKGCONFIG [$pkg_config_default]
@@ -429,6 +430,7 @@ Toolchain options:
--extra-libs=ELIBS add ELIBS [$ELIBS]
--extra-version=STRING version string suffix []
--optflags=OPTFLAGS override optimization-related compiler flags
+ --glslcflags=GLSLCFLAGS override glslc flags [$glslcflags_default]
--nvccflags=NVCCFLAGS override nvcc flags [$nvccflags_default]
--build-suffix=SUFFIX library name suffix []
--enable-pic build position-independent code
@@ -1072,6 +1074,10 @@ hostcc_o(){
eval printf '%s\\n' $HOSTCC_O
}
+glslc_o(){
+ eval printf '%s\\n' $GLSLC_O
+}
+
nvcc_o(){
eval printf '%s\\n' $NVCC_O
}
@@ -1097,6 +1103,25 @@ test_objcc(){
test_cmd $objcc -Werror=missing-prototypes $CPPFLAGS $CFLAGS $OBJCFLAGS "$@" $OBJCC_C $(cc_o $TMPO) $TMPM
}
+test_glslc(){
+ log test_glslc "$@"
+ cat > $TMPGLSL
+ log_file $TMPGLSL
+ test_cmd $glslc $glslcflags "$@" $(glslc_o $TMPO) $TMPGLSL
+}
+
+check_glslc(){
+ log check_glslc "$@"
+ name=$1
+ shift 1
+ disabled $name && return
+ disable $name
+ test_glslc "$@" <<EOF && enable $name
+#version 460
+void main(void) {}
+EOF
+}
+
test_nvcc(){
log test_nvcc "$@"
cat > $TMPCU
@@ -2777,6 +2802,8 @@ CMDLINE_SET="
ln_s
logfile
malloc_prefix
+ glslc
+ glslcflags
metalcc
metallib
nm
@@ -4254,6 +4281,8 @@ host_cc_default="gcc"
doxygen_default="doxygen"
install="install"
ln_s_default="ln -s -f"
+glslc_default="glslang"
+glslcflags_default="-V100 --target-env spirv1.6 -R -Os"
metalcc_default="xcrun -sdk macosx metal"
metallib_default="xcrun -sdk macosx metallib"
nm_default="nm -g"
@@ -4356,6 +4385,7 @@ HOSTCC_C='-c'
HOSTCC_E='-E -o $@'
HOSTCC_O='-o $@'
HOSTLD_O='-o $@'
+GLSLC_O='-o $@'
NVCC_C='-c'
NVCC_O='-o $@'
@@ -4888,7 +4918,7 @@ if enabled cuda_nvcc; then
fi
set_default arch cc cxx doxygen pkg_config ranlib strip sysinclude \
- target_exec x86asmexe metalcc metallib stdc stdcxx
+ target_exec x86asmexe glslc glslcflags metalcc metallib stdc stdcxx
enabled cross_compile || host_cc_default=$cc
set_default host_cc
@@ -4960,6 +4990,7 @@ tmpfile TMPE $EXESUF
tmpfile TMPH .h
tmpfile TMPM .m
tmpfile TMPCU .cu
+tmpfile TMPGLSL .comp.glsl
tmpfile TMPO .o
tmpfile TMPS .S
tmpfile TMPSH .sh
@@ -7630,6 +7661,8 @@ elif enabled vulkan; then
check_cpp_condition vulkan "vulkan/vulkan.h" "defined(VK_VERSION_1_4) || (defined(VK_VERSION_1_3) && VK_HEADER_VERSION >= 277)"
fi
+enabled vulkan && check_glslc vulkan
+
if disabled vulkan; then
disable libglslang libshaderc spirv_library
else
@@ -8383,6 +8416,7 @@ RESPONSE_FILES=$response_files
AR_O=$ar_o
AR_CMD=$ar
NM_CMD=$nm
+GLSLC=$glslc
METALCC=$metalcc
METALLIB=$metallib
RANLIB=$ranlib
@@ -8396,6 +8430,7 @@ CFLAGS=$CFLAGS
CXXFLAGS=$CXXFLAGS
OBJCFLAGS=$OBJCFLAGS
ASFLAGS=$ASFLAGS
+GLSLCFLAGS=$glslcflags
NVCCFLAGS=$nvccflags
AS_C=$AS_C
AS_O=$AS_O
@@ -8407,6 +8442,7 @@ CC_E=$CC_E
CC_O=$CC_O
CXX_C=$CXX_C
CXX_O=$CXX_O
+GLSLC_O=$GLSLC_O
NVCC_C=$NVCC_C
NVCC_O=$NVCC_O
LD_O=$LD_O
diff --git a/ffbuild/common.mak b/ffbuild/common.mak
index 89c0c413e1..6a37a606e4 100644
--- a/ffbuild/common.mak
+++ b/ffbuild/common.mak
@@ -27,7 +27,7 @@ BIN2C = $(BIN2CEXE)
ifndef V
Q = @
ECHO = printf "$(1)\t%s\n" $(2)
-BRIEF = CC CXX OBJCC HOSTCC HOSTLD AS X86ASM AR LD LDXX STRIP CP WINDRES NVCC BIN2C METALCC METALLIB
+BRIEF = CC CXX OBJCC HOSTCC HOSTLD AS X86ASM AR LD LDXX STRIP CP WINDRES GLSLC NVCC BIN2C METALCC METALLIB
SILENT = DEPCC DEPCXX DEPHOSTCC DEPAS DEPX86ASM RANLIB RM
MSG = $@
@@ -68,6 +68,7 @@ COMPILE_S = $(call COMPILE,AS)
COMPILE_M = $(call COMPILE,OBJCC)
COMPILE_X86ASM = $(call COMPILE,X86ASM)
COMPILE_HOSTC = $(call COMPILE,HOSTCC)
+COMPILE_GLSLC = $(call COMPILE,GLSLC)
COMPILE_NVCC = $(call COMPILE,NVCC)
COMPILE_MMI = $(call COMPILE,CC,MMIFLAGS)
COMPILE_MSA = $(call COMPILE,CC,MSAFLAGS)
@@ -130,6 +131,12 @@ RUN_MINIFY = $(M)sed 's!/\\*.*\\*/!!g' $< | tr '\n' ' ' | tr -s ' ' | sed 's/^ /
%.gz: TAG = GZIP
%.min: TAG = MINIFY
+%.spv: %.glsl
+ $(COMPILE_GLSLC)
+
+%.spv.c: %.spv $(BIN2CEXE)
+ $(RUN_BIN2C)
+
%.metal.air: %.metal
$(METALCC) $< -o $@
@@ -228,10 +235,11 @@ ALLHEADERS := $(subst $(SRC_DIR)/,$(SUBDIR),$(wildcard $(SRC_DIR)/*.h $(SRC_DIR)
SKIPHEADERS += $(ARCH_HEADERS:%=$(ARCH)/%) $(SKIPHEADERS-)
SKIPHEADERS := $(SKIPHEADERS:%=$(SUBDIR)%)
HOBJS = $(filter-out $(SKIPHEADERS:.h=.h.o),$(ALLHEADERS:.h=.h.o))
+SPVOBJS = $(filter %.spv.o,$(OBJS))
PTXOBJS = $(filter %.ptx.o,$(OBJS))
$(HOBJS): CCFLAGS += $(CFLAGS_HEADERS)
checkheaders: $(HOBJS)
-.SECONDARY: $(HOBJS:.o=.c) $(PTXOBJS:.o=.c) $(PTXOBJS:.o=.gz) $(PTXOBJS:.o=)
+.SECONDARY: $(HOBJS:.o=.c) $(SPVOBJS:.o=.c) $(SPVOBJS:.o=) $(PTXOBJS:.o=.c) $(PTXOBJS:.o=.gz) $(PTXOBJS:.o=)
alltools: $(TOOLS)
$(HOSTOBJS): %.o: %.c
@@ -250,7 +258,7 @@ $(TOOLOBJS): | tools
OUTDIRS := $(OUTDIRS) $(dir $(OBJS) $(HOBJS) $(HOSTOBJS) $(SHLIBOBJS) $(STLIBOBJS) $(TESTOBJS))
-CLEANSUFFIXES = *.d *.gcda *.gcno *.h.c *.ho *.map *.o *.objs *.pc *.ptx *.ptx.gz *.ptx.c *.ver *.version *.html.gz *.html.c *.css.min.gz *.css.min *.css.c *$(DEFAULT_X86ASMD).asm *~ *.ilk *.pdb
+CLEANSUFFIXES = *.d *.gcda *.gcno *.h.c *.ho *.map *.o *.objs *.pc *.ptx *.ptx.gz *.ptx.c *.spv *.spv.c *.ver *.version *.html.gz *.html.c *.css.min.gz *.css.min *.css.c *$(DEFAULT_X86ASMD).asm *~ *.ilk *.pdb
LIBSUFFIXES = *.a *.lib *.so *.so.* *.dylib *.dll *.def *.dll.a
define RULES
--
2.49.1
>From 2dff147c646352ef3cc5b2e337813197ceb9cb03 Mon Sep 17 00:00:00 2001
From: Lynne <dev@lynne.ee>
Date: Fri, 2 Jan 2026 04:26:36 +0100
Subject: [PATCH 05/12] vulkan: add support for precompiled shaders
---
libavutil/vulkan.c | 69 +++++++++++++++++++++++++++++++++++++---------
libavutil/vulkan.h | 17 ++++++++++--
2 files changed, 71 insertions(+), 15 deletions(-)
diff --git a/libavutil/vulkan.c b/libavutil/vulkan.c
index 85501c5bbd..b3f15daf8c 100644
--- a/libavutil/vulkan.c
+++ b/libavutil/vulkan.c
@@ -2078,19 +2078,14 @@ void ff_vk_frame_barrier(FFVulkanContext *s, FFVkExecContext *e,
ff_vk_exec_update_frame(s, e, pic, &bar[*nb_bar - nb_images], NULL);
}
-int ff_vk_shader_init(FFVulkanContext *s, FFVulkanShader *shd, const char *name,
- VkPipelineStageFlags stage,
- const char *extensions[], int nb_extensions,
- int lg_x, int lg_y, int lg_z,
- uint32_t required_subgroup_size)
+int ff_vk_shader_load(FFVulkanShader *shd,
+ VkPipelineStageFlags stage, VkSpecializationInfo *spec,
+ uint32_t wg_size[3], uint32_t required_subgroup_size)
{
- av_bprint_init(&shd->src, 0, AV_BPRINT_SIZE_UNLIMITED);
-
- shd->name = name;
shd->stage = stage;
- shd->lg_size[0] = lg_x;
- shd->lg_size[1] = lg_y;
- shd->lg_size[2] = lg_z;
+ shd->precompiled = 1;
+ shd->specialization_info = spec;
+ memcpy(shd->lg_size, wg_size, 3*sizeof(uint32_t));
switch (shd->stage) {
case VK_SHADER_STAGE_ANY_HIT_BIT_KHR:
@@ -2109,6 +2104,22 @@ int ff_vk_shader_init(FFVulkanContext *s, FFVulkanShader *shd, const char *name,
break;
};
+ return 0;
+}
+
+int ff_vk_shader_init(FFVulkanContext *s, FFVulkanShader *shd, const char *name,
+ VkPipelineStageFlags stage,
+ const char *extensions[], int nb_extensions,
+ int lg_x, int lg_y, int lg_z,
+ uint32_t required_subgroup_size)
+{
+ ff_vk_shader_load(shd, stage, NULL,
+ (uint32_t []) { lg_x, lg_y, lg_z }, required_subgroup_size);
+
+ shd->name = name;
+ shd->precompiled = 0;
+ av_bprint_init(&shd->src, 0, AV_BPRINT_SIZE_UNLIMITED);
+
if (required_subgroup_size) {
shd->subgroup_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_REQUIRED_SUBGROUP_SIZE_CREATE_INFO;
shd->subgroup_info.requiredSubgroupSize = required_subgroup_size;
@@ -2254,6 +2265,7 @@ static int init_compute_pipeline(FFVulkanContext *s, FFVulkanShader *shd,
VK_PIPELINE_SHADER_STAGE_CREATE_REQUIRE_FULL_SUBGROUPS_BIT : 0x0,
.stage = shd->stage,
.module = mod,
+ .pSpecializationInfo = shd->specialization_info,
},
};
@@ -2291,7 +2303,7 @@ static int create_shader_object(FFVulkanContext *s, FFVulkanShader *shd,
.setLayoutCount = shd->nb_descriptor_sets,
.pushConstantRangeCount = shd->push_consts_num,
.pPushConstantRanges = shd->push_consts,
- .pSpecializationInfo = NULL,
+ .pSpecializationInfo = shd->specialization_info,
};
ret = vk->CreateShadersEXT(s->hwctx->act_dev, 1, &shader_obj_create,
@@ -2371,11 +2383,39 @@ static int init_descriptors(FFVulkanContext *s, FFVulkanShader *shd)
}
int ff_vk_shader_link(FFVulkanContext *s, FFVulkanShader *shd,
- uint8_t *spirv, size_t spirv_len,
+ const char *spirv, size_t spirv_len,
const char *entrypoint)
{
int err;
FFVulkanFunctions *vk = &s->vkfn;
+ VkSpecializationMapEntry spec_entries[3];
+ VkSpecializationInfo spec_info;
+
+ if (shd->precompiled) {
+ if (!shd->specialization_info) {
+ spec_info = (VkSpecializationInfo) {
+ .pMapEntries = spec_entries,
+ .mapEntryCount = 0,
+ .pData = shd->lg_size,
+ .dataSize = 0,
+ };
+ shd->specialization_info = &spec_info;
+ }
+
+ VkSpecializationMapEntry *spe = (void *)shd->specialization_info->pMapEntries;
+ for (int i = 0; i < 3; i++) {
+ spe[shd->specialization_info->mapEntryCount++] = (VkSpecializationMapEntry) {
+ .constantID = i,
+ .offset = shd->specialization_info->dataSize + i*sizeof(uint32_t),
+ .size = sizeof(uint32_t),
+ };
+ }
+
+ uint8_t *spd = (uint8_t *)shd->specialization_info->pData;
+ memcpy(&spd[shd->specialization_info->dataSize],
+ shd->lg_size, 3*sizeof(uint32_t));
+ shd->specialization_info->dataSize += 3*sizeof(uint32_t);
+ }
err = init_descriptors(s, shd);
if (err < 0)
@@ -2488,6 +2528,9 @@ int ff_vk_shader_add_descriptor_set(FFVulkanContext *s, FFVulkanShader *shd,
set->singular = singular;
set->nb_bindings = nb;
+ if (shd->precompiled)
+ return 0;
+
print:
/* Write shader info */
for (int i = 0; i < nb; i++) {
diff --git a/libavutil/vulkan.h b/libavutil/vulkan.h
index 7c513fb8e2..a73517fa58 100644
--- a/libavutil/vulkan.h
+++ b/libavutil/vulkan.h
@@ -194,11 +194,15 @@ typedef struct FFVulkanShader {
/* Name for id/debugging purposes */
const char *name;
+ /* Whether shader is precompiled or not */
+ int precompiled;
+ VkSpecializationInfo *specialization_info;
+
/* Shader text */
AVBPrint src;
/* Compute shader local group sizes */
- int lg_size[3];
+ uint32_t lg_size[3];
/* Shader bind point/type */
VkPipelineStageFlags stage;
@@ -608,6 +612,15 @@ int ff_vk_shader_init(FFVulkanContext *s, FFVulkanShader *shd, const char *name,
int lg_x, int lg_y, int lg_z,
uint32_t required_subgroup_size);
+/**
+ * Initialize a shader object.
+ * The workgroup size must have local_size_XYZ_id of 0, 1, 2.
+ * If VkSpecializationInfo exists, it must have at least 3x4 byte entry left.
+ */
+int ff_vk_shader_load(FFVulkanShader *shd,
+ VkPipelineStageFlags stage, VkSpecializationInfo *spec,
+ uint32_t wg_size[3], uint32_t required_subgroup_size);
+
/**
* Output the shader code as logging data, with a specific
* priority.
@@ -618,7 +631,7 @@ void ff_vk_shader_print(void *ctx, FFVulkanShader *shd, int prio);
* Link a shader into an executable.
*/
int ff_vk_shader_link(FFVulkanContext *s, FFVulkanShader *shd,
- uint8_t *spirv, size_t spirv_len,
+ const char *spirv, size_t spirv_len,
const char *entrypoint);
/**
--
2.49.1
>From a57024c4e84fae3ffe21f3e7680ffe4c06331185 Mon Sep 17 00:00:00 2001
From: Lynne <dev@lynne.ee>
Date: Fri, 2 Jan 2026 06:55:50 +0100
Subject: [PATCH 06/12] configure: rename PTX_COMPRESSION to SHADER_COMPRESSION
Its useful for GLSL and Metal as well.
---
configure | 8 ++++----
ffbuild/common.mak | 2 +-
libavfilter/cuda/load_helper.c | 4 ++--
3 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/configure b/configure
index f61e59b8df..e2c4047a8c 100755
--- a/configure
+++ b/configure
@@ -531,7 +531,7 @@ Developer options (useful when working on FFmpeg itself):
--enable-linux-perf enable Linux Performance Monitor API
--enable-macos-kperf enable macOS kperf (private) API
--disable-large-tests disable tests that use a large amount of memory
- --disable-ptx-compression don't compress CUDA PTX code even when possible
+ --disable-shader-compression don't compress shader code even when possible
--disable-resource-compression don't compress resources even when possible
--disable-version-tracking don't include the git/release version in the build
@@ -2192,7 +2192,7 @@ CONFIG_LIST="
neon_clobber_test
ossfuzz
pic
- ptx_compression
+ shader_compression
resource_compression
thumb
valgrind_backtrace
@@ -4328,7 +4328,7 @@ enable faan faandct faanidct
enable iamf
enable large_tests
enable optimizations
-enable ptx_compression
+enable shader_compression
enable resource_compression
enable runtime_cpudetect
enable safe_bitstream_reader
@@ -7120,7 +7120,7 @@ EOF
[ -x "$(command -v gzip)" ] && enable gzip
-enabled zlib_gzip && enabled gzip || disable ptx_compression
+enabled zlib_gzip && enabled gzip || disable shader_compression
enabled zlib_gzip && enabled gzip || disable resource_compression
diff --git a/ffbuild/common.mak b/ffbuild/common.mak
index 6a37a606e4..c9918a9101 100644
--- a/ffbuild/common.mak
+++ b/ffbuild/common.mak
@@ -149,7 +149,7 @@ RUN_MINIFY = $(M)sed 's!/\\*.*\\*/!!g' $< | tr '\n' ' ' | tr -s ' ' | sed 's/^ /
%.ptx: %.cu $(SRC_PATH)/compat/cuda/cuda_runtime.h
$(COMPILE_NVCC)
-ifdef CONFIG_PTX_COMPRESSION
+ifdef CONFIG_SHADER_COMPRESSION
%.ptx.gz: %.ptx
$(RUN_GZIP)
diff --git a/libavfilter/cuda/load_helper.c b/libavfilter/cuda/load_helper.c
index b049ec7130..115523d642 100644
--- a/libavfilter/cuda/load_helper.c
+++ b/libavfilter/cuda/load_helper.c
@@ -23,7 +23,7 @@
#include "libavutil/cuda_check.h"
#include "libavutil/mem.h"
-#if CONFIG_PTX_COMPRESSION
+#if CONFIG_SHADER_COMPRESSION
#include <zlib.h>
#define CHUNK_SIZE 1024 * 64
#endif
@@ -37,7 +37,7 @@ int ff_cuda_load_module(void *avctx, AVCUDADeviceContext *hwctx, CUmodule *cu_mo
{
CudaFunctions *cu = hwctx->internal->cuda_dl;
-#if CONFIG_PTX_COMPRESSION
+#if CONFIG_SHADER_COMPRESSION
z_stream stream = { 0 };
uint8_t *buf, *tmp;
uint64_t buf_size;
--
2.49.1
>From da75cbc0bc96e9d4641a6d849aa2a28d477754ba Mon Sep 17 00:00:00 2001
From: Lynne <dev@lynne.ee>
Date: Fri, 2 Jan 2026 10:37:12 +0100
Subject: [PATCH 07/12] cuda/load_helper: move zlib decompression into a
separate file
Allows it to be reused for Vulkan
---
libavfilter/cuda/load_helper.c | 60 ++++--------------------
libavutil/Makefile | 1 +
libavutil/zlib_utils.h | 83 ++++++++++++++++++++++++++++++++++
3 files changed, 92 insertions(+), 52 deletions(-)
create mode 100644 libavutil/zlib_utils.h
diff --git a/libavfilter/cuda/load_helper.c b/libavfilter/cuda/load_helper.c
index 115523d642..ae8adcfeb7 100644
--- a/libavfilter/cuda/load_helper.c
+++ b/libavfilter/cuda/load_helper.c
@@ -24,8 +24,7 @@
#include "libavutil/mem.h"
#if CONFIG_SHADER_COMPRESSION
-#include <zlib.h>
-#define CHUNK_SIZE 1024 * 64
+#include "libavutil/zlib_utils.h"
#endif
#include "load_helper.h"
@@ -38,58 +37,15 @@ int ff_cuda_load_module(void *avctx, AVCUDADeviceContext *hwctx, CUmodule *cu_mo
CudaFunctions *cu = hwctx->internal->cuda_dl;
#if CONFIG_SHADER_COMPRESSION
- z_stream stream = { 0 };
- uint8_t *buf, *tmp;
- uint64_t buf_size;
- int ret;
-
- if (inflateInit2(&stream, 32 + 15) != Z_OK) {
- av_log(avctx, AV_LOG_ERROR, "Error during zlib initialisation: %s\n", stream.msg);
- return AVERROR(ENOSYS);
- }
-
- buf_size = CHUNK_SIZE * 4;
- buf = av_realloc(NULL, buf_size);
- if (!buf) {
- inflateEnd(&stream);
- return AVERROR(ENOMEM);
- }
-
- stream.next_in = data;
- stream.avail_in = length;
-
- do {
- stream.avail_out = buf_size - stream.total_out;
- stream.next_out = buf + stream.total_out;
-
- ret = inflate(&stream, Z_FINISH);
- if (ret != Z_OK && ret != Z_STREAM_END && ret != Z_BUF_ERROR) {
- av_log(avctx, AV_LOG_ERROR, "zlib inflate error(%d): %s\n", ret, stream.msg);
- inflateEnd(&stream);
- av_free(buf);
- return AVERROR(EINVAL);
- }
-
- if (stream.avail_out == 0) {
- buf_size += CHUNK_SIZE;
- tmp = av_realloc(buf, buf_size);
- if (!tmp) {
- inflateEnd(&stream);
- av_free(buf);
- return AVERROR(ENOMEM);
- }
- buf = tmp;
- }
- } while (ret != Z_STREAM_END);
-
- // NULL-terminate string
- // there is guaranteed to be space for this, due to condition in loop
- buf[stream.total_out] = 0;
-
- inflateEnd(&stream);
+ uint8_t *out;
+ size_t out_len;
+ int ret = ff_zlib_expand(avctx, &out, &out_len,
+ data, length);
+ if (ret < 0)
+ return ret;
ret = CHECK_CU(cu->cuModuleLoadData(cu_module, buf));
- av_free(buf);
+ av_free(out);
return ret;
#else
return CHECK_CU(cu->cuModuleLoadData(cu_module, data));
diff --git a/libavutil/Makefile b/libavutil/Makefile
index ee77e51c08..2e0e12c08b 100644
--- a/libavutil/Makefile
+++ b/libavutil/Makefile
@@ -234,6 +234,7 @@ STLIBOBJS-$(CONFIG_SWSCALE) += half2float.o
SHLIBOBJS-$(HAVE_GNU_WINDRES) += avutilres.o
SKIPHEADERS += objc.h
+SKIPHEADERS-$(CONFIG_ZLIB) += zlib_utils.h
SKIPHEADERS-$(HAVE_CUDA_H) += hwcontext_cuda.h
SKIPHEADERS-$(CONFIG_CUDA) += hwcontext_cuda_internal.h \
cuda_check.h
diff --git a/libavutil/zlib_utils.h b/libavutil/zlib_utils.h
new file mode 100644
index 0000000000..a00d5d85ed
--- /dev/null
+++ b/libavutil/zlib_utils.h
@@ -0,0 +1,83 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVUTIL_ZLIB_UTILS_H
+#define AVUTIL_ZLIB_UTILS_H
+
+#include <zlib.h>
+#define CHUNK_SIZE 1024 * 64
+
+static int ff_zlib_expand(void *ctx, uint8_t **out, size_t *out_len,
+ const uint8_t *src, int src_len)
+{
+ int ret;
+
+ z_stream stream = { 0 };
+ if (inflateInit2(&stream, 32 + 15) != Z_OK) {
+ av_log(ctx, AV_LOG_ERROR, "Error during zlib initialisation: %s\n",
+ stream.msg);
+ return AVERROR(ENOSYS);
+ }
+
+ uint64_t buf_size = CHUNK_SIZE * 4;
+ uint8_t *buf = av_realloc(NULL, buf_size);
+ if (!buf) {
+ inflateEnd(&stream);
+ return AVERROR(ENOMEM);
+ }
+
+ stream.next_in = src;
+ stream.avail_in = src_len;
+
+ do {
+ stream.avail_out = buf_size - stream.total_out;
+ stream.next_out = buf + stream.total_out;
+
+ ret = inflate(&stream, Z_FINISH);
+ if (ret != Z_OK && ret != Z_STREAM_END && ret != Z_BUF_ERROR) {
+ av_log(ctx, AV_LOG_ERROR, "zlib inflate error(%d): %s\n",
+ ret, stream.msg);
+ inflateEnd(&stream);
+ av_free(buf);
+ return AVERROR(EINVAL);
+ }
+
+ if (stream.avail_out == 0) {
+ buf_size += CHUNK_SIZE;
+ uint8_t *tmp = av_realloc(buf, buf_size);
+ if (!tmp) {
+ inflateEnd(&stream);
+ av_free(buf);
+ return AVERROR(ENOMEM);
+ }
+ buf = tmp;
+ }
+ } while (ret != Z_STREAM_END);
+
+ // NULL-terminate string
+ // there is guaranteed to be space for this, due to condition in loop
+ buf[stream.total_out] = 0;
+
+ inflateEnd(&stream);
+
+ *out = buf;
+ *out_len = stream.total_out;
+
+ return 0;
+}
+#endif /* AVUTIL_ZLIB_UTILS_H */
--
2.49.1
>From 46302e2a1d6bd1e8200992a6473a687e47d3d369 Mon Sep 17 00:00:00 2001
From: Lynne <dev@lynne.ee>
Date: Fri, 2 Jan 2026 10:37:52 +0100
Subject: [PATCH 08/12] configure: allow shader compression for Vulkan
14KiB -> 4KiB bwdif shader. Saves binary space.
---
ffbuild/common.mak | 8 ++++++++
libavutil/vulkan.c | 29 ++++++++++++++++++++++++-----
2 files changed, 32 insertions(+), 5 deletions(-)
diff --git a/ffbuild/common.mak b/ffbuild/common.mak
index c9918a9101..5a46f08b90 100644
--- a/ffbuild/common.mak
+++ b/ffbuild/common.mak
@@ -134,8 +134,16 @@ RUN_MINIFY = $(M)sed 's!/\\*.*\\*/!!g' $< | tr '\n' ' ' | tr -s ' ' | sed 's/^ /
%.spv: %.glsl
$(COMPILE_GLSLC)
+ifdef CONFIG_SHADER_COMPRESSION
+%.spv.gz: %.spv
+ $(RUN_GZIP)
+
+%.spv.c: %.spv.gz $(BIN2CEXE)
+ $(RUN_BIN2C)
+else
%.spv.c: %.spv $(BIN2CEXE)
$(RUN_BIN2C)
+endif
%.metal.air: %.metal
$(METALCC) $< -o $@
diff --git a/libavutil/vulkan.c b/libavutil/vulkan.c
index b3f15daf8c..bb0f2c9670 100644
--- a/libavutil/vulkan.c
+++ b/libavutil/vulkan.c
@@ -18,12 +18,17 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include "config.h"
#include "avassert.h"
#include "mem.h"
#include "vulkan.h"
#include "libavutil/vulkan_loader.h"
+#if CONFIG_SHADER_COMPRESSION
+#include "libavutil/zlib_utils.h"
+#endif
+
const VkComponentMapping ff_comp_identity_map = {
.r = VK_COMPONENT_SWIZZLE_IDENTITY,
.g = VK_COMPONENT_SWIZZLE_IDENTITY,
@@ -2415,15 +2420,25 @@ int ff_vk_shader_link(FFVulkanContext *s, FFVulkanShader *shd,
memcpy(&spd[shd->specialization_info->dataSize],
shd->lg_size, 3*sizeof(uint32_t));
shd->specialization_info->dataSize += 3*sizeof(uint32_t);
+
+#if CONFIG_SHADER_COMPRESSION
+ uint8_t *out;
+ size_t out_len;
+ int ret = ff_zlib_expand(s, &out, &out_len, spirv, spirv_len);
+ if (ret < 0)
+ return ret;
+ spirv = out;
+ spirv_len = out_len;
+#endif
}
err = init_descriptors(s, shd);
if (err < 0)
- return err;
+ goto end;
err = init_pipeline_layout(s, shd);
if (err < 0)
- return err;
+ goto end;
if (s->extensions & FF_VK_EXT_DESCRIPTOR_BUFFER) {
for (int i = 0; i < shd->nb_descriptor_sets; i++)
@@ -2432,13 +2447,11 @@ int ff_vk_shader_link(FFVulkanContext *s, FFVulkanShader *shd,
if (s->extensions & FF_VK_EXT_SHADER_OBJECT) {
err = create_shader_object(s, shd, spirv, spirv_len, entrypoint);
- if (err < 0)
- return err;
} else {
VkShaderModule mod;
err = create_shader_module(s, shd, &mod, spirv, spirv_len);
if (err < 0)
- return err;
+ goto end;
switch (shd->bind_point) {
case VK_PIPELINE_BIND_POINT_COMPUTE:
@@ -2456,6 +2469,12 @@ int ff_vk_shader_link(FFVulkanContext *s, FFVulkanShader *shd,
return err;
}
+end:
+
+#if CONFIG_SHADER_COMPRESSION
+ if (shd->precompiled)
+ av_free((void *)spirv);
+#endif
return 0;
}
--
2.49.1
>From a96daa85c5092527216e312fc145996fdd93eec5 Mon Sep 17 00:00:00 2001
From: Lynne <dev@lynne.ee>
Date: Fri, 2 Jan 2026 10:00:10 +0100
Subject: [PATCH 09/12] bwdif_vulkan: use compile-time SPIR-V
---
configure | 2 +-
libavfilter/vf_bwdif_vulkan.c | 97 ++-----------------
libavfilter/vulkan/Makefile | 2 +-
.../vulkan/{bwdif.comp => bwdif.comp.glsl} | 47 ++++++++-
4 files changed, 54 insertions(+), 94 deletions(-)
rename libavfilter/vulkan/{bwdif.comp => bwdif.comp.glsl} (76%)
diff --git a/configure b/configure
index e2c4047a8c..c4a66c9a12 100755
--- a/configure
+++ b/configure
@@ -4027,7 +4027,7 @@ boxblur_opencl_filter_deps="opencl gpl"
bs2b_filter_deps="libbs2b"
bwdif_cuda_filter_deps="ffnvcodec"
bwdif_cuda_filter_deps_any="cuda_nvcc cuda_llvm"
-bwdif_vulkan_filter_deps="vulkan spirv_library"
+bwdif_vulkan_filter_deps="vulkan"
chromaber_vulkan_filter_deps="vulkan spirv_library"
color_vulkan_filter_deps="vulkan spirv_library"
colorkey_opencl_filter_deps="opencl"
diff --git a/libavfilter/vf_bwdif_vulkan.c b/libavfilter/vf_bwdif_vulkan.c
index 549e814886..c6fb6abe9c 100644
--- a/libavfilter/vf_bwdif_vulkan.c
+++ b/libavfilter/vf_bwdif_vulkan.c
@@ -22,7 +22,6 @@
#include "libavutil/random_seed.h"
#include "libavutil/opt.h"
-#include "libavutil/vulkan_spirv.h"
#include "vulkan_filter.h"
#include "yadif.h"
#include "filters.h"
@@ -43,27 +42,17 @@ typedef struct BWDIFParameters {
int current_field;
} BWDIFParameters;
-extern const char *ff_source_bwdif_comp;
+extern const unsigned char ff_bwdif_comp_spv_data[];
+extern const unsigned int ff_bwdif_comp_spv_len;
static av_cold int init_filter(AVFilterContext *ctx)
{
int err;
- uint8_t *spv_data;
- size_t spv_len;
- void *spv_opaque = NULL;
BWDIFVulkanContext *s = ctx->priv;
FFVulkanContext *vkctx = &s->vkctx;
const int planes = av_pix_fmt_count_planes(s->vkctx.output_format);
- FFVulkanShader *shd;
- FFVkSPIRVCompiler *spv;
FFVulkanDescriptorSetBinding *desc;
- 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");
@@ -73,119 +62,49 @@ 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, "bwdif",
- VK_SHADER_STAGE_COMPUTE_BIT,
- NULL, 0,
- 1, 64, 1,
- 0));
- shd = &s->shd;
+ ff_vk_shader_load(&s->shd, VK_SHADER_STAGE_COMPUTE_BIT, NULL,
+ (uint32_t [3]) { 1, 64, planes }, 0);
desc = (FFVulkanDescriptorSetBinding []) {
{
.name = "prev",
.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 = planes,
.stages = VK_SHADER_STAGE_COMPUTE_BIT,
},
{
.name = "cur",
.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 = planes,
.stages = VK_SHADER_STAGE_COMPUTE_BIT,
},
{
.name = "next",
.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 = planes,
.stages = VK_SHADER_STAGE_COMPUTE_BIT,
},
{
.name = "dst",
.type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
- .mem_layout = ff_vk_shader_rep_fmt(s->vkctx.output_format, FF_VK_REP_FLOAT),
- .mem_quali = "writeonly",
- .dimensions = 2,
.elems = planes,
.stages = VK_SHADER_STAGE_COMPUTE_BIT,
},
};
- RET(ff_vk_shader_add_descriptor_set(vkctx, &s->shd, desc, 4, 0, 0));
-
- GLSLC(0, layout(push_constant, std430) uniform pushConstants { );
- GLSLC(1, int parity; );
- GLSLC(1, int tff; );
- GLSLC(1, int current_field; );
- GLSLC(0, }; );
+ ff_vk_shader_add_descriptor_set(vkctx, &s->shd, desc, 4, 0, 0);
ff_vk_shader_add_push_const(&s->shd, 0, sizeof(BWDIFParameters),
VK_SHADER_STAGE_COMPUTE_BIT);
- GLSLD(ff_source_bwdif_comp );
- GLSLC(0, void main() );
- GLSLC(0, { );
- GLSLC(1, ivec2 size; );
- GLSLC(1, const ivec2 pos = ivec2(gl_GlobalInvocationID.xy); );
- GLSLC(1, bool filter_field = ((pos.y ^ parity) & 1) == 1; );
- GLSLF(1, bool is_intra = filter_field && (current_field == %i); ,YADIF_FIELD_END);
- GLSLC(1, bool field_parity = (parity ^ tff) != 0; );
- GLSLC(0, );
- GLSLC(1, size = imageSize(dst[0]); );
- GLSLC(1, if (!IS_WITHIN(pos, size)) { );
- GLSLC(2, return; );
- GLSLC(1, } else if (is_intra) { );
- for (int i = 0; i < planes; i++) {
- if (i == 1) {
- GLSLF(2, size = imageSize(dst[%i]); ,i);
- GLSLC(2, if (!IS_WITHIN(pos, size)) );
- GLSLC(3, return; );
- }
- GLSLF(2, process_plane_intra(%i, pos); ,i);
- }
- GLSLC(1, } else if (filter_field) { );
- for (int i = 0; i < planes; i++) {
- if (i == 1) {
- GLSLF(2, size = imageSize(dst[%i]); ,i);
- GLSLC(2, if (!IS_WITHIN(pos, size)) );
- GLSLC(3, return; );
- }
- GLSLF(2, process_plane(%i, pos, filter_field, is_intra, field_parity); ,i);
- }
- GLSLC(1, } else { );
- for (int i = 0; i < planes; i++) {
- if (i == 1) {
- GLSLF(2, size = imageSize(dst[%i]); ,i);
- GLSLC(2, if (!IS_WITHIN(pos, size)) );
- GLSLC(3, return; );
- }
- GLSLF(2, imageStore(dst[%i], pos, imageLoad(cur[%i], pos)); ,i, i);
- }
- GLSLC(1, } );
- 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_bwdif_comp_spv_data,
+ ff_bwdif_comp_spv_len, "main"));
RET(ff_vk_shader_register_exec(vkctx, &s->e, &s->shd));
s->initialized = 1;
fail:
- if (spv_opaque)
- spv->free_shader(spv, &spv_opaque);
- if (spv)
- spv->uninit(&spv);
-
return err;
}
diff --git a/libavfilter/vulkan/Makefile b/libavfilter/vulkan/Makefile
index c77aaf4f6b..4987ba3a8c 100644
--- a/libavfilter/vulkan/Makefile
+++ b/libavfilter/vulkan/Makefile
@@ -3,7 +3,7 @@ GEN_CLEANSUFFIXES = *.o *.c *.d
clean::
$(RM) $(GEN_CLEANSUFFIXES:%=libavfilter/vulkan/%)
-OBJS-$(CONFIG_BWDIF_VULKAN_FILTER) += vulkan/bwdif.o
+OBJS-$(CONFIG_BWDIF_VULKAN_FILTER) += vulkan/bwdif.comp.spv.o
OBJS-$(CONFIG_SCALE_VULKAN_FILTER) += vulkan/debayer.o
VULKAN = $(subst $(SRC_PATH)/,,$(wildcard $(SRC_PATH)/libavfilter/vulkan/*.comp))
diff --git a/libavfilter/vulkan/bwdif.comp b/libavfilter/vulkan/bwdif.comp.glsl
similarity index 76%
rename from libavfilter/vulkan/bwdif.comp
rename to libavfilter/vulkan/bwdif.comp.glsl
index 5152464823..fc190eaf82 100644
--- a/libavfilter/vulkan/bwdif.comp
+++ b/libavfilter/vulkan/bwdif.comp.glsl
@@ -18,6 +18,24 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#version 460
+#extension GL_EXT_shader_image_load_formatted : require
+#extension GL_EXT_nonuniform_qualifier : require
+#extension GL_EXT_scalar_block_layout : require
+
+layout(local_size_x_id = 0, local_size_y_id = 1, local_size_z_id = 2) in;
+
+layout(set = 0, binding = 0) uniform readonly image2D prev[];
+layout(set = 0, binding = 1) uniform readonly image2D cur[];
+layout(set = 0, binding = 2) uniform readonly image2D next[];
+layout(set = 0, binding = 3) uniform writeonly image2D dst[];
+
+layout(push_constant, scalar) uniform pushConstants {
+ int parity;
+ int tff;
+ int current_field;
+};
+
const vec4 coef_lf[2] = { vec4(4309), vec4(213), };
const vec4 coef_hf[3] = { vec4(5570), vec4(3801), vec4(1016) };
const vec4 coef_sp[2] = { vec4(5077), vec4(981), };
@@ -27,8 +45,10 @@ vec4 process_intra(vec4 cur[4])
return (coef_sp[0]*(cur[1] + cur[2]) - coef_sp[1]*(cur[0] + cur[3])) / (1 << 13);
}
-void process_plane_intra(int idx, ivec2 pos)
+void process_plane_intra(ivec2 pos)
{
+ const uint idx = gl_LocalInvocationID.z;
+
vec4 dcur[4];
dcur[0] = imageLoad(cur[idx], pos - ivec2(0, 3));
dcur[1] = imageLoad(cur[idx], pos - ivec2(0, 1));
@@ -72,9 +92,11 @@ vec4 process_line(vec4 prev2[5], vec4 prev1[2], vec4 cur[4], vec4 next1[2], vec4
return mix(interpol, fd, diff_mask);
}
-void process_plane(int idx, const ivec2 pos, bool filter_field,
- bool is_intra, bool field_parity)
+void process_plane(const ivec2 pos)
{
+ const uint idx = gl_LocalInvocationID.z;
+ bool field_parity = (parity ^ tff) != 0;
+
vec4 dcur[4];
vec4 prev1[2];
vec4 next1[2];
@@ -120,3 +142,22 @@ void process_plane(int idx, const ivec2 pos, bool filter_field,
imageStore(dst[idx], pos, process_line(prev2, prev1, dcur, next1, next2));
}
+
+void main()
+{
+ const ivec2 pos = ivec2(gl_GlobalInvocationID.xy);
+ bool filter_field = ((pos.y ^ parity) & 1) == 1;
+ bool is_intra = filter_field && (current_field == 0);
+
+#define IS_WITHIN(v1, v2) ((v1.x < v2.x) && (v1.y < v2.y))
+ if (!IS_WITHIN(pos, imageSize(dst[gl_LocalInvocationID.z]))) {
+ return;
+ } else if (is_intra) {
+ process_plane_intra(pos);
+ } else if (filter_field) {
+ process_plane(pos);
+ } else {
+ imageStore(dst[gl_LocalInvocationID.z], pos,
+ imageLoad(cur[gl_LocalInvocationID.z], pos));
+ }
+}
--
2.49.1
>From e105b0d2d1acf811b4bbe68fe6c6e173e0e930ae Mon Sep 17 00:00:00 2001
From: Lynne <dev@lynne.ee>
Date: Fri, 2 Jan 2026 15:21:36 +0100
Subject: [PATCH 10/12] avgblur_vulkan: generate SPIR-V during compilation
---
configure | 2 +-
libavfilter/vf_avgblur_vulkan.c | 114 +++++++--------------------
libavfilter/vulkan/Makefile | 1 +
libavfilter/vulkan/avgblur.comp.glsl | 58 ++++++++++++++
4 files changed, 87 insertions(+), 88 deletions(-)
create mode 100644 libavfilter/vulkan/avgblur.comp.glsl
diff --git a/configure b/configure
index c4a66c9a12..1ad5278f6a 100755
--- a/configure
+++ b/configure
@@ -4017,7 +4017,7 @@ aresample_filter_deps="swresample"
asr_filter_deps="pocketsphinx"
ass_filter_deps="libass"
avgblur_opencl_filter_deps="opencl"
-avgblur_vulkan_filter_deps="vulkan spirv_library"
+avgblur_vulkan_filter_deps="vulkan"
azmq_filter_deps="libzmq"
blackdetect_vulkan_filter_deps="vulkan spirv_library"
blackframe_filter_deps="gpl"
diff --git a/libavfilter/vf_avgblur_vulkan.c b/libavfilter/vf_avgblur_vulkan.c
index 156278dd78..847390d064 100644
--- a/libavfilter/vf_avgblur_vulkan.c
+++ b/libavfilter/vf_avgblur_vulkan.c
@@ -19,13 +19,15 @@
*/
#include "libavutil/random_seed.h"
-#include "libavutil/vulkan_spirv.h"
#include "libavutil/opt.h"
#include "vulkan_filter.h"
#include "filters.h"
#include "video.h"
+extern const unsigned char ff_avgblur_comp_spv_data[];
+extern const unsigned int ff_avgblur_comp_spv_len;
+
typedef struct AvgBlurVulkanContext {
FFVulkanContext vkctx;
@@ -38,43 +40,21 @@ typedef struct AvgBlurVulkanContext {
struct {
float filter_norm[4];
int32_t filter_len[2];
+ uint32_t planes;
} opts;
int size_x;
int size_y;
- int planes;
} AvgBlurVulkanContext;
-static const char blur_kernel[] = {
- C(0, void distort(const ivec2 pos, const int idx) )
- C(0, { )
- C(1, vec4 sum = vec4(0); )
- C(1, for (int y = -filter_len.y; y <= filter_len.y; y++) )
- C(1, for (int x = -filter_len.x; x <= filter_len.x; x++) )
- C(2, sum += imageLoad(input_img[idx], pos + ivec2(x, y)); )
- C(0, )
- C(1, imageStore(output_img[idx], pos, sum * filter_norm); )
- C(0, } )
-};
-
static av_cold int init_filter(AVFilterContext *ctx, AVFrame *in)
{
int err;
- uint8_t *spv_data;
- size_t spv_len;
- void *spv_opaque = NULL;
AvgBlurVulkanContext *s = ctx->priv;
FFVulkanContext *vkctx = &s->vkctx;
const int planes = av_pix_fmt_count_planes(s->vkctx.output_format);
- FFVulkanShader *shd;
- FFVkSPIRVCompiler *spv;
- FFVulkanDescriptorSetBinding *desc;
- spv = ff_vk_spirv_init();
- if (!spv) {
- av_log(ctx, AV_LOG_ERROR, "Unable to initialize SPIR-V compiler!\n");
- return AVERROR_EXTERNAL;
- }
+ FFVulkanDescriptorSetBinding *desc;
s->qf = ff_vk_qf_find(vkctx, VK_QUEUE_COMPUTE_BIT, 0);
if (!s->qf) {
@@ -84,68 +64,33 @@ static av_cold int init_filter(AVFilterContext *ctx, AVFrame *in)
}
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, "avgblur",
- VK_SHADER_STAGE_COMPUTE_BIT,
- NULL, 0,
- 32, 1, 1,
- 0));
- shd = &s->shd;
- desc = (FFVulkanDescriptorSetBinding []) {
- {
- .name = "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 = planes,
- .stages = VK_SHADER_STAGE_COMPUTE_BIT,
- },
- {
- .name = "output_img",
- .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
- .mem_layout = ff_vk_shader_rep_fmt(s->vkctx.output_format, FF_VK_REP_FLOAT),
- .mem_quali = "writeonly",
- .dimensions = 2,
- .elems = planes,
- .stages = VK_SHADER_STAGE_COMPUTE_BIT,
- },
- };
-
- RET(ff_vk_shader_add_descriptor_set(vkctx, shd, desc, 2, 0, 0));
-
- GLSLC(0, layout(push_constant, std430) uniform pushConstants { );
- GLSLC(1, vec4 filter_norm; );
- GLSLC(1, ivec2 filter_len; );
- GLSLC(0, }; );
- GLSLC(0, );
+ ff_vk_shader_load(&s->shd, VK_SHADER_STAGE_COMPUTE_BIT,
+ NULL, (uint32_t []) { 32, 1, planes }, 0);
ff_vk_shader_add_push_const(&s->shd, 0, sizeof(s->opts),
VK_SHADER_STAGE_COMPUTE_BIT);
- GLSLD( blur_kernel );
- GLSLC(0, void main() );
- GLSLC(0, { );
- GLSLC(1, ivec2 size; );
- GLSLC(1, vec4 res; );
- GLSLC(1, const ivec2 pos = ivec2(gl_GlobalInvocationID.xy); );
- for (int i = 0; i < planes; i++) {
- GLSLC(0, );
- GLSLF(1, size = imageSize(output_img[%i]); ,i);
- GLSLC(1, if (!IS_WITHIN(pos, size)) );
- GLSLC(2, return; );
- if (s->planes & (1 << i)) {
- GLSLF(1, distort(pos, %i); ,i);
- } else {
- GLSLF(1, res = imageLoad(input_img[%i], pos); ,i);
- GLSLF(1, imageStore(output_img[%i], pos, res); ,i);
- }
- }
- GLSLC(0, } );
+ desc = (FFVulkanDescriptorSetBinding []) {
+ {
+ .name = "input_img",
+ .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
+ .stages = VK_SHADER_STAGE_COMPUTE_BIT,
+ .elems = planes,
+ },
+ {
+ .name = "output_img",
+ .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
+ .stages = VK_SHADER_STAGE_COMPUTE_BIT,
+ .elems = planes,
+ },
+ };
- 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"));
+ ff_vk_shader_add_descriptor_set(vkctx, &s->shd, desc, 2, 0, 0);
+
+ RET(ff_vk_shader_link(vkctx, &s->shd,
+ ff_avgblur_comp_spv_data,
+ ff_avgblur_comp_spv_len, "main"));
RET(ff_vk_shader_register_exec(vkctx, &s->e, &s->shd));
@@ -160,11 +105,6 @@ static av_cold int init_filter(AVFilterContext *ctx, AVFrame *in)
s->opts.filter_norm[3] = s->opts.filter_norm[0];
fail:
- if (spv_opaque)
- spv->free_shader(spv, &spv_opaque);
- if (spv)
- spv->uninit(&spv);
-
return err;
}
@@ -221,7 +161,7 @@ static void avgblur_vulkan_uninit(AVFilterContext *avctx)
static const AVOption avgblur_vulkan_options[] = {
{ "sizeX", "Set horizontal radius", OFFSET(size_x), AV_OPT_TYPE_INT, { .i64 = 3 }, 1, 32, .flags = FLAGS },
{ "sizeY", "Set vertical radius", OFFSET(size_y), AV_OPT_TYPE_INT, { .i64 = 3 }, 1, 32, .flags = FLAGS },
- { "planes", "Set planes to filter (bitmask)", OFFSET(planes), AV_OPT_TYPE_INT, {.i64 = 0xF}, 0, 0xF, .flags = FLAGS },
+ { "planes", "Set planes to filter (bitmask)", OFFSET(opts.planes), AV_OPT_TYPE_INT, {.i64 = 0xF}, 0, 0xF, .flags = FLAGS },
{ NULL },
};
diff --git a/libavfilter/vulkan/Makefile b/libavfilter/vulkan/Makefile
index 4987ba3a8c..50f821fd53 100644
--- a/libavfilter/vulkan/Makefile
+++ b/libavfilter/vulkan/Makefile
@@ -3,6 +3,7 @@ GEN_CLEANSUFFIXES = *.o *.c *.d
clean::
$(RM) $(GEN_CLEANSUFFIXES:%=libavfilter/vulkan/%)
+OBJS-$(CONFIG_SCALE_VULKAN_FILTER) += vulkan/avgblur.comp.spv.o
OBJS-$(CONFIG_BWDIF_VULKAN_FILTER) += vulkan/bwdif.comp.spv.o
OBJS-$(CONFIG_SCALE_VULKAN_FILTER) += vulkan/debayer.o
diff --git a/libavfilter/vulkan/avgblur.comp.glsl b/libavfilter/vulkan/avgblur.comp.glsl
new file mode 100644
index 0000000000..6ac401867a
--- /dev/null
+++ b/libavfilter/vulkan/avgblur.comp.glsl
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2026 Lynne <dev@lynne.ee>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#version 460
+#extension GL_EXT_shader_image_load_formatted : require
+#extension GL_EXT_scalar_block_layout : require
+#extension GL_EXT_nonuniform_qualifier : require
+
+layout(local_size_x_id = 0, local_size_y_id = 1, local_size_z_id = 2) in;
+
+layout(set = 0, binding = 0) uniform readonly image2D input_img[];
+layout(set = 0, binding = 1) uniform writeonly image2D output_img[];
+
+layout(push_constant, scalar) uniform pushConstants {
+ vec4 filter_norm;
+ ivec2 filter_len;
+ uint planes;
+};
+
+void main()
+{
+ const ivec2 pos = ivec2(gl_GlobalInvocationID.xy);
+
+#define IS_WITHIN(v1, v2) ((v1.x < v2.x) && (v1.y < v2.y))
+ ivec2 size = imageSize(output_img[gl_LocalInvocationID.z]);
+ if (!IS_WITHIN(pos, size))
+ return;
+
+ if ((planes & (1 << gl_LocalInvocationID.z)) == 0) {
+ imageStore(output_img[gl_LocalInvocationID.z], pos,
+ imageLoad(input_img[gl_LocalInvocationID.z], pos));
+ return;
+ }
+
+ vec4 sum = vec4(0);
+ for (int y = -filter_len.y; y <= filter_len.y; y++)
+ for (int x = -filter_len.x; x <= filter_len.x; x++)
+ sum += imageLoad(input_img[gl_LocalInvocationID.z], pos + ivec2(x, y));
+
+ imageStore(output_img[gl_LocalInvocationID.z], pos, sum * filter_norm);
+}
--
2.49.1
>From 2bee285888cd6f1bffe665375a8e7dbc7bad2004 Mon Sep 17 00:00:00 2001
From: Lynne <dev@lynne.ee>
Date: Fri, 2 Jan 2026 13:12:44 +0100
Subject: [PATCH 11/12] vulkan_prores_raw: use compile-time SPIR-V generation
---
configure | 2 +-
libavcodec/vulkan/Makefile | 5 +-
libavcodec/vulkan/common.comp | 11 ++
libavcodec/vulkan/dct.comp | 14 +-
...ecode.comp => prores_raw_decode.comp.glsl} | 24 +++
...aw_idct.comp => prores_raw_idct.comp.glsl} | 27 ++++
libavcodec/vulkan_prores_raw.c | 139 ++++++------------
7 files changed, 124 insertions(+), 98 deletions(-)
rename libavcodec/vulkan/{prores_raw_decode.comp => prores_raw_decode.comp.glsl} (93%)
rename libavcodec/vulkan/{prores_raw_idct.comp => prores_raw_idct.comp.glsl} (85%)
diff --git a/configure b/configure
index 1ad5278f6a..886ab7ba1e 100755
--- a/configure
+++ b/configure
@@ -3378,7 +3378,7 @@ mpeg4_videotoolbox_hwaccel_deps="videotoolbox"
mpeg4_videotoolbox_hwaccel_select="mpeg4_decoder"
prores_videotoolbox_hwaccel_deps="videotoolbox"
prores_videotoolbox_hwaccel_select="prores_decoder"
-prores_raw_vulkan_hwaccel_deps="vulkan spirv_library"
+prores_raw_vulkan_hwaccel_deps="vulkan"
prores_raw_vulkan_hwaccel_select="prores_raw_decoder"
prores_vulkan_hwaccel_deps="vulkan spirv_library"
prores_vulkan_hwaccel_select="prores_decoder"
diff --git a/libavcodec/vulkan/Makefile b/libavcodec/vulkan/Makefile
index 35e96c506d..c1f22cb8cc 100644
--- a/libavcodec/vulkan/Makefile
+++ b/libavcodec/vulkan/Makefile
@@ -14,9 +14,8 @@ OBJS-$(CONFIG_FFV1_VULKAN_HWACCEL) += vulkan/common.o \
vulkan/ffv1_common.o vulkan/ffv1_reset.o \
vulkan/ffv1_dec_setup.o vulkan/ffv1_dec.o
-OBJS-$(CONFIG_PRORES_RAW_VULKAN_HWACCEL) += vulkan/common.o vulkan/dct.o \
- vulkan/prores_raw_decode.o \
- vulkan/prores_raw_idct.o
+OBJS-$(CONFIG_PRORES_RAW_VULKAN_HWACCEL) += vulkan/prores_raw_decode.comp.spv.o \
+ vulkan/prores_raw_idct.comp.spv.o
OBJS-$(CONFIG_PRORES_VULKAN_HWACCEL) += vulkan/common.o vulkan/dct.o \
vulkan/prores_vld.o \
diff --git a/libavcodec/vulkan/common.comp b/libavcodec/vulkan/common.comp
index 3538aeacd1..19619e2d06 100644
--- a/libavcodec/vulkan/common.comp
+++ b/libavcodec/vulkan/common.comp
@@ -18,6 +18,15 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#ifndef VULKAN_COMMON_H
+#define VULKAN_COMMON_H
+
+#extension GL_EXT_shader_explicit_arithmetic_types : require
+#extension GL_EXT_buffer_reference : require
+#extension GL_EXT_buffer_reference2 : require
+#extension GL_EXT_expect_assume : enable
+#extension GL_EXT_control_flow_attributes : enable
+
layout(buffer_reference, buffer_reference_align = 1) buffer u8buf {
uint8_t v;
};
@@ -336,3 +345,5 @@ int left_bits(in GetBitContext gb)
{
return int(gb.buf_end - gb.buf) * 8 + gb.bits_valid;
}
+
+#endif /* VULKAN_COMMON_H */
diff --git a/libavcodec/vulkan/dct.comp b/libavcodec/vulkan/dct.comp
index 34c6ad128f..3cae84877f 100644
--- a/libavcodec/vulkan/dct.comp
+++ b/libavcodec/vulkan/dct.comp
@@ -31,12 +31,22 @@
* IEEE Transactions on Communications, Vol. 25, No. 9, pp 1004-1009, Sept. 1977
*/
+#ifndef VULKAN_DCT_H
+#define VULKAN_DCT_H
+
+#ifndef NB_BLOCKS
+#define NB_BLOCKS 1
+#endif
+
#ifndef NB_COMPONENTS
#define NB_COMPONENTS 1
#endif
+layout(constant_id = 3) const uint32_t nb_blocks = NB_BLOCKS;
+layout(constant_id = 4) const uint32_t nb_components = NB_COMPONENTS;
+
/* Padded by 1 row to avoid bank conflicts */
-shared float blocks[NB_BLOCKS][NB_COMPONENTS*8*(8 + 1)];
+shared float blocks[nb_blocks][nb_components*8*(8 + 1)];
const float idct_scale[64] = {
0.1250000000000000, 0.1733799806652684, 0.1633203706095471, 0.1469844503024199,
@@ -117,3 +127,5 @@ void idct8(uint block, uint offset, uint stride)
blocks[block][6*stride + offset] = u6;
blocks[block][7*stride + offset] = u7;
}
+
+#endif /* VULKAN_DCT_H */
diff --git a/libavcodec/vulkan/prores_raw_decode.comp b/libavcodec/vulkan/prores_raw_decode.comp.glsl
similarity index 93%
rename from libavcodec/vulkan/prores_raw_decode.comp
rename to libavcodec/vulkan/prores_raw_decode.comp.glsl
index 384046f891..8f0717a408 100644
--- a/libavcodec/vulkan/prores_raw_decode.comp
+++ b/libavcodec/vulkan/prores_raw_decode.comp.glsl
@@ -20,6 +20,30 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#version 460
+#extension GL_GOOGLE_include_directive : require
+#extension GL_EXT_scalar_block_layout : require
+
+#include "common.comp"
+
+struct TileData {
+ ivec2 pos;
+ uint offset;
+ uint size;
+};
+
+layout(set = 0, binding = 0) uniform writeonly uimage2D dst;
+layout(set = 0, binding = 1, scalar) readonly buffer frame_data_buf {
+ TileData tile_data[];
+};
+
+layout(push_constant, scalar) uniform pushConstants {
+ u8buf pkt_data;
+ ivec2 frame_size;
+ ivec2 tile_size;
+ uint8_t qmat[64];
+};
+
#define COMP_ID (gl_LocalInvocationID.x)
GetBitContext gb;
diff --git a/libavcodec/vulkan/prores_raw_idct.comp b/libavcodec/vulkan/prores_raw_idct.comp.glsl
similarity index 85%
rename from libavcodec/vulkan/prores_raw_idct.comp
rename to libavcodec/vulkan/prores_raw_idct.comp.glsl
index c9850d17d7..64c234e78e 100644
--- a/libavcodec/vulkan/prores_raw_idct.comp
+++ b/libavcodec/vulkan/prores_raw_idct.comp.glsl
@@ -20,6 +20,33 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#version 460
+#extension GL_GOOGLE_include_directive : require
+#extension GL_EXT_scalar_block_layout : require
+#extension GL_EXT_shader_image_load_formatted : require
+
+#include "common.comp"
+#include "dct.comp"
+
+struct TileData {
+ ivec2 pos;
+ uint offset;
+ uint size;
+};
+
+layout(local_size_x_id = 0, local_size_y_id = 1, local_size_z_id = 2) in;
+layout(set = 0, binding = 0) uniform uimage2D dst;
+layout(set = 0, binding = 1, scalar) readonly buffer frame_data_buf {
+ TileData tile_data[];
+};
+
+layout(push_constant, scalar) uniform pushConstants {
+ u8buf pkt_data;
+ ivec2 frame_size;
+ ivec2 tile_size;
+ uint8_t qmat[64];
+};
+
#define COMP_ID (gl_LocalInvocationID.z)
#define BLOCK_ID (gl_LocalInvocationID.y)
#define ROW_ID (gl_LocalInvocationID.x)
diff --git a/libavcodec/vulkan_prores_raw.c b/libavcodec/vulkan_prores_raw.c
index aa2b698925..0746a38ddc 100644
--- a/libavcodec/vulkan_prores_raw.c
+++ b/libavcodec/vulkan_prores_raw.c
@@ -22,13 +22,13 @@
#include "hwaccel_internal.h"
#include "prores_raw.h"
-#include "libavutil/vulkan_spirv.h"
#include "libavutil/mem.h"
-extern const char *ff_source_common_comp;
-extern const char *ff_source_dct_comp;
-extern const char *ff_source_prores_raw_decode_comp;
-extern const char *ff_source_prores_raw_idct_comp;
+extern const unsigned char ff_prores_raw_decode_comp_spv_data[];
+extern const unsigned int ff_prores_raw_decode_comp_spv_len;
+
+extern const unsigned char ff_prores_raw_idct_comp_spv_data[];
+extern const unsigned int ff_prores_raw_idct_comp_spv_len;
const FFVulkanDecodeDescriptor ff_vk_dec_prores_raw_desc = {
.codec_id = AV_CODEC_ID_PRORES_RAW,
@@ -287,46 +287,19 @@ fail:
static int add_common_data(AVCodecContext *avctx, FFVulkanContext *s,
FFVulkanShader *shd, int writeonly)
{
- AVHWFramesContext *dec_frames_ctx;
- dec_frames_ctx = (AVHWFramesContext *)avctx->hw_frames_ctx->data;
-
- /* Common codec header */
- GLSLD(ff_source_common_comp);
-
- GLSLC(0, struct TileData { );
- GLSLC(1, ivec2 pos; );
- GLSLC(1, uint offset; );
- GLSLC(1, uint size; );
- GLSLC(0, }; );
- GLSLC(0, );
- GLSLC(0, layout(push_constant, scalar) uniform pushConstants { );
- GLSLC(1, u8buf pkt_data; );
- GLSLC(1, ivec2 frame_size; );
- GLSLC(1, ivec2 tile_size; );
- GLSLC(1, uint8_t qmat[64]; );
- GLSLC(0, }; );
- GLSLC(0, );
ff_vk_shader_add_push_const(shd, 0, sizeof(DecodePushData),
VK_SHADER_STAGE_COMPUTE_BIT);
- FFVulkanDescriptorSetBinding *desc_set;
- desc_set = (FFVulkanDescriptorSetBinding []) {
+ FFVulkanDescriptorSetBinding desc_set[] = {
{
- .name = "dst",
- .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
- .mem_layout = ff_vk_shader_rep_fmt(dec_frames_ctx->sw_format,
- FF_VK_REP_NATIVE),
- .mem_quali = writeonly ? "writeonly" : NULL,
- .dimensions = 2,
- .stages = VK_SHADER_STAGE_COMPUTE_BIT,
+ .name = "dst",
+ .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
+ .stages = VK_SHADER_STAGE_COMPUTE_BIT,
},
{
- .name = "frame_data_buf",
- .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
- .stages = VK_SHADER_STAGE_COMPUTE_BIT,
- .mem_layout = "scalar",
- .mem_quali = "readonly",
- .buf_content = "TileData tile_data[];",
+ .name = "frame_data_buf",
+ .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
+ .stages = VK_SHADER_STAGE_COMPUTE_BIT,
},
};
@@ -334,74 +307,62 @@ static int add_common_data(AVCodecContext *avctx, FFVulkanContext *s,
}
static int init_decode_shader(AVCodecContext *avctx, FFVulkanContext *s,
- FFVkExecPool *pool, FFVkSPIRVCompiler *spv,
- FFVulkanShader *shd, int version)
+ FFVkExecPool *pool, FFVulkanShader *shd,
+ int version)
{
int err;
- uint8_t *spv_data;
- size_t spv_len;
- void *spv_opaque = NULL;
- RET(ff_vk_shader_init(s, shd, "prores_raw",
- VK_SHADER_STAGE_COMPUTE_BIT,
- (const char *[]) { "GL_EXT_buffer_reference",
- "GL_EXT_buffer_reference2",
- "GL_EXT_null_initializer" }, 3,
- 4, 1, 1, 0));
+ ff_vk_shader_load(shd, VK_SHADER_STAGE_COMPUTE_BIT, NULL,
+ (uint32_t []) { 4, 1, 1 }, 0);
- RET(add_common_data(avctx, s, shd, 1));
+ add_common_data(avctx, s, shd, 1);
- GLSLD(ff_source_prores_raw_decode_comp);
-
- RET(spv->compile_shader(s, spv, shd, &spv_data, &spv_len, "main",
- &spv_opaque));
- RET(ff_vk_shader_link(s, shd, spv_data, spv_len, "main"));
+ RET(ff_vk_shader_link(s, shd,
+ ff_prores_raw_decode_comp_spv_data,
+ ff_prores_raw_decode_comp_spv_len, "main"));
RET(ff_vk_shader_register_exec(s, pool, shd));
fail:
- if (spv_opaque)
- spv->free_shader(spv, &spv_opaque);
-
return err;
}
static int init_idct_shader(AVCodecContext *avctx, FFVulkanContext *s,
- FFVkExecPool *pool, FFVkSPIRVCompiler *spv,
- FFVulkanShader *shd, int version)
+ FFVkExecPool *pool, FFVulkanShader *shd,
+ int version)
{
int err;
- uint8_t *spv_data;
- size_t spv_len;
- void *spv_opaque = NULL;
+ uint32_t spec_data[5];
+ VkSpecializationMapEntry spec_entries[5];
+ VkSpecializationInfo spec_info = {
+ .pMapEntries = spec_entries,
+ .mapEntryCount = 2,
+ .pData = spec_data,
+ .dataSize = 2*sizeof(uint32_t),
+ };
- RET(ff_vk_shader_init(s, shd, "prores_raw",
- VK_SHADER_STAGE_COMPUTE_BIT,
- (const char *[]) { "GL_EXT_buffer_reference",
- "GL_EXT_buffer_reference2" }, 2,
- 8,
- version == 0 ? 8 : 16 /* Horizontal blocks */,
- 4 /* Components */,
- 0));
+ spec_data[0] = version == 0 ? 8 : 16; /* nb_blocks */
+ spec_entries[0].constantID = 3;
+ spec_entries[0].size = 4;
+ spec_entries[0].offset = 0;
- RET(add_common_data(avctx, s, shd, 0));
+ spec_data[1] = 4; /* nb_components */
+ spec_entries[1].constantID = 4;
+ spec_entries[1].size = 4;
+ spec_entries[1].offset = 4;
- GLSLC(0, #define NB_BLOCKS 16);
- GLSLC(0, #define NB_COMPONENTS 4);
- GLSLD(ff_source_dct_comp);
+ ff_vk_shader_load(shd, VK_SHADER_STAGE_COMPUTE_BIT, &spec_info,
+ (uint32_t []) { 8, spec_data[0], spec_data[1] }, 0);
- GLSLD(ff_source_prores_raw_idct_comp);
+ add_common_data(avctx, s, shd, 0);
- RET(spv->compile_shader(s, spv, shd, &spv_data, &spv_len, "main",
- &spv_opaque));
- RET(ff_vk_shader_link(s, shd, spv_data, spv_len, "main"));
+ RET(ff_vk_shader_link(s, shd,
+ ff_prores_raw_idct_comp_spv_data,
+ ff_prores_raw_idct_comp_spv_len, "main"));
RET(ff_vk_shader_register_exec(s, pool, shd));
fail:
- if (spv_opaque)
- spv->free_shader(spv, &spv_opaque);
-
return err;
}
@@ -423,12 +384,6 @@ static int vk_decode_prores_raw_init(AVCodecContext *avctx)
FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data;
ProResRAWContext *prr = avctx->priv_data;
- FFVkSPIRVCompiler *spv = ff_vk_spirv_init();
- if (!spv) {
- av_log(avctx, AV_LOG_ERROR, "Unable to initialize SPIR-V compiler!\n");
- return AVERROR_EXTERNAL;
- }
-
err = ff_vk_decode_init(avctx);
if (err < 0)
return err;
@@ -443,14 +398,12 @@ static int vk_decode_prores_raw_init(AVCodecContext *avctx)
ctx->sd_ctx_free = &vk_decode_prores_raw_uninit;
/* Setup decode shader */
- RET(init_decode_shader(avctx, &ctx->s, &ctx->exec_pool, spv, &prv->decode,
+ RET(init_decode_shader(avctx, &ctx->s, &ctx->exec_pool, &prv->decode,
prr->version));
- RET(init_idct_shader(avctx, &ctx->s, &ctx->exec_pool, spv, &prv->idct,
+ RET(init_idct_shader(avctx, &ctx->s, &ctx->exec_pool, &prv->idct,
prr->version));
fail:
- spv->uninit(&spv);
-
return err;
}
--
2.49.1
>From e3bd6dba621ecfd1fd4fb3ec4bc7444d81c6c47d Mon Sep 17 00:00:00 2001
From: Lynne <dev@lynne.ee>
Date: Fri, 2 Jan 2026 13:41:27 +0100
Subject: [PATCH 12/12] vulkan_prores: generate SPIR-V at compile-time
---
configure | 2 +-
libavcodec/vulkan/Makefile | 5 +-
...prores_idct.comp => prores_idct.comp.glsl} | 38 +++-
.../{prores_vld.comp => prores_vld.comp.glsl} | 38 ++++
libavcodec/vulkan_prores.c | 183 ++++++------------
5 files changed, 136 insertions(+), 130 deletions(-)
rename libavcodec/vulkan/{prores_idct.comp => prores_idct.comp.glsl} (76%)
rename libavcodec/vulkan/{prores_vld.comp => prores_vld.comp.glsl} (92%)
diff --git a/configure b/configure
index 886ab7ba1e..060a0bded8 100755
--- a/configure
+++ b/configure
@@ -3380,7 +3380,7 @@ prores_videotoolbox_hwaccel_deps="videotoolbox"
prores_videotoolbox_hwaccel_select="prores_decoder"
prores_raw_vulkan_hwaccel_deps="vulkan"
prores_raw_vulkan_hwaccel_select="prores_raw_decoder"
-prores_vulkan_hwaccel_deps="vulkan spirv_library"
+prores_vulkan_hwaccel_deps="vulkan"
prores_vulkan_hwaccel_select="prores_decoder"
vc1_d3d11va_hwaccel_deps="d3d11va"
vc1_d3d11va_hwaccel_select="vc1_decoder"
diff --git a/libavcodec/vulkan/Makefile b/libavcodec/vulkan/Makefile
index c1f22cb8cc..093908b0b9 100644
--- a/libavcodec/vulkan/Makefile
+++ b/libavcodec/vulkan/Makefile
@@ -17,9 +17,8 @@ OBJS-$(CONFIG_FFV1_VULKAN_HWACCEL) += vulkan/common.o \
OBJS-$(CONFIG_PRORES_RAW_VULKAN_HWACCEL) += vulkan/prores_raw_decode.comp.spv.o \
vulkan/prores_raw_idct.comp.spv.o
-OBJS-$(CONFIG_PRORES_VULKAN_HWACCEL) += vulkan/common.o vulkan/dct.o \
- vulkan/prores_vld.o \
- vulkan/prores_idct.o
+OBJS-$(CONFIG_PRORES_VULKAN_HWACCEL) += vulkan/prores_vld.comp.spv.o \
+ vulkan/prores_idct.comp.spv.o
OBJS-$(CONFIG_DPX_VULKAN_HWACCEL) += vulkan/common.o \
vulkan/dpx_unpack.o \
diff --git a/libavcodec/vulkan/prores_idct.comp b/libavcodec/vulkan/prores_idct.comp.glsl
similarity index 76%
rename from libavcodec/vulkan/prores_idct.comp
rename to libavcodec/vulkan/prores_idct.comp.glsl
index 25431d61c1..c30e4983a1 100644
--- a/libavcodec/vulkan/prores_idct.comp
+++ b/libavcodec/vulkan/prores_idct.comp.glsl
@@ -16,10 +16,46 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#version 460
+#extension GL_GOOGLE_include_directive : require
+#extension GL_EXT_scalar_block_layout : require
+#extension GL_EXT_shader_image_load_formatted : require
+
+#include "common.comp"
+#include "dct.comp"
+
+layout(local_size_x_id = 0, local_size_y_id = 1, local_size_z_id = 2) in;
+layout(constant_id = 6) const uint32_t interlaced = 0;
+
+layout(set = 0, binding = 0) readonly buffer quant_idx_buf {
+ uint8_t quant_idx[68400];
+};
+layout(set = 0, binding = 1) uniform uimage2D dst[3];
+
+layout(push_constant, scalar) uniform pushConstants {
+ u8buf slice_data;
+ uint bitstream_size;
+
+ uint16_t width;
+ uint16_t height;
+ uint16_t mb_width;
+ uint16_t mb_height;
+ uint16_t slice_width;
+ uint16_t slice_height;
+ uint8_t log2_slice_width;
+ uint8_t log2_chroma_w;
+ uint8_t depth;
+ uint8_t alpha_info;
+ uint8_t bottom_field;
+
+ uint8_t qmat_luma [8*8];
+ uint8_t qmat_chroma[8*8];
+};
+
uint get_px(uint tex_idx, ivec2 pos)
{
#ifndef INTERLACED
- return imageLoad(dst[tex_idx], pos).x;
+ return uint(imageLoad(dst[tex_idx], pos).x);
#else
return imageLoad(dst[tex_idx], ivec2(pos.x, (pos.y << 1) + bottom_field)).x;
#endif
diff --git a/libavcodec/vulkan/prores_vld.comp b/libavcodec/vulkan/prores_vld.comp.glsl
similarity index 92%
rename from libavcodec/vulkan/prores_vld.comp
rename to libavcodec/vulkan/prores_vld.comp.glsl
index ab0dbf0116..8bf78389e2 100644
--- a/libavcodec/vulkan/prores_vld.comp
+++ b/libavcodec/vulkan/prores_vld.comp.glsl
@@ -16,6 +16,44 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#version 460
+#extension GL_GOOGLE_include_directive : require
+#extension GL_EXT_scalar_block_layout : require
+
+#define GET_BITS_SMEM 4
+#include "common.comp"
+
+layout(local_size_x_id = 0, local_size_y_id = 1, local_size_z_id = 2) in;
+layout(constant_id = 3) const uint32_t interlaced = 0;
+
+layout(set = 0, binding = 0) readonly buffer slice_offsets_buf {
+ uint32_t slice_offsets[68401];
+};
+layout(set = 0, binding = 1) writeonly buffer quant_idx_buf {
+ uint8_t quant_idx[68400];
+};
+layout(set = 0, binding = 2) uniform writeonly uimage2D dst[3];
+
+layout(push_constant, scalar) uniform pushConstants {
+ u8buf slice_data;
+ uint bitstream_size;
+
+ uint16_t width;
+ uint16_t height;
+ uint16_t mb_width;
+ uint16_t mb_height;
+ uint16_t slice_width;
+ uint16_t slice_height;
+ uint8_t log2_slice_width;
+ uint8_t log2_chroma_w;
+ uint8_t depth;
+ uint8_t alpha_info;
+ uint8_t bottom_field;
+
+ uint8_t qmat_luma [8*8];
+ uint8_t qmat_chroma[8*8];
+};
+
/**
* Table 9, encoded as (last_rice_q << 0) | (krice or kexp << 4) | ((kexp or kexp + 1) << 8)
* According to the SMPTE document, abs(prev_dc_diff) should be used
diff --git a/libavcodec/vulkan_prores.c b/libavcodec/vulkan_prores.c
index 7e7c2ace9c..4ab678668c 100644
--- a/libavcodec/vulkan_prores.c
+++ b/libavcodec/vulkan_prores.c
@@ -21,12 +21,12 @@
#include "hwaccel_internal.h"
#include "libavutil/mem.h"
#include "libavutil/vulkan.h"
-#include "libavutil/vulkan_spirv.h"
-extern const char *ff_source_common_comp;
-extern const char *ff_source_dct_comp;
-extern const char *ff_source_prores_vld_comp;
-extern const char *ff_source_prores_idct_comp;
+extern const unsigned char ff_prores_vld_comp_spv_data[];
+extern const unsigned int ff_prores_vld_comp_spv_len;
+
+extern const unsigned char ff_prores_idct_comp_spv_data[];
+extern const unsigned int ff_prores_idct_comp_spv_len;
const FFVulkanDecodeDescriptor ff_vk_dec_prores_desc = {
.codec_id = AV_CODEC_ID_PRORES,
@@ -342,171 +342,115 @@ fail:
return err;
}
-static int add_push_data(FFVulkanShader *shd)
-{
- GLSLC(0, layout(push_constant, scalar) uniform pushConstants { );
- GLSLC(1, u8buf slice_data; );
- GLSLC(1, uint bitstream_size; );
- GLSLC(0, );
- GLSLC(1, uint16_t width; );
- GLSLC(1, uint16_t height; );
- GLSLC(1, uint16_t mb_width; );
- GLSLC(1, uint16_t mb_height; );
- GLSLC(1, uint16_t slice_width; );
- GLSLC(1, uint16_t slice_height; );
- GLSLC(1, uint8_t log2_slice_width; );
- GLSLC(1, uint8_t log2_chroma_w; );
- GLSLC(1, uint8_t depth; );
- GLSLC(1, uint8_t alpha_info; );
- GLSLC(1, uint8_t bottom_field; );
- GLSLC(0, );
- GLSLC(1, uint8_t qmat_luma [8*8]; );
- GLSLC(1, uint8_t qmat_chroma[8*8]; );
- GLSLC(0, }; );
-
- return ff_vk_shader_add_push_const(shd, 0, sizeof(ProresVkParameters),
- VK_SHADER_STAGE_COMPUTE_BIT);
-}
-
static int init_decode_shader(AVCodecContext *avctx, FFVulkanContext *s,
- FFVkExecPool *pool, FFVkSPIRVCompiler *spv,
- FFVulkanShader *shd, int max_num_mbs,
- int interlaced)
+ FFVkExecPool *pool, FFVulkanShader *shd,
+ int max_num_mbs, int interlaced)
{
int err;
- AVHWFramesContext *dec_frames_ctx;
- dec_frames_ctx = (AVHWFramesContext *)avctx->hw_frames_ctx->data;
+ uint32_t spec_data[4];
+ VkSpecializationMapEntry spec_entries[4];
+ VkSpecializationInfo spec_info = {
+ .pMapEntries = spec_entries,
+ .mapEntryCount = 1,
+ .pData = spec_data,
+ .dataSize = 1*sizeof(uint32_t),
+ };
- uint8_t *spv_data;
- size_t spv_len;
- void *spv_opaque = NULL;
+ spec_data[0] = interlaced;
+ spec_entries[0].constantID = 3;
+ spec_entries[0].size = 4;
+ spec_entries[0].offset = 0;
- RET(ff_vk_shader_init(s, shd, "prores_vld",
- VK_SHADER_STAGE_COMPUTE_BIT,
- (const char *[]) { "GL_EXT_buffer_reference",
- "GL_EXT_buffer_reference2" }, 2,
- 8, 8, 1,
- 0));
+ ff_vk_shader_load(shd,
+ VK_SHADER_STAGE_COMPUTE_BIT, &spec_info,
+ (uint32_t []) { 8, 8, 1 }, 0);
- av_bprintf(&shd->src, "#define GET_BITS_SMEM %d\n", 4);
-
- if (interlaced)
- av_bprintf(&shd->src, "#define INTERLACED\n");
-
- /* Common codec header */
- GLSLD(ff_source_common_comp);
-
- RET(add_push_data(shd));
+ ff_vk_shader_add_push_const(shd, 0, sizeof(ProresVkParameters),
+ VK_SHADER_STAGE_COMPUTE_BIT);
FFVulkanDescriptorSetBinding desc_set[] = {
{
.name = "slice_offsets_buf",
.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
.stages = VK_SHADER_STAGE_COMPUTE_BIT,
- .mem_quali = "readonly",
- .buf_content = "uint32_t slice_offsets",
- .buf_elems = max_num_mbs + 1,
},
{
.name = "quant_idx_buf",
.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
.stages = VK_SHADER_STAGE_COMPUTE_BIT,
- .mem_quali = "writeonly",
- .buf_content = "uint8_t quant_idx",
- .buf_elems = max_num_mbs,
},
{
.name = "dst",
.type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
- .dimensions = 2,
- .mem_layout = ff_vk_shader_rep_fmt(dec_frames_ctx->sw_format,
- FF_VK_REP_NATIVE),
- .mem_quali = "writeonly",
- .elems = av_pix_fmt_count_planes(dec_frames_ctx->sw_format),
.stages = VK_SHADER_STAGE_COMPUTE_BIT,
+ .elems = 3, /* Always 3 separate planes */
},
};
- RET(ff_vk_shader_add_descriptor_set(s, shd, desc_set, 3, 0, 0));
+ ff_vk_shader_add_descriptor_set(s, shd, desc_set, 3, 0, 0);
- GLSLD(ff_source_prores_vld_comp);
-
- RET(spv->compile_shader(s, spv, shd, &spv_data, &spv_len, "main",
- &spv_opaque));
- RET(ff_vk_shader_link(s, shd, spv_data, spv_len, "main"));
+ RET(ff_vk_shader_link(s, shd,
+ ff_prores_vld_comp_spv_data,
+ ff_prores_vld_comp_spv_len, "main"));
RET(ff_vk_shader_register_exec(s, pool, shd));
fail:
- if (spv_opaque)
- spv->free_shader(spv, &spv_opaque);
-
return 0;
}
static int init_idct_shader(AVCodecContext *avctx, FFVulkanContext *s,
- FFVkExecPool *pool, FFVkSPIRVCompiler *spv,
- FFVulkanShader *shd, int max_num_mbs,
- int interlaced)
+ FFVkExecPool *pool, FFVulkanShader *shd,
+ int max_num_mbs, int interlaced)
{
int err;
- AVHWFramesContext *dec_frames_ctx;
- dec_frames_ctx = (AVHWFramesContext *)avctx->hw_frames_ctx->data;
+ uint32_t spec_data[5];
+ VkSpecializationMapEntry spec_entries[5];
+ VkSpecializationInfo spec_info = {
+ .pMapEntries = spec_entries,
+ .mapEntryCount = 2,
+ .pData = spec_data,
+ .dataSize = 2*sizeof(uint32_t),
+ };
- uint8_t *spv_data;
- size_t spv_len;
- void *spv_opaque = NULL;
+ spec_data[0] = 4*2; /* nb_blocks */
+ spec_entries[0].constantID = 3;
+ spec_entries[0].size = 4;
+ spec_entries[0].offset = 0;
- RET(ff_vk_shader_init(s, shd, "prores_idct",
- VK_SHADER_STAGE_COMPUTE_BIT,
- (const char *[]) { "GL_EXT_buffer_reference",
- "GL_EXT_buffer_reference2" }, 2,
- 32, 2, 1,
- 0));
+ spec_data[1] = interlaced;
+ spec_entries[1].constantID = 5;
+ spec_entries[1].size = 4;
+ spec_entries[1].offset = 4;
- if (interlaced)
- av_bprintf(&shd->src, "#define INTERLACED\n");
+ ff_vk_shader_load(shd,
+ VK_SHADER_STAGE_COMPUTE_BIT, &spec_info,
+ (uint32_t []) { 32, 2, 1 }, 0);
- /* Common codec header */
- GLSLD(ff_source_common_comp);
-
- RET(add_push_data(shd));
+ ff_vk_shader_add_push_const(shd, 0, sizeof(ProresVkParameters),
+ VK_SHADER_STAGE_COMPUTE_BIT);
FFVulkanDescriptorSetBinding desc_set[] = {
{
.name = "quant_idx_buf",
.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
.stages = VK_SHADER_STAGE_COMPUTE_BIT,
- .mem_quali = "readonly",
- .buf_content = "uint8_t quant_idx",
- .buf_elems = max_num_mbs,
},
{
.name = "dst",
.type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
- .dimensions = 2,
- .mem_layout = ff_vk_shader_rep_fmt(dec_frames_ctx->sw_format,
- FF_VK_REP_NATIVE),
- .elems = av_pix_fmt_count_planes(dec_frames_ctx->sw_format),
.stages = VK_SHADER_STAGE_COMPUTE_BIT,
+ .elems = 3,
},
};
RET(ff_vk_shader_add_descriptor_set(s, shd, desc_set, 2, 0, 0));
- GLSLC(0, #define NB_BLOCKS 4*2);
- GLSLD(ff_source_dct_comp);
-
- GLSLD(ff_source_prores_idct_comp);
-
- RET(spv->compile_shader(s, spv, shd, &spv_data, &spv_len, "main",
- &spv_opaque));
- RET(ff_vk_shader_link(s, shd, spv_data, spv_len, "main"));
+ RET(ff_vk_shader_link(s, shd,
+ ff_prores_idct_comp_spv_data,
+ ff_prores_idct_comp_spv_len, "main"));
RET(ff_vk_shader_register_exec(s, pool, shd));
fail:
- if (spv_opaque)
- spv->free_shader(spv, &spv_opaque);
-
return 0;
}
@@ -529,17 +473,10 @@ static int vk_decode_prores_init(AVCodecContext *avctx)
ProresContext *pr = avctx->priv_data;
ProresVulkanDecodeContext *pv;
- FFVkSPIRVCompiler *spv;
int max_num_mbs, err;
max_num_mbs = (avctx->coded_width >> 4) * (avctx->coded_height >> 4);
- spv = ff_vk_spirv_init();
- if (!spv) {
- av_log(avctx, AV_LOG_ERROR, "Unable to initialize SPIR-V compiler!\n");
- return AVERROR_EXTERNAL;
- }
-
err = ff_vk_decode_init(avctx);
if (err < 0)
return err;
@@ -554,15 +491,11 @@ static int vk_decode_prores_init(AVCodecContext *avctx)
ctx->sd_ctx_free = vk_decode_prores_uninit;
RET(init_decode_shader(avctx, &ctx->s, &ctx->exec_pool,
- spv, &pv->vld, max_num_mbs, pr->frame_type != 0));
+ &pv->vld, max_num_mbs, pr->frame_type != 0));
RET(init_idct_shader(avctx, &ctx->s, &ctx->exec_pool,
- spv, &pv->idct, max_num_mbs, pr->frame_type != 0));
-
- err = 0;
+ &pv->idct, max_num_mbs, pr->frame_type != 0));
fail:
- spv->uninit(&spv);
-
return err;
}
--
2.49.1
_______________________________________________
ffmpeg-devel mailing list -- ffmpeg-devel@ffmpeg.org
To unsubscribe send an email to ffmpeg-devel-leave@ffmpeg.org
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2026-01-02 14:44 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-01-02 14:42 [FFmpeg-devel] [PR] vulkan: convert ProRes, ProRes RAW and 2 filters to compile-time SPIR-V generation (PR #21356) Lynne via ffmpeg-devel
Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
This inbox may be cloned and mirrored by anyone:
git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git
# If you have public-inbox 1.1+ installed, you may
# initialize and index your mirror using the following commands:
public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \
ffmpegdev@gitmailbox.com
public-inbox-index ffmpegdev
Example config snippet for mirrors.
AGPL code for this site: git clone https://public-inbox.org/public-inbox.git