mirror of
https://git.ffmpeg.org/ffmpeg.git
synced 2026-10-24 02:09:03 +03:00
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.
This commit is contained in:
@@ -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. */
|
||||
|
||||
@@ -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);
|
||||
/* 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);
|
||||
|
||||
/* Accumulate total bits and error of all planes */
|
||||
total_bits = sum_of_planes(bits);
|
||||
total_score = sum_of_planes(error);
|
||||
|
||||
/* 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;
|
||||
|
||||
Reference in New Issue
Block a user