This is an automated email from the git hooks/post-receive script. Git pushed a commit to branch master in repository ffmpeg.
commit 540c4df5c7b85852b18b591353c0a475ae3e358e Author: Lynne <[email protected]> AuthorDate: Fri Jan 2 04:26:36 2026 +0100 Commit: Lynne <[email protected]> CommitDate: Mon Jan 12 17:28:40 2026 +0100 vulkan: add support for precompiled shaders --- libavutil/vulkan.c | 113 ++++++++++++++++++++++++++++++++++++++++------------- libavutil/vulkan.h | 49 ++++++++++++++++++++++- 2 files changed, 133 insertions(+), 29 deletions(-) diff --git a/libavutil/vulkan.c b/libavutil/vulkan.c index de7fe4f73d..59d25db8f0 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; @@ -2210,7 +2221,7 @@ static int init_pipeline_layout(FFVulkanContext *s, FFVulkanShader *shd) static int create_shader_module(FFVulkanContext *s, FFVulkanShader *shd, VkShaderModule *mod, - uint8_t *spirv, size_t spirv_len) + const uint8_t *spirv, size_t spirv_len) { VkResult ret; FFVulkanFunctions *vk = &s->vkfn; @@ -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, }, }; @@ -2270,12 +2282,11 @@ static int init_compute_pipeline(FFVulkanContext *s, FFVulkanShader *shd, } static int create_shader_object(FFVulkanContext *s, FFVulkanShader *shd, - uint8_t *spirv, size_t spirv_len, - const char *entrypoint) + const uint8_t *spirv, size_t spirv_len, + size_t *binary_size, const char *entrypoint) { VkResult ret; FFVulkanFunctions *vk = &s->vkfn; - size_t shader_size = 0; VkShaderCreateInfoEXT shader_obj_create = { .sType = VK_STRUCTURE_TYPE_SHADER_CREATE_INFO_EXT, @@ -2291,7 +2302,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, @@ -2303,9 +2314,8 @@ static int create_shader_object(FFVulkanContext *s, FFVulkanShader *shd, } if (vk->GetShaderBinaryDataEXT(s->hwctx->act_dev, shd->object, - &shader_size, NULL) == VK_SUCCESS) - av_log(s, AV_LOG_VERBOSE, "Shader %s size: %zu binary (%zu SPIR-V)\n", - shd->name, shader_size, spirv_len); + binary_size, NULL) != VK_SUCCESS) + return AVERROR_EXTERNAL; return 0; } @@ -2371,19 +2381,48 @@ 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; + size_t binary_size = 0; + + 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 = 253 + 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) - 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++) @@ -2391,14 +2430,15 @@ 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); + err = create_shader_object(s, shd, spirv, spirv_len, + &binary_size, entrypoint); if (err < 0) - return err; + goto end; } 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: @@ -2408,15 +2448,31 @@ int ff_vk_shader_link(FFVulkanContext *s, FFVulkanShader *shd, av_log(s, AV_LOG_ERROR, "Unsupported shader type: %i\n", shd->bind_point); err = AVERROR(EINVAL); + goto end; break; }; vk->DestroyShaderModule(s->hwctx->act_dev, mod, s->hwctx->alloc); if (err < 0) - return err; + goto end; } - return 0; + if (shd->name) + av_log(s, AV_LOG_VERBOSE, "Shader %s linked, size:", shd->name); + else + av_log(s, AV_LOG_VERBOSE, "Shader linked, size:"); + + av_log(s, AV_LOG_VERBOSE, " %zu SPIR-V", spirv_len); + if (binary_size != spirv_len) + av_log(s, AV_LOG_VERBOSE, ", %zu binary", spirv_len); + av_log(s, AV_LOG_VERBOSE, "\n"); + +end: + if (shd->precompiled) { + shd->specialization_info->mapEntryCount -= 3; + shd->specialization_info->dataSize -= 3*sizeof(uint32_t); + } + return err; } static const struct descriptor_props { @@ -2488,6 +2544,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 9bc2ff8fad..c56cd93e18 100644 --- a/libavutil/vulkan.h +++ b/libavutil/vulkan.h @@ -28,6 +28,8 @@ #include "hwcontext.h" #include "vulkan_functions.h" #include "hwcontext_vulkan.h" +#include "avassert.h" +#include "intreadwrite.h" /* GLSL management macros */ #define INDENT(N) INDENT_##N @@ -69,6 +71,36 @@ goto fail; \ } while (0) +/* Convenience macros for specialization lists */ +#define SPEC_LIST_MAX 256 +#define SPEC_LIST_CREATE(name, max_length, max_size) \ + av_assert1((max_length) < (SPEC_LIST_MAX - 3)); \ + uint8_t name##_data[(max_size) + 3*sizeof(uint32_t)]; \ + VkSpecializationMapEntry name##_entries[(max_length) + 3]; \ + VkSpecializationInfo name##_info = { \ + .pMapEntries = name##_entries, \ + .pData = name##_data, \ + }; \ + VkSpecializationInfo *name = &name##_info; + +#define SPEC_LIST_ADD(name, idx, val_bits, val) \ +do { \ + unsigned int name##_cnt = name->mapEntryCount; \ + size_t name##_off = name->dataSize; \ + uint8_t *name##_dp = (uint8_t *)name->pData; \ + void *name##_ep = (void *)&name->pMapEntries[name##_cnt]; \ + AV_WN(val_bits, name##_dp + name##_off, (val)); \ + VkSpecializationMapEntry name##_new_entry = { \ + .constantID = (idx), \ + .offset = name##_off, \ + .size = val_bits >> 3, \ + }; \ + memcpy(name##_ep, &name##_new_entry, \ + sizeof(VkSpecializationMapEntry)); \ + name->dataSize = name##_off + (val_bits >> 3); \ + name->mapEntryCount = name##_cnt + 1; \ +} while (0) + #define DUP_SAMPLER(x) { x, x, x, x } #define FF_VK_MAX_DESCRIPTOR_SETS 4 @@ -194,11 +226,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 +644,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. + * If spec is non-null, it must have been created with SPEC_LIST_CREATE(). + * The IDs for the workgroup size must be 253, 254, 255. + */ +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 +663,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); /** _______________________________________________ ffmpeg-cvslog mailing list -- [email protected] To unsubscribe send an email to [email protected]
