This is an automated email from the git hooks/post-receive script. Git pushed a commit to branch master in repository ffmpeg.
commit d49fcd7f82834c9668eb9b1ed682cb53ca824842 Author: Lynne <[email protected]> AuthorDate: Wed Sep 23 02:09:36 2026 +0900 Commit: Lynne <[email protected]> CommitDate: Thu Sep 24 11:05:26 2026 +0900 vulkan_video: add a shared segment gather The FFv1, APV and ProRes encoders each carried a copy of the same segment gather. Move it into ff_vk_seg_gather(), which also writes the packed size after the segment sizes, all that FFv1 needed from them, and makes the output visible to the host, which none of them did. Gather straight into the host-visible output, as ProRes already did. FFv1 and APV gathered into VRAM and copied the worst case out, but on a compute queue that copy is just another shader writing to system memory, after a round trip through VRAM. This also drops a worst-case VRAM buffer per frame in flight. At depth 1 on RADV, APV goes from 12 to 40 fps at 4K and from 44 to 175 fps at 1080p, and FFv1 from 42 to 131 fps at 1080p. --- libavcodec/apv_encode_vulkan.c | 126 +++--------------------------- libavcodec/ffv1enc_vulkan.c | 136 ++++----------------------------- libavcodec/proresenc_kostya_vulkan.c | 96 ++--------------------- libavcodec/vulkan/Makefile | 8 +- libavcodec/vulkan/seg_gather.comp.glsl | 7 +- libavcodec/vulkan_video.c | 86 +++++++++++++++++++++ libavcodec/vulkan_video.h | 17 +++++ 7 files changed, 149 insertions(+), 327 deletions(-) diff --git a/libavcodec/apv_encode_vulkan.c b/libavcodec/apv_encode_vulkan.c index c0b3999e43..0e0fc1abc7 100644 --- a/libavcodec/apv_encode_vulkan.c +++ b/libavcodec/apv_encode_vulkan.c @@ -30,6 +30,7 @@ #include "codec_internal.h" #include "encode.h" #include "hwconfig.h" +#include "vulkan_video.h" #include "internal.h" #include "apv.h" @@ -42,9 +43,6 @@ extern const unsigned int ff_apv_encode_dct_comp_spv_len; extern const unsigned char ff_apv_encode_tiles_comp_spv_data[]; extern const unsigned int ff_apv_encode_tiles_comp_spv_len; -extern const unsigned char ff_seg_gather_comp_spv_data[]; -extern const unsigned int ff_seg_gather_comp_spv_len; - #define APV_DEFAULT_QMAT 16 #define APV_MAX_NUM_COMP 4 @@ -71,12 +69,6 @@ typedef struct EntropyPushData { uint32_t blocks_per_mb; /* blocks per MB of this dispatch's components */ } EntropyPushData; -typedef struct CompactPushData { - VkDeviceAddress sparse; - VkDeviceAddress compacted; - uint32_t slot_size; -} CompactPushData; - typedef struct VulkanEncodeAPVFrameData { FFVkBuffer *coeffs_ref; FFVkBuffer *bytestream_ref; @@ -104,7 +96,6 @@ typedef struct VulkanEncodeAPVContext { /* Per-frame buffer pools */ AVRefStructPool *coeffs_pool; AVRefStructPool *bytestream_pool; - AVRefStructPool *gathered_pool; AVRefStructPool *compacted_pool; AVRefStructPool *sizes_pool; @@ -316,37 +307,6 @@ fail: return err; } -static int init_compact_shader(AVCodecContext *avctx) -{ - int err; - VulkanEncodeAPVContext *ev = avctx->priv_data; - FFVulkanShader *shd = &ev->shd_compact; - - ff_vk_shader_load(shd, VK_SHADER_STAGE_COMPUTE_BIT, NULL, - (uint32_t []) { 256, 1, 1 }, 0); - - ff_vk_shader_add_push_const(shd, 0, sizeof(CompactPushData), - VK_SHADER_STAGE_COMPUTE_BIT); - - const FFVulkanDescriptorSetBinding desc_set[] = { - { - .name = "sizes_buf", - .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, - .stages = VK_SHADER_STAGE_COMPUTE_BIT, - }, - }; - ff_vk_shader_add_descriptor_set(&ev->s, shd, desc_set, 1, 0); - - RET(ff_vk_shader_link(&ev->s, shd, - ff_seg_gather_comp_spv_data, - ff_seg_gather_comp_spv_len, "main")); - - RET(ff_vk_shader_register_exec(&ev->s, &ev->exec_pool, shd)); - -fail: - return err; -} - /* * The DCT/quantize shader's push constants are entirely encoder-constant: * frame geometry, the per-component quant scale qf, and the quantisation @@ -410,7 +370,6 @@ static int submit_frame(AVCodecContext *avctx, FFVkExecContext *exec, FFVkBuffer *coeffs_buf; FFVkBuffer *bytestream_buf; - FFVkBuffer *gathered_buf = NULL; FFVkBuffer *compacted_buf; FFVkBuffer *sizes_buf; @@ -437,22 +396,10 @@ static int submit_frame(AVCodecContext *avctx, FFVkExecContext *exec, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)); bytestream_buf = fd->bytestream_ref; - /* The compaction shader gathers the sparse slots into here, contiguous. - * Device-local: shader stores over the bus are unreliably slow on some - * drivers, so the transfer to the host is left to the copy engine. */ - RET(ff_vk_get_pooled_buffer(&ev->s, &ev->gathered_pool, - &gathered_buf, - VK_BUFFER_USAGE_TRANSFER_SRC_BIT | - VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | - VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, - NULL, ev->bytestream_size, - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)); - - /* Copy-engine destination the CPU assembles the packet from. - * Host-visible + host-cached so the readback is a fast cached copy. */ + /* The compaction shader gathers the sparse slots into here, and the CPU + * assembles the packet from it. */ RET(ff_vk_get_pooled_buffer(&ev->s, &ev->compacted_pool, &fd->compacted_ref, - VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, NULL, ev->bytestream_size, @@ -571,61 +518,14 @@ static int submit_frame(AVCodecContext *avctx, FFVkExecContext *exec, vk->CmdDispatch(exec->buf, ev->tile_cols, ev->tile_rows, z_comps); } - /* Compaction pass: gather the sparse per-tile-component slots into one - * contiguous device-local buffer, then read it back with the copy - * engine. */ - if (!ev->headers_only) { - ff_vk_buf_barrier(buf_bar[nb_buf_bar++], bytestream_buf, - COMPUTE_SHADER_BIT, SHADER_WRITE_BIT, NONE, - COMPUTE_SHADER_BIT, SHADER_READ_BIT, NONE, - 0, bytestream_buf->size); - ff_vk_buf_barrier(buf_bar[nb_buf_bar++], sizes_buf, - COMPUTE_SHADER_BIT, SHADER_WRITE_BIT, NONE, - COMPUTE_SHADER_BIT, SHADER_READ_BIT, NONE, - 0, sizes_buf->size); - vk->CmdPipelineBarrier2(exec->buf, &(VkDependencyInfo) { - .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, - .pBufferMemoryBarriers = buf_bar, - .bufferMemoryBarrierCount = nb_buf_bar, - }); - nb_buf_bar = 0; - - CompactPushData pd = { - .sparse = bytestream_buf->address, - .compacted = gathered_buf->address, - .slot_size = (uint32_t)ev->slot_size, - }; - - ff_vk_shader_update_desc_buffer(&ev->s, exec, &ev->shd_compact, - 0, 0, 0, - sizes_buf, 0, sizes_buf->size, - VK_FORMAT_UNDEFINED); - ff_vk_exec_bind_shader(&ev->s, exec, &ev->shd_compact); - ff_vk_shader_update_push_const(&ev->s, exec, &ev->shd_compact, - VK_SHADER_STAGE_COMPUTE_BIT, - 0, sizeof(pd), &pd); - - vk->CmdDispatch(exec->buf, ev->tile_count * ev->num_comp, 1, 1); - - /* The gathered size is only known once the encode is done, so the - * whole buffer is copied; the slots are sized to the entropy coder's - * worst case, which keeps this close to the payload size. */ - ff_vk_buf_barrier(buf_bar[nb_buf_bar++], gathered_buf, - COMPUTE_SHADER_BIT, SHADER_WRITE_BIT, NONE, - TRANSFER_BIT, TRANSFER_READ_BIT, NONE, - 0, gathered_buf->size); - vk->CmdPipelineBarrier2(exec->buf, &(VkDependencyInfo) { - .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, - .pBufferMemoryBarriers = buf_bar, - .bufferMemoryBarrierCount = nb_buf_bar, - }); - nb_buf_bar = 0; - - vk->CmdCopyBuffer(exec->buf, gathered_buf->buf, compacted_buf->buf, - 1, &(VkBufferCopy) { .size = ev->bytestream_size }); - } + /* Compaction pass: gather the sparse per-tile-component slots into the + * output buffer. */ + if (!ev->headers_only) + 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)); - ff_vk_exec_move_dep_refstruct(&ev->s, exec, &gathered_buf); err = ff_vk_exec_submit(&ev->s, exec); if (err < 0) return err; @@ -633,7 +533,6 @@ static int submit_frame(AVCodecContext *avctx, FFVkExecContext *exec, return 0; fail: - av_refstruct_unref(&gathered_buf); ff_vk_exec_discard(&ev->s, exec); return err; } @@ -869,7 +768,6 @@ static av_cold int vulkan_encode_apv_close(AVCodecContext *avctx) av_refstruct_pool_uninit(&ev->coeffs_pool); av_refstruct_pool_uninit(&ev->bytestream_pool); - av_refstruct_pool_uninit(&ev->gathered_pool); av_refstruct_pool_uninit(&ev->compacted_pool); av_refstruct_pool_uninit(&ev->sizes_pool); @@ -1002,7 +900,7 @@ static av_cold int vulkan_encode_apv_init(AVCodecContext *avctx) ev->slot_size = blocks_per_tile * APV_BLK_COEFFS * 8; ev->slot_size = FFALIGN(ev->slot_size, 64); ev->bytestream_size = (size_t)ev->tile_count * ev->num_comp * ev->slot_size; - ev->sizes_size = (size_t)ev->tile_count * ev->num_comp * sizeof(uint32_t); + ev->sizes_size = ((size_t)ev->tile_count * ev->num_comp + 1) * sizeof(uint32_t); av_log(avctx, AV_LOG_VERBOSE, "APV Vulkan encoder: %dx%d, %d tiles (%dx%d MBs each), " @@ -1056,7 +954,7 @@ static av_cold int vulkan_encode_apv_init(AVCodecContext *avctx) &ev->shd_entropy[1]); if (err < 0) return err; - err = init_compact_shader(avctx); + err = ff_vk_seg_gather_init(&ev->s, &ev->exec_pool, &ev->shd_compact); if (err < 0) return err; diff --git a/libavcodec/ffv1enc_vulkan.c b/libavcodec/ffv1enc_vulkan.c index f91bd0a6c1..83b3a140de 100644 --- a/libavcodec/ffv1enc_vulkan.c +++ b/libavcodec/ffv1enc_vulkan.c @@ -31,6 +31,7 @@ #include "ffv1.h" #include "ffv1enc.h" #include "ffv1_vulkan.h" +#include "vulkan_video.h" /* Parallel Golomb alignment */ #define LG_ALIGN_W 32 @@ -92,9 +93,6 @@ typedef struct VulkanEncodeFFv1Context { /* Output data buffer */ AVRefStructPool *out_data_pool; - /* Gathered (contiguous) device-local buffer pool */ - AVRefStructPool *gathered_data_pool; - /* Host-visible readback buffer pool */ AVRefStructPool *compacted_data_pool; @@ -113,12 +111,6 @@ typedef struct VulkanEncodeFFv1Context { int chunks; } VulkanEncodeFFv1Context; -typedef struct SegGatherPushData { - VkDeviceAddress sparse; - VkDeviceAddress compacted; - uint32_t slot_size; -} SegGatherPushData; - extern const char *ff_source_common_comp; extern const char *ff_source_rangecoder_comp; extern const char *ff_source_ffv1_vlc_comp; @@ -167,9 +159,6 @@ extern const unsigned int ff_ffv1_enc_bayer_comp_spv_len; extern const unsigned char ff_ffv1_enc_bayer_golomb_comp_spv_data[]; extern const unsigned int ff_ffv1_enc_bayer_golomb_comp_spv_len; -extern const unsigned char ff_seg_gather_comp_spv_data[]; -extern const unsigned int ff_seg_gather_comp_spv_len; - /* Size output slots with the v4 worst case; v3's ~(2*bits+5) bytes/sample runs * to gigabytes on large frames. The bitstream version is unaffected. */ static size_t ffv1_vk_buffer_size(AVCodecContext *avctx) @@ -303,7 +292,6 @@ static int vulkan_encode_ffv1_submit_frame(AVCodecContext *avctx, /* Output data */ size_t maxsize; FFVkBuffer *out_data_buf; - FFVkBuffer *gathered_buf = NULL; FFVkBuffer *compacted_buf; int has_inter = avctx->gop_size > 1; @@ -388,19 +376,10 @@ static int vulkan_encode_ffv1_submit_frame(AVCodecContext *avctx, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)); out_data_buf = fd->out_data_ref; - /* Device-local gather destination */ - RET(ff_vk_get_pooled_buffer(&fv->s, &fv->gathered_data_pool, - &gathered_buf, - VK_BUFFER_USAGE_TRANSFER_SRC_BIT | - VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | - VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, - NULL, maxsize, - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)); - /* Contiguous output, read back by the CPU. */ RET(ff_vk_get_pooled_buffer(&fv->s, &fv->compacted_data_pool, &fd->compacted_data_ref, - VK_BUFFER_USAGE_TRANSFER_DST_BIT, + VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, NULL, maxsize, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | fv->s.host_cached_flag)); @@ -673,7 +652,7 @@ static int vulkan_encode_ffv1_submit_frame(AVCodecContext *avctx, ff_vk_shader_update_desc_buffer(&fv->s, exec, &fv->enc, 1, 1, 0, &fv->results_buf, - fd->idx*f->max_slice_count*sizeof(uint32_t), + fd->idx*(f->max_slice_count + 1)*sizeof(uint32_t), f->slice_count*sizeof(uint32_t), VK_FORMAT_UNDEFINED); ff_vk_shader_update_desc_buffer(&fv->s, exec, &fv->enc, @@ -706,60 +685,16 @@ static int vulkan_encode_ffv1_submit_frame(AVCodecContext *avctx, 0, sizeof(FFv1ShaderParams), &pd); vk->CmdDispatch(exec->buf, fv->ctx.num_h_slices, fv->ctx.num_v_slices, 1); - /* Gather the per-slice slots into one contiguous buffer, in the same + /* Gather the per-slice slots into the packet buffer, in the same * submission. */ - FFVkBuffer *results_buf = &fv->results_buf; - ff_vk_buf_barrier(buf_bar[nb_buf_bar++], out_data_buf, - COMPUTE_SHADER_BIT, SHADER_WRITE_BIT, NONE_KHR, - COMPUTE_SHADER_BIT, SHADER_READ_BIT, NONE_KHR, - 0, VK_WHOLE_SIZE); - ff_vk_buf_barrier(buf_bar[nb_buf_bar++], results_buf, - COMPUTE_SHADER_BIT, SHADER_WRITE_BIT, NONE_KHR, - COMPUTE_SHADER_BIT, SHADER_READ_BIT, NONE_KHR, - 0, VK_WHOLE_SIZE); - vk->CmdPipelineBarrier2(exec->buf, &(VkDependencyInfo) { - .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, - .pBufferMemoryBarriers = buf_bar, - .bufferMemoryBarrierCount = nb_buf_bar, - }); - nb_buf_bar = 0; - - SegGatherPushData gather_pd = { - .sparse = out_data_buf->address, - .compacted = gathered_buf->address, - .slot_size = (uint32_t)((out_data_buf->size / f->slice_count) & ~(size_t)15), - }; - ff_vk_shader_update_desc_buffer(&fv->s, exec, &fv->gather, 0, 0, 0, - &fv->results_buf, - fd->idx*f->max_slice_count*sizeof(uint32_t), - f->slice_count*sizeof(uint32_t), - VK_FORMAT_UNDEFINED); - ff_vk_exec_bind_shader(&fv->s, exec, &fv->gather); - ff_vk_shader_update_push_const(&fv->s, exec, &fv->gather, - VK_SHADER_STAGE_COMPUTE_BIT, - 0, sizeof(gather_pd), &gather_pd); - vk->CmdDispatch(exec->buf, f->slice_count, 1, 1); - - /* Read the gathered bitstream back with the copy engine. The size is - * only known once the encode is done, so the whole buffer is copied; - * with the version-4 slot sizing this is close to the payload size. */ - ff_vk_buf_barrier(buf_bar[nb_buf_bar++], gathered_buf, - COMPUTE_SHADER_BIT, SHADER_WRITE_BIT, NONE_KHR, - TRANSFER_BIT, TRANSFER_READ_BIT, NONE_KHR, - 0, VK_WHOLE_SIZE); - vk->CmdPipelineBarrier2(exec->buf, &(VkDependencyInfo) { - .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, - .pBufferMemoryBarriers = buf_bar, - .bufferMemoryBarrierCount = nb_buf_bar, - }); - nb_buf_bar = 0; - - vk->CmdCopyBuffer(exec->buf, gathered_buf->buf, compacted_buf->buf, - 1, &(VkBufferCopy) { .size = maxsize }); + RET(ff_vk_seg_gather(&fv->s, exec, &fv->gather, + &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)); /* Submit */ ff_vk_exec_move_dep_refstruct(&fv->s, exec, &slice_data_buf); - ff_vk_exec_move_dep_refstruct(&fv->s, exec, &gathered_buf); if (remap_data_buf) ff_vk_exec_move_dep_refstruct(&fv->s, exec, &remap_data_buf); err = ff_vk_exec_submit(&fv->s, exec); @@ -778,7 +713,6 @@ fail: av_frame_free(&tmp); av_refstruct_unref(&slice_data_buf); av_refstruct_unref(&remap_data_buf); - av_refstruct_unref(&gathered_buf); return err; } @@ -802,27 +736,20 @@ static int get_packet(AVCodecContext *avctx, FFVkExecContext *exec, /* Make sure the encode + gather submission is done */ ff_vk_exec_wait(&fv->s, exec); - /* Invalidate the per-slice sizes if needed */ - uint32_t rb_off = fd->idx*f->max_slice_count*sizeof(uint32_t); + /* Invalidate the packed size if needed */ + size_t total_off = (fd->idx*(f->max_slice_count + 1) + f->slice_count)*sizeof(uint32_t); if (!(fv->results_buf.flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) { VkMappedMemoryRange invalidate_data = { .sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, .memory = fv->results_buf.mem, - .offset = rb_off, - .size = f->slice_count*sizeof(uint32_t), + .offset = total_off, + .size = sizeof(uint32_t), }; vk->InvalidateMappedMemoryRanges(fv->s.hwctx->act_dev, 1, &invalidate_data); } - /* The gather packed the slices tight and in order; sum their lengths. */ - pkt->size = 0; - uint8_t *rb = fv->results_buf.mapped_mem + rb_off; - for (int i = 0; i < f->slice_count; i++) { - uint32_t sl_len = AV_RN32(rb + i*4); - av_log(avctx, AV_LOG_DEBUG, "Slice %i size = %u\n", i, sl_len); - pkt->size += sl_len; - } + pkt->size = AV_RN32(fv->results_buf.mapped_mem + total_off); av_log(avctx, AV_LOG_VERBOSE, "Encoded data: %iMiB\n", pkt->size / (1024*1024)); /* Invalidate the gathered bitstream if needed */ @@ -1288,36 +1215,6 @@ fail: return err; } -static int init_gather_shader(AVCodecContext *avctx) -{ - int err; - VulkanEncodeFFv1Context *fv = avctx->priv_data; - FFVulkanShader *shd = &fv->gather; - - ff_vk_shader_load(shd, VK_SHADER_STAGE_COMPUTE_BIT, NULL, - (uint32_t []) { 256, 1, 1 }, 0); - - ff_vk_shader_add_push_const(shd, 0, sizeof(SegGatherPushData), - VK_SHADER_STAGE_COMPUTE_BIT); - - const FFVulkanDescriptorSetBinding desc_set[] = { - { /* sizes_buf */ - .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, - .stages = VK_SHADER_STAGE_COMPUTE_BIT, - }, - }; - ff_vk_shader_add_descriptor_set(&fv->s, shd, desc_set, 1, 0); - - RET(ff_vk_shader_link(&fv->s, shd, - ff_seg_gather_comp_spv_data, - ff_seg_gather_comp_spv_len, "main")); - - RET(ff_vk_shader_register_exec(&fv->s, &fv->exec_pool, shd)); - -fail: - return err; -} - static av_cold int vulkan_encode_ffv1_init(AVCodecContext *avctx) { int err; @@ -1521,7 +1418,7 @@ static av_cold int vulkan_encode_ffv1_init(AVCodecContext *avctx) return err; /* Gather shader */ - err = init_gather_shader(avctx); + err = ff_vk_seg_gather_init(&fv->s, &fv->exec_pool, &fv->gather); if (err < 0) return err; @@ -1572,7 +1469,7 @@ static av_cold int vulkan_encode_ffv1_init(AVCodecContext *avctx) /* Buffers */ RET(ff_vk_create_buf(&fv->s, &fv->results_buf, - fv->async_depth*f->max_slice_count*sizeof(uint32_t), + fv->async_depth*(f->max_slice_count + 1)*sizeof(uint32_t), NULL, NULL, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | @@ -1610,7 +1507,6 @@ static av_cold int vulkan_encode_ffv1_close(AVCodecContext *avctx) av_buffer_unref(&fv->intermediate_frames_ref); av_refstruct_pool_uninit(&fv->out_data_pool); - av_refstruct_pool_uninit(&fv->gathered_data_pool); av_refstruct_pool_uninit(&fv->compacted_data_pool); av_refstruct_unref(&fv->keyframe_slice_data_ref); diff --git a/libavcodec/proresenc_kostya_vulkan.c b/libavcodec/proresenc_kostya_vulkan.c index ff4df910c5..9449e88c4e 100644 --- a/libavcodec/proresenc_kostya_vulkan.c +++ b/libavcodec/proresenc_kostya_vulkan.c @@ -42,6 +42,7 @@ #include "proresdata.h" #include "proresenc_kostya_common.h" #include "hwconfig.h" +#include "vulkan_video.h" #define DCTSIZE 8 @@ -62,12 +63,6 @@ typedef struct EncodeSliceInfo { uint32_t slot_size; } EncodeSliceInfo; -typedef struct SegGatherPushData { - VkDeviceAddress sparse; - VkDeviceAddress compacted; - uint32_t slot_size; -} SegGatherPushData; - typedef struct SliceData { uint32_t mbs_per_slice; int16_t rows[MAX_PLANES * MAX_MBS_PER_SLICE * 256]; @@ -143,9 +138,6 @@ typedef struct ProresVulkanContext { extern const unsigned char ff_prores_ks_alpha_data_comp_spv_data[]; extern const unsigned int ff_prores_ks_alpha_data_comp_spv_len; -extern const unsigned char ff_seg_gather_comp_spv_data[]; -extern const unsigned int ff_seg_gather_comp_spv_len; - extern const unsigned char ff_prores_ks_slice_data_comp_spv_data[]; extern const unsigned int ff_prores_ks_slice_data_comp_spv_len; @@ -390,37 +382,6 @@ fail: return err; } -static int init_gather_pipeline(ProresVulkanContext *pv, FFVulkanShader *shd) -{ - int err = 0; - FFVulkanContext *vkctx = &pv->vkctx; - FFVulkanDescriptorSetBinding *desc; - - ff_vk_shader_load(shd, VK_SHADER_STAGE_COMPUTE_BIT, NULL, - (uint32_t []) { 256, 1, 1 }, 0); - - desc = (FFVulkanDescriptorSetBinding []) { - { - .name = "sizes_buf", - .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, - .stages = VK_SHADER_STAGE_COMPUTE_BIT, - }, - }; - ff_vk_shader_add_descriptor_set(vkctx, shd, desc, 1, 0); - - ff_vk_shader_add_push_const(shd, 0, sizeof(SegGatherPushData), - VK_SHADER_STAGE_COMPUTE_BIT); - - RET(ff_vk_shader_link(vkctx, shd, - ff_seg_gather_comp_spv_data, - ff_seg_gather_comp_spv_len, "main")); - - RET(ff_vk_shader_register_exec(vkctx, &pv->e, shd)); - -fail: - return err; -} - static int vulkan_encode_prores_submit_frame(AVCodecContext *avctx, FFVkExecContext *exec, AVFrame *frame, int picture_idx) { @@ -454,7 +415,7 @@ static int vulkan_encode_prores_submit_frame(AVCodecContext *avctx, FFVkExecCont RET(ff_vk_get_pooled_buffer(vkctx, &pv->slice_sizes_buf_pool, &pd->slice_sizes_ref[picture_idx], VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, NULL, - ctx->slices_per_picture * sizeof(uint32_t), + (ctx->slices_per_picture + 1) * sizeof(uint32_t), VK_MEMORY_PROPERTY_HOST_CACHED_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)); @@ -655,52 +616,11 @@ static int vulkan_encode_prores_submit_frame(AVCodecContext *avctx, FFVkExecCont /* Gather the sparse slots into the contiguous bitstream, in the same * submission. */ - VkBufferMemoryBarrier2 gather_bar[2] = { - { - .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2, - .srcStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, - .srcAccessMask = VK_ACCESS_2_SHADER_WRITE_BIT, - .dstStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, - .dstAccessMask = VK_ACCESS_2_SHADER_READ_BIT, - .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .buffer = pkt_vk_buf->buf, - .offset = 0, - .size = pkt_vk_buf->size, - }, { - .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2, - .srcStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, - .srcAccessMask = VK_ACCESS_2_SHADER_WRITE_BIT, - .dstStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, - .dstAccessMask = VK_ACCESS_2_SHADER_READ_BIT, - .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .buffer = pd->slice_sizes_ref[picture_idx]->buf, - .offset = 0, - .size = pd->slice_sizes_ref[picture_idx]->size, - }, - }; - vk->CmdPipelineBarrier2(exec->buf, &(VkDependencyInfo) { - .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, - .pBufferMemoryBarriers = gather_bar, - .bufferMemoryBarrierCount = 2, - }); - - SegGatherPushData gather_pd = { - .sparse = pkt_vk_buf->address, - .compacted = pd->gathered_ref[picture_idx]->address + - (picture_idx == 0 ? pv->payload_off : 0), - .slot_size = pv->slice_slot_size, - }; - ff_vk_shader_update_desc_buffer(vkctx, exec, &pv->gather_shd, 0, 0, 0, - pd->slice_sizes_ref[picture_idx], - 0, ctx->slices_per_picture * sizeof(uint32_t), - VK_FORMAT_UNDEFINED); - ff_vk_exec_bind_shader(vkctx, exec, &pv->gather_shd); - ff_vk_shader_update_push_const(vkctx, exec, &pv->gather_shd, - VK_SHADER_STAGE_COMPUTE_BIT, - 0, sizeof(gather_pd), &gather_pd); - vk->CmdDispatch(exec->buf, ctx->slices_per_picture, 1, 1); + 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)); fail: return err; @@ -1033,7 +953,7 @@ static av_cold int encode_init(AVCodecContext *avctx) init_estimate_slice_pipeline(pv, &pv->estimate_slice_shd); init_trellis_node_pipeline(pv, &pv->trellis_node_shd); init_encode_slice_pipeline(pv, &pv->encode_slice_shd); - init_gather_pipeline(pv, &pv->gather_shd); + RET(ff_vk_seg_gather_init(vkctx, &pv->e, &pv->gather_shd)); /* Size slots for the entropy coder's worst case; bits_per_mb is only a rate-control average */ { diff --git a/libavcodec/vulkan/Makefile b/libavcodec/vulkan/Makefile index 48afd639f4..a2ff2a4d6d 100644 --- a/libavcodec/vulkan/Makefile +++ b/libavcodec/vulkan/Makefile @@ -4,9 +4,10 @@ clean:: OBJS-$(CONFIG_APV_VULKAN_HWACCEL) += vulkan/apv_decode.comp.spv.o \ vulkan/apv_idct.comp.spv.o +OBJS-$(CONFIG_VULKAN) += vulkan/seg_gather.comp.spv.o + OBJS-$(CONFIG_APV_VULKAN_ENCODER) += vulkan/apv_encode_dct.comp.spv.o \ - vulkan/apv_encode_tiles.comp.spv.o \ - vulkan/seg_gather.comp.spv.o + vulkan/apv_encode_tiles.comp.spv.o OBJS-$(CONFIG_FFV1_VULKAN_ENCODER) += vulkan/ffv1_enc_setup.comp.spv.o \ vulkan/ffv1_enc_reset.comp.spv.o \ @@ -21,8 +22,7 @@ OBJS-$(CONFIG_FFV1_VULKAN_ENCODER) += vulkan/ffv1_enc_setup.comp.spv.o \ vulkan/ffv1_enc_rgb_float_golomb.comp.spv.o \ vulkan/ffv1_enc_sort32.comp.spv.o \ vulkan/ffv1_enc_bayer.comp.spv.o \ - vulkan/ffv1_enc_bayer_golomb.comp.spv.o \ - vulkan/seg_gather.comp.spv.o + vulkan/ffv1_enc_bayer_golomb.comp.spv.o OBJS-$(CONFIG_FFV1_VULKAN_HWACCEL) += vulkan/ffv1_dec_setup.comp.spv.o \ vulkan/ffv1_dec_reset.comp.spv.o \ diff --git a/libavcodec/vulkan/seg_gather.comp.glsl b/libavcodec/vulkan/seg_gather.comp.glsl index 5ee28097d6..0a3c6cbf42 100644 --- a/libavcodec/vulkan/seg_gather.comp.glsl +++ b/libavcodec/vulkan/seg_gather.comp.glsl @@ -37,9 +37,11 @@ * * One workgroup per segment. Inputs: the sparse slot buffer, the per-segment * sizes, and the slot stride. + * + * The last workgroup writes the packed size after the segment sizes. */ -layout (set = 0, binding = 0, scalar) readonly buffer sizes_buf { +layout (set = 0, binding = 0, scalar) buffer sizes_buf { uint32_t seg_sizes[]; }; @@ -141,4 +143,7 @@ void main(void) for (uint i = head + (nsafe << 4u) + b; i < n; i += wg) dst8[i].v = src8[i].v; + + if (seg == gl_NumWorkGroups.x - 1u && b == 0u) + seg_sizes[gl_NumWorkGroups.x] = s_dst_off + n; } diff --git a/libavcodec/vulkan_video.c b/libavcodec/vulkan_video.c index 44ad8e9233..838d681e64 100644 --- a/libavcodec/vulkan_video.c +++ b/libavcodec/vulkan_video.c @@ -543,3 +543,89 @@ fail: ff_vk_video_common_uninit(s, common); return err; } + +typedef struct SegGatherPushData { + VkDeviceAddress sparse; + VkDeviceAddress compacted; + uint32_t slot_size; +} SegGatherPushData; + +extern const unsigned char ff_seg_gather_comp_spv_data[]; +extern const unsigned int ff_seg_gather_comp_spv_len; + +int ff_vk_seg_gather_init(FFVulkanContext *s, FFVkExecPool *pool, + FFVulkanShader *shd) +{ + int err; + FFVulkanDescriptorSetBinding desc_set[] = { + { + .name = "sizes_buf", + .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + }, + }; + + ff_vk_shader_load(shd, VK_SHADER_STAGE_COMPUTE_BIT, NULL, + (uint32_t []) { 256, 1, 1 }, 0); + ff_vk_shader_add_push_const(shd, 0, sizeof(SegGatherPushData), + VK_SHADER_STAGE_COMPUTE_BIT); + ff_vk_shader_add_descriptor_set(s, shd, desc_set, 1, 0); + + RET(ff_vk_shader_link(s, shd, ff_seg_gather_comp_spv_data, + ff_seg_gather_comp_spv_len, "main")); + RET(ff_vk_shader_register_exec(s, pool, shd)); + +fail: + return err; +} + +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) +{ + int err; + FFVulkanFunctions *vk = &s->vkfn; + SegGatherPushData pd = { + .sparse = sparse->address, + .compacted = compacted->address + compacted_offset, + .slot_size = slot_size, + }; + + vk->CmdPipelineBarrier2(exec->buf, &(VkDependencyInfo) { + .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, + .pMemoryBarriers = &(VkMemoryBarrier2) { + .sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER_2, + .srcStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, + .srcAccessMask = VK_ACCESS_2_SHADER_WRITE_BIT, + .dstStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, + .dstAccessMask = VK_ACCESS_2_SHADER_READ_BIT | + VK_ACCESS_2_SHADER_WRITE_BIT, + }, + .memoryBarrierCount = 1, + }); + + RET(ff_vk_shader_update_desc_buffer(s, exec, shd, 0, 0, 0, + sizes, sizes_offset, (nb_segs + 1)*sizeof(uint32_t), + VK_FORMAT_UNDEFINED)); + ff_vk_exec_bind_shader(s, exec, shd); + ff_vk_shader_update_push_const(s, exec, shd, VK_SHADER_STAGE_COMPUTE_BIT, + 0, sizeof(pd), &pd); + vk->CmdDispatch(exec->buf, nb_segs, 1, 1); + + /* For the host to read the output and the packed size */ + vk->CmdPipelineBarrier2(exec->buf, &(VkDependencyInfo) { + .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, + .pMemoryBarriers = &(VkMemoryBarrier2) { + .sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER_2, + .srcStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, + .srcAccessMask = VK_ACCESS_2_SHADER_WRITE_BIT, + .dstStageMask = VK_PIPELINE_STAGE_2_HOST_BIT, + .dstAccessMask = VK_ACCESS_2_HOST_READ_BIT, + }, + .memoryBarrierCount = 1, + }); + +fail: + return err; +} diff --git a/libavcodec/vulkan_video.h b/libavcodec/vulkan_video.h index 15aefc7136..cc3fe41640 100644 --- a/libavcodec/vulkan_video.h +++ b/libavcodec/vulkan_video.h @@ -136,4 +136,21 @@ int ff_vk_video_common_init(AVCodecContext *avctx, FFVulkanContext *s, */ void ff_vk_video_common_uninit(FFVulkanContext *s, FFVkVideoCommon *common); +/** + * Packs fixed-stride segment slots back to back into a contiguous buffer. + */ +int ff_vk_seg_gather_init(FFVulkanContext *s, FFVkExecPool *pool, + FFVulkanShader *shd); + +/** + * 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. + */ +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); + #endif /* AVCODEC_VULKAN_VIDEO_H */ -- 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]
