This is an automated email from the git hooks/post-receive script.

Git pushed a commit to branch master
in repository ffmpeg.

commit 56d60b54196bd0b9e3d187385822acf4f9d3dbc9
Author:     Lynne <[email protected]>
AuthorDate: Thu Jul 30 23:44:44 2026 +0900
Commit:     Lynne <[email protected]>
CommitDate: Wed Aug 5 16:04:37 2026 +0900

    proresenc_kostya_vulkan: gather slices on the GPU
    
    Same as with APV, and FFv1.
    1080p on RADV goes from 34 to 48 fps, 4K goes from 20 to 31 fps.
---
 libavcodec/proresenc_kostya_vulkan.c               | 314 +++++++++++++++------
 libavcodec/vulkan/prores_ks_encode_slice.comp.glsl |  11 +-
 2 files changed, 233 insertions(+), 92 deletions(-)

diff --git a/libavcodec/proresenc_kostya_vulkan.c 
b/libavcodec/proresenc_kostya_vulkan.c
index 97a107b8ea..de4b34efc2 100644
--- a/libavcodec/proresenc_kostya_vulkan.c
+++ b/libavcodec/proresenc_kostya_vulkan.c
@@ -21,6 +21,7 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
+#include "libavutil/avassert.h"
 #include "libavutil/buffer.h"
 #include "libavutil/macros.h"
 #include "libavutil/mem.h"
@@ -57,9 +58,16 @@ typedef struct SliceDataInfo {
 
 typedef struct EncodeSliceInfo {
     VkDeviceAddress bytestream;
-    VkDeviceAddress seek_table;
+    VkDeviceAddress slice_sizes;
+    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];
@@ -78,6 +86,8 @@ typedef struct SliceScore {
 typedef struct VulkanEncodeProresFrameData {
     /* Intermediate buffers */
     FFVkBuffer *out_data_ref[2];
+    FFVkBuffer *slice_sizes_ref[2];
+    FFVkBuffer *gathered_ref[2];
     FFVkBuffer *slice_data_ref[2];
     FFVkBuffer *slice_score_ref[2];
     FFVkBuffer *frame_size_ref[2];
@@ -101,18 +111,22 @@ typedef struct ProresVulkanContext {
     FFVulkanContext vkctx;
     AVVulkanDeviceQueueFamily *qf;
     FFVkExecPool e;
-    AVVulkanDeviceQueueFamily *transfer_qf;
-    FFVkExecPool transfer_exec_pool;
     AVRefStructPool *pkt_buf_pool;
+    AVRefStructPool *slice_sizes_buf_pool;
+    AVRefStructPool *gathered_buf_pool;
     AVRefStructPool *slice_data_buf_pool;
     AVRefStructPool *slice_score_buf_pool;
     AVRefStructPool *frame_size_buf_pool;
 
+    size_t slice_slot_size;
+    int payload_off;
+
     FFVulkanShader alpha_data_shd;
     FFVulkanShader slice_data_shd[2];
     FFVulkanShader estimate_slice_shd;
     FFVulkanShader encode_slice_shd;
     FFVulkanShader trellis_node_shd;
+    FFVulkanShader gather_shd;
     FFVkBuffer prores_data_tables_buf;
 
     int *slice_quants;
@@ -128,6 +142,9 @@ 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;
 
@@ -364,6 +381,37 @@ 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)
 {
@@ -377,7 +425,6 @@ static int vulkan_encode_prores_submit_frame(AVCodecContext 
*avctx, FFVkExecCont
     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;
-    int transfer_slices = vkctx->extensions & FF_VK_EXT_EXTERNAL_HOST_MEMORY;
     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];
@@ -389,19 +436,38 @@ static int 
vulkan_encode_prores_submit_frame(AVCodecContext *avctx, FFVkExecCont
     /* Start recording */
     ff_vk_exec_start(vkctx, exec);
 
-    /* Get a pooled buffer for writing output data */
+    /* Sparse slice output: one fixed-stride, device-local slot per slice */
     RET(ff_vk_get_pooled_buffer(vkctx, &pv->pkt_buf_pool, 
&pd->out_data_ref[picture_idx],
                                 VK_BUFFER_USAGE_STORAGE_BUFFER_BIT |
-                                VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT |
-                                VK_BUFFER_USAGE_TRANSFER_SRC_BIT, NULL,
-                                ctx->frame_size_upper_bound + 
FF_INPUT_BUFFER_MIN_SIZE,
-                                transfer_slices ? 
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT
-                                                : 
(VK_MEMORY_PROPERTY_HOST_CACHED_BIT |
-                                                   
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
-                                                   
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)));
+                                VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, 
NULL,
+                                ctx->slices_per_picture * pv->slice_slot_size,
+                                VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT));
     pkt_vk_buf = pd->out_data_ref[picture_idx];
     ff_vk_exec_add_dep_refstruct(vkctx, exec, pd->out_data_ref[picture_idx]);
 
+    /* Per-slice sizes: read by the gather pass, and by the CPU to write the
+     * seek table. */
+    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),
+                                VK_MEMORY_PROPERTY_HOST_CACHED_BIT |
+                                VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
+                                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]);
+
     /* Allocate buffer for writing slice data */
     RET(ff_vk_get_pooled_buffer(vkctx, &pv->slice_data_buf_pool, 
&pd->slice_data_ref[picture_idx],
                                 VK_BUFFER_USAGE_STORAGE_BUFFER_BIT |
@@ -563,8 +629,9 @@ static int vulkan_encode_prores_submit_frame(AVCodecContext 
*avctx, FFVkExecCont
 
     /* Encode slices. */
     encode_info = (EncodeSliceInfo) {
-        .seek_table = pkt_vk_buf->address,
-        .bytestream = pkt_vk_buf->address + ctx->slices_per_picture * 2,
+        .bytestream  = pkt_vk_buf->address,
+        .slice_sizes = pd->slice_sizes_ref[picture_idx]->address,
+        .slot_size   = pv->slice_slot_size,
     };
     ff_vk_shader_update_desc_buffer(vkctx, exec, &pv->encode_slice_shd, 0, 0, 
0,
                                     slice_data_buf, 0, slice_data_buf->size,
@@ -581,6 +648,55 @@ static int 
vulkan_encode_prores_submit_frame(AVCodecContext *avctx, FFVkExecCont
     vk->CmdDispatch(exec->buf, FFALIGN(ctx->slices_per_picture, 64) / 64,
                                ctx->num_planes, 1);
 
+    /* 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);
+
 fail:
     return err;
 }
@@ -629,6 +745,12 @@ static uint8_t *write_frame_header(AVCodecContext *avctx, 
ProresContext *ctx,
     return buf;
 }
 
+/* Return the assembled-frame buffer to its pool when the packet is freed. */
+static void prores_vk_packet_free(void *opaque, uint8_t *data)
+{
+    av_refstruct_unref(&opaque);
+}
+
 static int get_packet(AVCodecContext *avctx, FFVkExecContext *exec, AVPacket 
*pkt)
 {
     ProresVulkanContext *pv = avctx->priv_data;
@@ -636,64 +758,49 @@ static int get_packet(AVCodecContext *avctx, 
FFVkExecContext *exec, AVPacket *pk
     VulkanEncodeProresFrameData *pd = exec->opaque;
     FFVulkanContext *vkctx = &pv->vkctx;
     FFVulkanFunctions *vk = &vkctx->vkfn;
-    FFVkExecContext *transfer_exec;
+    FFVkBuffer *wrap_buf = pd->gathered_ref[0];
     uint8_t *orig_buf, *buf, *slice_sizes;
     uint8_t *picture_size_pos;
-    int picture_idx, err = 0;
+    int picture_idx;
     int frame_size, picture_size;
-    int pkt_size = ctx->frame_size_upper_bound;
-    int transfer_slices = vkctx->extensions & FF_VK_EXT_EXTERNAL_HOST_MEMORY;
-    FFVkBuffer *out_data_buf, *frame_size_buf;
+    FFVkBuffer *frame_size_buf;
     VkMappedMemoryRange invalidate_data;
-    FFVkBuffer *mapped_buf = NULL;
-
-    /* Allocate packet */
-    RET(ff_get_encode_buffer(avctx, pkt, pkt_size + FF_INPUT_BUFFER_MIN_SIZE, 
0));
 
-    /* Initialize packet. */
-    pkt->pts      = pd->pts;
-    pkt->dts      = pd->pts;
-    pkt->duration = pd->duration;
-    pkt->flags   |= AV_PKT_FLAG_KEY * pd->key_frame;
+    /* Make sure encoding's done */
+    ff_vk_exec_wait(vkctx, exec);
 
-    if (avctx->flags & AV_CODEC_FLAG_COPY_OPAQUE) {
-        pkt->opaque          = pd->frame_opaque;
-        pkt->opaque_ref      = pd->frame_opaque_ref;
-        pd->frame_opaque_ref = NULL;
+    /* Invalidate the gathered bitstream if needed */
+    invalidate_data = (VkMappedMemoryRange) {
+        .sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
+        .offset = 0,
+        .size = VK_WHOLE_SIZE,
+    };
+    if (!(wrap_buf->flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) {
+        invalidate_data.memory = wrap_buf->mem;
+        vk->InvalidateMappedMemoryRanges(vkctx->hwctx->act_dev, 1, 
&invalidate_data);
     }
 
     /* Write frame atom */
-    orig_buf = pkt->data;
+    orig_buf = wrap_buf->mapped_mem;
     buf = write_frame_header(avctx,  ctx, &orig_buf, pd->flags,
                              pd->color_primaries, pd->color_trc,
                              pd->colorspace);
 
-    /* Make sure encoding's done */
-    ff_vk_exec_wait(vkctx, exec);
-
-    /* Roll transfer execution context */
-    if (transfer_slices) {
-        RET(ff_vk_host_map_buffer(vkctx, &mapped_buf, pkt->data, pkt->size,
-                                  pkt->buf, VK_BUFFER_USAGE_TRANSFER_DST_BIT));
-        transfer_exec = ff_vk_exec_get(vkctx, &pv->transfer_exec_pool);
-        ff_vk_exec_start(vkctx, transfer_exec);
-    }
-
     for (picture_idx = 0; picture_idx < ctx->pictures_per_frame; 
picture_idx++) {
-        /* Fetch buffers for the current picture. */
-        out_data_buf = pd->out_data_ref[picture_idx];
+        FFVkBuffer *slice_sizes_buf = pd->slice_sizes_ref[picture_idx];
+        const uint32_t *sizes;
+
         frame_size_buf = pd->frame_size_ref[picture_idx];
 
-        /* Invalidate slice/output data if needed */
-        invalidate_data = (VkMappedMemoryRange) {
-            .sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
-            .offset = 0,
-            .size = VK_WHOLE_SIZE,
-        };
+        /* Invalidate slice sizes if needed */
         if (!(frame_size_buf->flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) {
             invalidate_data.memory = frame_size_buf->mem;
             vk->InvalidateMappedMemoryRanges(vkctx->hwctx->act_dev, 1, 
&invalidate_data);
         }
+        if (!(slice_sizes_buf->flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) {
+            invalidate_data.memory = slice_sizes_buf->mem;
+            vk->InvalidateMappedMemoryRanges(vkctx->hwctx->act_dev, 1, 
&invalidate_data);
+        }
 
         /* Write picture header */
         picture_size_pos = buf + 1;
@@ -702,29 +809,29 @@ static int get_packet(AVCodecContext *avctx, 
FFVkExecContext *exec, AVPacket *pk
         bytestream_put_be16(&buf, ctx->slices_per_picture);
         bytestream_put_byte(&buf, av_log2(ctx->mbs_per_slice) << 4); // slice 
width and height in MBs
 
-        /* Skip over seek table */
+        /* Write the seek table from the per-slice sizes; the payload itself
+         * was already packed to match by the gather pass. */
         slice_sizes = buf;
-        buf += ctx->slices_per_picture * 2;
+        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]);
 
         /* Calculate final size */
         buf += *(int*)frame_size_buf->mapped_mem;
 
-        if (transfer_slices) {
-            /* Perform host mapped transfer of slice data */
-            ff_vk_exec_move_dep_refstruct(vkctx, transfer_exec, 
&pd->out_data_ref[picture_idx]);
-            vk->CmdCopyBuffer(transfer_exec->buf, out_data_buf->buf, 
mapped_buf->buf, 1, & (VkBufferCopy) {
-                .srcOffset = 0,
-                .dstOffset = mapped_buf->virtual_offset + slice_sizes - 
pkt->data,
-                .size = buf - slice_sizes,
-            });
+        if (picture_idx == 0) {
+            av_assert1(((slice_sizes + ctx->slices_per_picture * 2) -
+                        wrap_buf->mapped_mem) == pv->payload_off);
         } else {
-            /* Fallback to regular memcpy if transfer is not available */
-            if (!(out_data_buf->flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) 
{
-                invalidate_data.memory = out_data_buf->mem;
+            /* 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, out_data_buf->mapped_mem, buf - slice_sizes);
-            av_refstruct_unref(&pd->out_data_ref[picture_idx]);
+            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 */
@@ -732,6 +839,8 @@ static int get_packet(AVCodecContext *avctx, 
FFVkExecContext *exec, AVPacket *pk
         bytestream_put_be32(&picture_size_pos, picture_size);
 
         /* Slice output buffers no longer needed */
+        av_refstruct_unref(&pd->out_data_ref[picture_idx]);
+        av_refstruct_unref(&pd->slice_sizes_ref[picture_idx]);
         av_refstruct_unref(&pd->slice_data_ref[picture_idx]);
         av_refstruct_unref(&pd->slice_score_ref[picture_idx]);
         av_refstruct_unref(&pd->frame_size_ref[picture_idx]);
@@ -742,19 +851,34 @@ static int get_packet(AVCodecContext *avctx, 
FFVkExecContext *exec, AVPacket *pk
     frame_size = buf - orig_buf;
     bytestream_put_be32(&orig_buf, frame_size);
 
-    av_shrink_packet(pkt, frame_size);
-    av_log(avctx, AV_LOG_VERBOSE, "Encoded data: %iMiB\n", pkt->size / 
(1024*1024));
+    memset(buf, 0, AV_INPUT_BUFFER_PADDING_SIZE);
 
-    /* Wait for slice transfer */
-    if (transfer_slices) {
-        ff_vk_exec_move_dep_refstruct(vkctx, transfer_exec, &mapped_buf);
-        RET(ff_vk_exec_submit(vkctx, transfer_exec));
-        ff_vk_exec_wait(vkctx, transfer_exec);
+    /* 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);
+    if (!pkt->buf) {
+        av_refstruct_unref(&pd->gathered_ref[0]);
+        return AVERROR(ENOMEM);
     }
+    pd->gathered_ref[0] = NULL; /* ownership passed to pkt->buf */
+    pkt->data = wrap_buf->mapped_mem;
+    pkt->size = frame_size;
 
-fail:
-    av_refstruct_unref(&mapped_buf);
-    return err;
+    pkt->pts      = pd->pts;
+    pkt->dts      = pd->pts;
+    pkt->duration = pd->duration;
+    pkt->flags   |= AV_PKT_FLAG_KEY * pd->key_frame;
+
+    if (avctx->flags & AV_CODEC_FLAG_COPY_OPAQUE) {
+        pkt->opaque          = pd->frame_opaque;
+        pkt->opaque_ref      = pd->frame_opaque_ref;
+        pd->frame_opaque_ref = NULL;
+    }
+
+    av_log(avctx, AV_LOG_VERBOSE, "Encoded data: %iMiB\n", pkt->size / 
(1024*1024));
+
+    return 0;
 }
 
 static int vulkan_encode_prores_receive_packet(AVCodecContext *avctx, AVPacket 
*pkt)
@@ -827,7 +951,6 @@ static av_cold int encode_close(AVCodecContext *avctx)
     FFVulkanContext *vkctx = &pv->vkctx;
 
     ff_vk_exec_pool_free(vkctx, &pv->e);
-    ff_vk_exec_pool_free(vkctx, &pv->transfer_exec_pool);
 
     if (ctx->alpha_bits)
         ff_vk_shader_free(vkctx, &pv->alpha_data_shd);
@@ -837,10 +960,13 @@ static av_cold int encode_close(AVCodecContext *avctx)
     ff_vk_shader_free(vkctx, &pv->estimate_slice_shd);
     ff_vk_shader_free(vkctx, &pv->encode_slice_shd);
     ff_vk_shader_free(vkctx, &pv->trellis_node_shd);
+    ff_vk_shader_free(vkctx, &pv->gather_shd);
 
     ff_vk_free_buf(vkctx, &pv->prores_data_tables_buf);
 
     av_refstruct_pool_uninit(&pv->pkt_buf_pool);
+    av_refstruct_pool_uninit(&pv->slice_sizes_buf_pool);
+    av_refstruct_pool_uninit(&pv->gathered_buf_pool);
     av_refstruct_pool_uninit(&pv->slice_data_buf_pool);
     av_refstruct_pool_uninit(&pv->slice_score_buf_pool);
     av_refstruct_pool_uninit(&pv->frame_size_buf_pool);
@@ -868,15 +994,6 @@ static av_cold int encode_init(AVCodecContext *avctx)
 
     RET(ff_vk_exec_pool_init(vkctx, pv->qf, &pv->e, 1, 0, 0, 0, NULL));
 
-    pv->transfer_qf = ff_vk_qf_find(vkctx, VK_QUEUE_TRANSFER_BIT, 0);
-    if (!pv->transfer_qf) {
-        av_log(avctx, AV_LOG_ERROR, "Device has no transfer queues!\n");
-        return err;
-    }
-
-    RET(ff_vk_exec_pool_init(vkctx, pv->transfer_qf, &pv->transfer_exec_pool,
-                             pv->async_depth, 0, 0, 0, NULL));
-
     /* Init common prores structures */
     err = ff_prores_kostya_encode_init(avctx, ctx, vkctx->frames->sw_format);
     if (err < 0)
@@ -901,6 +1018,29 @@ 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);
+
+    /* Size slots for the entropy coder's worst case; bits_per_mb is only a 
rate-control average */
+    {
+        size_t samples = ctx->mbs_per_slice *
+                         (256 + (ctx->chroma_factor == CFACTOR_Y444 ? 512 : 
256));
+        pv->slice_slot_size = 2 + 2 * ctx->num_planes + samples * 8;
+        if (ctx->alpha_bits)
+            pv->slice_slot_size += (ctx->mbs_per_slice * 256 *
+                                    (1 + ctx->alpha_bits + 1) + 7) >> 3;
+        pv->slice_slot_size = FFMIN(pv->slice_slot_size,
+                                    UINT16_MAX + 2 + 2 * ctx->num_planes);
+        pv->slice_slot_size = FFALIGN(pv->slice_slot_size, 16);
+    }
+
+    /* First picture's payload offset: everything before it in the stream has
+     * a static size, so the gather pass writes the payload directly in place 
*/
+    {
+        uint8_t tmp[256];
+        uint8_t *start = tmp;
+        uint8_t *end = write_frame_header(avctx, ctx, &start, 0, 0, 0, 0);
+        pv->payload_off = (end - tmp) + 8 + ctx->slices_per_picture * 2;
+    }
 
     if (ctx->alpha_bits)
         init_alpha_data_pipeline(pv, &pv->alpha_data_shd);
diff --git a/libavcodec/vulkan/prores_ks_encode_slice.comp.glsl 
b/libavcodec/vulkan/prores_ks_encode_slice.comp.glsl
index 7105ad8dae..a974e51d9e 100644
--- a/libavcodec/vulkan/prores_ks_encode_slice.comp.glsl
+++ b/libavcodec/vulkan/prores_ks_encode_slice.comp.glsl
@@ -49,8 +49,10 @@ struct SliceScore {
 };
 
 layout(push_constant, scalar) uniform EncodeSliceInfo {
-    u8buf bytestream;
-    u8vec2buf seek_table;
+    u8buf bytestream;     /* one fixed-stride slot per slice */
+    u32buf slice_sizes;   /* per-slice byte sizes, for the gather pass and
+                           * the CPU-written seek table */
+    uint slot_size;
 };
 
 layout (set = 0, binding = 0, scalar) readonly buffer SliceBuffer {
@@ -244,8 +246,7 @@ void main()
     ivec4 bits = scores[slice].bits[q_idx];
     int slice_hdr_size = 2 * num_planes;
     int slice_size = slice_hdr_size + ((bits.x + bits.y + bits.z + bits.w) / 
8);
-    int buf_start = scores[slice].buf_start;
-    u8buf buf = OFFBUF(u8buf, bytestream, buf_start);
+    u8buf buf = OFFBUF(u8buf, bytestream, slice * slot_size);
 
     /* Write slice header */
     if (plane == 0) {
@@ -255,7 +256,7 @@ void main()
         for (int i = 0; i < num_planes - 1; i++) {
             slice_hdr[i].v = byteswap16(bits[i] / 8);
         }
-        seek_table[slice].v = byteswap16(slice_size);
+        slice_sizes[slice].v = uint32_t(slice_size);
     }
 
     int plane_offset = 0;

_______________________________________________
ffmpeg-cvslog mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to