This is an automated email from the git hooks/post-receive script. Git pushed a commit to branch master in repository ffmpeg.
commit 8465572d7d66be6d39af15eca0cffe5968a79209 Author: Lynne <[email protected]> AuthorDate: Wed Sep 23 02:15:58 2026 +0900 Commit: Lynne <[email protected]> CommitDate: Thu Sep 24 11:05:30 2026 +0900 proresenc_kostya_vulkan: gather the second field in place The second field follows the first field's payload, whose size is only known on the GPU, so it was gathered into a scratch buffer and copied into the packet by the CPU. Let the gather add an offset it reads from GPU memory, and point it at the size the first field's gather wrote. --- libavcodec/apv_encode_vulkan.c | 2 +- libavcodec/ffv1enc_vulkan.c | 2 +- libavcodec/proresenc_kostya_vulkan.c | 62 +++++++++++++--------------------- libavcodec/vulkan/seg_gather.comp.glsl | 10 +++--- libavcodec/vulkan_video.c | 11 +++--- libavcodec/vulkan_video.h | 6 ++-- 6 files changed, 43 insertions(+), 50 deletions(-) diff --git a/libavcodec/apv_encode_vulkan.c b/libavcodec/apv_encode_vulkan.c index 8b078bce39..8c703b3324 100644 --- a/libavcodec/apv_encode_vulkan.c +++ b/libavcodec/apv_encode_vulkan.c @@ -517,7 +517,7 @@ static int submit_frame(AVCodecContext *avctx, FFVkExecContext *exec, RET(ff_vk_seg_gather(&ev->s, exec, &ev->shd_compact, sizes_buf, 0, ev->tile_count * ev->num_comp, bytestream_buf, ev->slot_size, - compacted_buf, 0)); + compacted_buf, 0, 0)); err = ff_vk_exec_submit(&ev->s, exec); if (err < 0) diff --git a/libavcodec/ffv1enc_vulkan.c b/libavcodec/ffv1enc_vulkan.c index a0d8ac035f..b7524d2bc0 100644 --- a/libavcodec/ffv1enc_vulkan.c +++ b/libavcodec/ffv1enc_vulkan.c @@ -684,7 +684,7 @@ static int vulkan_encode_ffv1_submit_frame(AVCodecContext *avctx, &fv->results_buf, fd->idx*(f->max_slice_count + 1)*sizeof(uint32_t), f->slice_count, out_data_buf, (out_data_buf->size / f->slice_count) & ~(size_t)15, - compacted_buf, 0)); + compacted_buf, 0, 0)); /* Submit */ ff_vk_exec_move_dep_refstruct(&fv->s, exec, &slice_data_buf); diff --git a/libavcodec/proresenc_kostya_vulkan.c b/libavcodec/proresenc_kostya_vulkan.c index b92170f41e..e8ddcc4d71 100644 --- a/libavcodec/proresenc_kostya_vulkan.c +++ b/libavcodec/proresenc_kostya_vulkan.c @@ -82,7 +82,7 @@ typedef struct VulkanEncodeProresFrameData { /* Intermediate buffers */ FFVkBuffer *out_data_ref[2]; FFVkBuffer *slice_sizes_ref[2]; - FFVkBuffer *gathered_ref[2]; + FFVkBuffer *gathered_ref; FFVkBuffer *slice_data_ref[2]; FFVkBuffer *slice_score_ref[2]; FFVkBuffer *frame_size_ref[2]; @@ -413,17 +413,16 @@ static int encode_picture(AVCodecContext *avctx, FFVkExecContext *exec, VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)); ff_vk_exec_add_dep_refstruct(vkctx, exec, pd->slice_sizes_ref[picture_idx]); - /* Picture 0 is gathered directly into the packet buffer at its static - * offset; picture 1's offset depends on picture 0's encoded size, so it - * is gathered to a scratch buffer and moved into place by the CPU. */ - RET(ff_vk_get_pooled_buffer(vkctx, &pv->gathered_buf_pool, &pd->gathered_ref[picture_idx], - VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | - VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, NULL, - picture_idx == 0 ? ctx->frame_size_upper_bound + FF_INPUT_BUFFER_MIN_SIZE - : ctx->slices_per_picture * pv->slice_slot_size, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | - vkctx->host_cached_flag)); - ff_vk_exec_add_dep_refstruct(vkctx, exec, pd->gathered_ref[picture_idx]); + /* Both pictures are gathered directly into the packet buffer */ + if (!picture_idx) { + RET(ff_vk_get_pooled_buffer(vkctx, &pv->gathered_buf_pool, &pd->gathered_ref, + VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | + VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, NULL, + ctx->frame_size_upper_bound + FF_INPUT_BUFFER_MIN_SIZE, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | + vkctx->host_cached_flag)); + ff_vk_exec_add_dep_refstruct(vkctx, exec, pd->gathered_ref); + } /* Allocate buffer for writing slice data */ RET(ff_vk_get_pooled_buffer(vkctx, &pv->slice_data_buf_pool, &pd->slice_data_ref[picture_idx], @@ -607,12 +606,14 @@ static int encode_picture(AVCodecContext *avctx, FFVkExecContext *exec, ctx->num_planes, 1); /* Gather the sparse slots into the contiguous bitstream, in the same - * submission. */ + * submission. Picture 1 follows the header and seek table after + * picture 0's payload, whose size the gather of picture 0 wrote. */ RET(ff_vk_seg_gather(vkctx, exec, &pv->gather_shd, pd->slice_sizes_ref[picture_idx], 0, ctx->slices_per_picture, - pkt_vk_buf, pv->slice_slot_size, - pd->gathered_ref[picture_idx], - picture_idx == 0 ? pv->payload_off : 0)); + pkt_vk_buf, pv->slice_slot_size, pd->gathered_ref, + pv->payload_off + picture_idx * (8 + ctx->slices_per_picture * 2), + picture_idx ? pd->slice_sizes_ref[0]->address + + ctx->slices_per_picture * sizeof(uint32_t) : 0)); fail: return err; @@ -675,8 +676,8 @@ static int get_packet(AVCodecContext *avctx, FFVkExecContext *exec, AVPacket *pk VulkanEncodeProresFrameData *pd = exec->opaque; FFVulkanContext *vkctx = &pv->vkctx; FFVulkanFunctions *vk = &vkctx->vkfn; - FFVkBuffer *wrap_buf = pd->gathered_ref[0]; - uint8_t *orig_buf, *buf, *slice_sizes; + FFVkBuffer *wrap_buf = pd->gathered_ref; + uint8_t *orig_buf, *buf; uint8_t *picture_size_pos; int picture_idx; int frame_size, picture_size; @@ -728,29 +729,14 @@ static int get_packet(AVCodecContext *avctx, FFVkExecContext *exec, AVPacket *pk /* Write the seek table from the per-slice sizes; the payload itself * was already packed to match by the gather pass. */ - slice_sizes = buf; sizes = (const uint32_t *)slice_sizes_buf->mapped_mem; for (int i = 0; i < ctx->slices_per_picture; i++) bytestream_put_be16(&buf, sizes[i]); + av_assert1(picture_idx || buf - wrap_buf->mapped_mem == pv->payload_off); /* Calculate final size */ buf += *(int*)frame_size_buf->mapped_mem; - if (picture_idx == 0) { - av_assert1(((slice_sizes + ctx->slices_per_picture * 2) - - wrap_buf->mapped_mem) == pv->payload_off); - } else { - /* Relocate the second picture's payload from its scratch buffer */ - FFVkBuffer *scratch = pd->gathered_ref[1]; - if (!(scratch->flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) { - invalidate_data.memory = scratch->mem; - vk->InvalidateMappedMemoryRanges(vkctx->hwctx->act_dev, 1, &invalidate_data); - } - memcpy(slice_sizes + ctx->slices_per_picture * 2, scratch->mapped_mem, - buf - (slice_sizes + ctx->slices_per_picture * 2)); - av_refstruct_unref(&pd->gathered_ref[1]); - } - /* Write picture size with header */ picture_size = buf - (picture_size_pos - 1); bytestream_put_be32(&picture_size_pos, picture_size); @@ -773,12 +759,12 @@ static int get_packet(AVCodecContext *avctx, FFVkExecContext *exec, AVPacket *pk /* Hand the buffer to the packet with no copy: pkt->buf references the * pooled Vulkan buffer, returned to its pool when the packet is freed. */ pkt->buf = av_buffer_create(wrap_buf->mapped_mem, wrap_buf->size, - prores_vk_packet_free, pd->gathered_ref[0], 0); + prores_vk_packet_free, pd->gathered_ref, 0); if (!pkt->buf) { - av_refstruct_unref(&pd->gathered_ref[0]); + av_refstruct_unref(&pd->gathered_ref); return AVERROR(ENOMEM); } - pd->gathered_ref[0] = NULL; /* ownership passed to pkt->buf */ + pd->gathered_ref = NULL; /* ownership passed to pkt->buf */ pkt->data = wrap_buf->mapped_mem; pkt->size = frame_size; @@ -852,11 +838,11 @@ static av_cold int encode_close(AVCodecContext *avctx) for (int j = 0; j < 2; j++) { av_refstruct_unref(&pd->out_data_ref[j]); av_refstruct_unref(&pd->slice_sizes_ref[j]); - av_refstruct_unref(&pd->gathered_ref[j]); av_refstruct_unref(&pd->slice_data_ref[j]); av_refstruct_unref(&pd->slice_score_ref[j]); av_refstruct_unref(&pd->frame_size_ref[j]); } + av_refstruct_unref(&pd->gathered_ref); } av_freep(&pv->exec_ctx_info); } diff --git a/libavcodec/vulkan/seg_gather.comp.glsl b/libavcodec/vulkan/seg_gather.comp.glsl index 0a3c6cbf42..073c43536b 100644 --- a/libavcodec/vulkan/seg_gather.comp.glsl +++ b/libavcodec/vulkan/seg_gather.comp.glsl @@ -46,9 +46,10 @@ layout (set = 0, binding = 0, scalar) buffer sizes_buf { }; layout (push_constant, scalar) uniform pushConstants { - u8buf sparse; /* one slot per segment */ - u8buf compacted; /* contiguous output */ - uint slot_size; /* stride between sparse slots */ + u8buf sparse; /* one slot per segment */ + u8buf compacted; /* contiguous output */ + uint64_t offset_addr; /* extra output offset, or 0 */ + uint slot_size; /* stride between sparse slots */ }; shared uint s_dst_off; @@ -110,7 +111,8 @@ void main(void) const uint n = seg_sizes[seg]; const uint64_t src_base = uint64_t(sparse) + seg * slot_size; - const uint64_t dst_base = uint64_t(compacted) + s_dst_off; + const uint base = offset_addr != 0ul ? u32buf(offset_addr).v : 0u; + const uint64_t dst_base = uint64_t(compacted) + base + s_dst_off; u8buf src8 = u8buf(src_base); u8buf dst8 = u8buf(dst_base); diff --git a/libavcodec/vulkan_video.c b/libavcodec/vulkan_video.c index a4b1caede4..1a52401d1c 100644 --- a/libavcodec/vulkan_video.c +++ b/libavcodec/vulkan_video.c @@ -548,6 +548,7 @@ fail: typedef struct SegGatherPushData { VkDeviceAddress sparse; VkDeviceAddress compacted; + VkDeviceAddress offset_addr; uint32_t slot_size; } SegGatherPushData; @@ -583,14 +584,16 @@ fail: int ff_vk_seg_gather(FFVulkanContext *s, FFVkExecContext *exec, FFVulkanShader *shd, FFVkBuffer *sizes, size_t sizes_offset, uint32_t nb_segs, FFVkBuffer *sparse, uint32_t slot_size, - FFVkBuffer *compacted, size_t compacted_offset) + FFVkBuffer *compacted, size_t compacted_offset, + VkDeviceAddress offset_addr) { int err; FFVulkanFunctions *vk = &s->vkfn; SegGatherPushData pd = { - .sparse = sparse->address, - .compacted = compacted->address + compacted_offset, - .slot_size = slot_size, + .sparse = sparse->address, + .compacted = compacted->address + compacted_offset, + .offset_addr = offset_addr, + .slot_size = slot_size, }; vk->CmdPipelineBarrier2(exec->buf, &(VkDependencyInfo) { diff --git a/libavcodec/vulkan_video.h b/libavcodec/vulkan_video.h index 467974d306..4c991863d2 100644 --- a/libavcodec/vulkan_video.h +++ b/libavcodec/vulkan_video.h @@ -146,12 +146,14 @@ int ff_vk_seg_gather_init(FFVulkanContext *s, FFVkExecPool *pool, * Gathers nb_segs slots of slot_size bytes from sparse into compacted, with * the segment sizes given as nb_segs uint32_t in sizes at sizes_offset, * followed by one more that receives the packed size. Both are made visible - * to the host. + * to the host. If offset_addr is non-zero, the uint32_t it points to is added + * to compacted_offset. */ int ff_vk_seg_gather(FFVulkanContext *s, FFVkExecContext *exec, FFVulkanShader *shd, FFVkBuffer *sizes, size_t sizes_offset, uint32_t nb_segs, FFVkBuffer *sparse, uint32_t slot_size, - FFVkBuffer *compacted, size_t compacted_offset); + FFVkBuffer *compacted, size_t compacted_offset, + VkDeviceAddress offset_addr); /** * Frame loop for compute encoders. Keeps up to pool_size frames in flight, -- 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]
