This is an automated email from the git hooks/post-receive script. Git pushed a commit to branch master in repository ffmpeg.
commit 03e58384a6a54ce5db54681141f1ed517981a64c Author: Lynne <[email protected]> AuthorDate: Tue Sep 22 01:20:02 2026 +0900 Commit: Lynne <[email protected]> CommitDate: Wed Sep 23 00:30:52 2026 +0900 vulkan/prores_ks_estimate_slice: keep the planes of a slice within one subgroup The estimate sums the planes of a slice with subgroup shuffles, so their lanes must share a subgroup, which the workgroup size derived from the maximum subgroup size did not guarantee. Size the workgroup to a single subgroup and pin its size where the device allows it. The overquant search also ran the shuffles inside a loop the slices leave at different iterations; ANV then sank the unused sum out of the loop, and every overquant slice scored zero. Keep the loop subgroup-uniform instead. Output on ANV is now identical to RADV. --- libavcodec/proresenc_kostya_vulkan.c | 17 +++++---- .../vulkan/prores_ks_estimate_slice.comp.glsl | 41 ++++++++++++---------- 2 files changed, 34 insertions(+), 24 deletions(-) diff --git a/libavcodec/proresenc_kostya_vulkan.c b/libavcodec/proresenc_kostya_vulkan.c index 2668d040f2..a8eb7d56bd 100644 --- a/libavcodec/proresenc_kostya_vulkan.c +++ b/libavcodec/proresenc_kostya_vulkan.c @@ -119,6 +119,7 @@ typedef struct ProresVulkanContext { AVRefStructPool *frame_size_buf_pool; size_t slice_slot_size; + int estimate_slices_per_wg; int payload_off; FFVulkanShader alpha_data_shd; @@ -244,8 +245,13 @@ static int init_estimate_slice_pipeline(ProresVulkanContext *pv, FFVulkanShader* int err = 0; FFVulkanContext *vkctx = &pv->vkctx; FFVulkanDescriptorSetBinding *desc; - int subgroup_size = vkctx->subgroup_props.maxSubgroupSize; - int dim_x = pv->ctx.alpha_bits ? subgroup_size : (subgroup_size / 3) * 3; + /* A single subgroup per workgroup, pinned to its size where possible */ + int required = vkctx->subgroup_props.requiredSubgroupSizeStages & + VK_SHADER_STAGE_COMPUTE_BIT; + int dim_x = required ? vkctx->subgroup_props.maxSubgroupSize : + vkctx->subgroup_props.minSubgroupSize; + + pv->estimate_slices_per_wg = dim_x / pv->ctx.num_planes; SPEC_LIST_CREATE(sl, 8, 8 * sizeof(uint32_t)) SPEC_LIST_ADD(sl, 0, 32, pv->ctx.mbs_per_slice); @@ -258,7 +264,7 @@ static int init_estimate_slice_pipeline(ProresVulkanContext *pv, FFVulkanShader* SPEC_LIST_ADD(sl, 7, 32, pv->ctx.bits_per_mb); ff_vk_shader_load(shd, VK_SHADER_STAGE_COMPUTE_BIT, sl, - (uint32_t []) { dim_x, 1, 1 }, 0); + (uint32_t []) { dim_x, 1, 1 }, required ? dim_x : 0); desc = (FFVulkanDescriptorSetBinding []) { { @@ -424,8 +430,6 @@ static int vulkan_encode_prores_submit_frame(AVCodecContext *avctx, FFVkExecCont int err = 0, nb_img_bar = 0, i, is_chroma; int min_quant = ctx->profile_info->min_quant; int max_quant = ctx->profile_info->max_quant; - int subgroup_size = vkctx->subgroup_props.maxSubgroupSize; - int estimate_dim_x = ctx->alpha_bits ? subgroup_size : (subgroup_size / 3) * 3; const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(vkctx->frames->sw_format); VkImageView views[AV_NUM_DATA_POINTERS]; VkImageMemoryBarrier2 img_bar[AV_NUM_DATA_POINTERS]; @@ -579,7 +583,8 @@ static int vulkan_encode_prores_submit_frame(AVCodecContext *avctx, FFVkExecCont &pv->prores_data_tables_buf, 0, pv->prores_data_tables_buf.size, VK_FORMAT_UNDEFINED); ff_vk_exec_bind_shader(vkctx, exec, &pv->estimate_slice_shd); - vk->CmdDispatch(exec->buf, (ctx->slices_per_picture * ctx->num_planes + estimate_dim_x - 1) / estimate_dim_x, + vk->CmdDispatch(exec->buf, (ctx->slices_per_picture + pv->estimate_slices_per_wg - 1) / + pv->estimate_slices_per_wg, ctx->force_quant ? 1 : (max_quant - min_quant + 1), 1); /* Wait for writes to score buffer. */ diff --git a/libavcodec/vulkan/prores_ks_estimate_slice.comp.glsl b/libavcodec/vulkan/prores_ks_estimate_slice.comp.glsl index 01d2531584..be0f95a9bd 100644 --- a/libavcodec/vulkan/prores_ks_estimate_slice.comp.glsl +++ b/libavcodec/vulkan/prores_ks_estimate_slice.comp.glsl @@ -23,6 +23,7 @@ #extension GL_EXT_shader_explicit_arithmetic_types : require #extension GL_KHR_shader_subgroup_clustered : require #extension GL_KHR_shader_subgroup_shuffle : require +#extension GL_KHR_shader_subgroup_vote : require #extension GL_EXT_maximal_reconvergence : require #extension GL_GOOGLE_include_directive : require @@ -236,10 +237,12 @@ int sum_of_planes(int value) void main() [[maximally_reconverges]] { - uint slice = gl_GlobalInvocationID.x / num_planes; + /* One lane per plane of a slice; the workgroup is a single subgroup */ + const uint slices_per_wg = gl_WorkGroupSize.x / num_planes; + uint slice = gl_WorkGroupID.x * slices_per_wg + gl_LocalInvocationID.x / num_planes; uint plane = gl_LocalInvocationID.x % num_planes; uint q = min_quant + gl_GlobalInvocationID.y; - if (slice >= slices_per_picture) + if (gl_LocalInvocationID.x >= slices_per_wg * num_planes || slice >= slices_per_picture) return; /* Estimate slice bits and error for specified quantizer and plane */ @@ -285,23 +288,25 @@ void main() [[maximally_reconverges]] scores[slice].score[max_quant + 1][plane] = error; scores[slice].overquant = int(max_quant); } else { - /* Keep searching until an encoding fits our budget */ - for (q = max_quant + 1; q < 128; ++q) { - /* Estimate slice bits and error for specified quantizer and plane */ - error = 0; - bits = 0; - if (plane == 3) - bits = estimate_alpha_plane(slice); - else - bits = estimate_slice_plane(error, slice, plane, q); - - /* Accumulate total bits and error of all planes */ - total_bits = sum_of_planes(bits); - total_score = sum_of_planes(error); + /* Keep searching until an encoding fits our budget. The loop stays + * subgroup-uniform, as the sums must not run under divergence. */ + bool done = false; + for (uint oq = max_quant + 1; oq < 128 && !subgroupAll(done); ++oq) { + int e = 0, b = 0; + if (!done) + b = plane == 3 ? estimate_alpha_plane(slice) : + estimate_slice_plane(e, slice, plane, oq); - /* If estimated bits fit within budget, we are done */ - if (total_bits <= bits_per_mb * mbs_per_slice) - break; + int tb = sum_of_planes(b); + int ts = sum_of_planes(e); + if (!done) { + bits = b; + error = e; + total_bits = tb; + total_score = ts; + q = oq; + done = total_bits <= bits_per_mb * mbs_per_slice; + } } scores[slice].bits[max_quant + 1][plane] = bits; -- To stop receiving notification emails like this one, please contact [email protected]. _______________________________________________ ffmpeg-cvslog mailing list -- [email protected] To unsubscribe send an email to [email protected]
