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

Git pushed a commit to branch master
in repository ffmpeg.

commit 48236ce1a8c0d37c31ce5c6394e4bd284b8b3bc1
Author:     Lynne <[email protected]>
AuthorDate: Sun Jul 5 16:30:36 2026 +0900
Commit:     Lynne <[email protected]>
CommitDate: Sun Jul 12 13:34:58 2026 +0900

    ffv1enc_vulkan: gather into VRAM and then copy, drop the host-only path
    
    The gather shader wrote the finished bitstream directly into a
    host visible buffer with BDA stores.
    
    Keep the gather output in VRAM and append a single copy-engine
    transfer to the same submission to move it into the host-visible
    readback buffer. DMA readback into cached system memory is the one
    path every driver optimizes. Still no CPU involvement.
    
    The host path was awfully slow and only really used because of FFv1's
    insane overallocation.
---
 libavcodec/ffv1enc_vulkan.c | 95 +++++++++++++++++++++++----------------------
 1 file changed, 48 insertions(+), 47 deletions(-)

diff --git a/libavcodec/ffv1enc_vulkan.c b/libavcodec/ffv1enc_vulkan.c
index c993409071..7e7edbfd0e 100644
--- a/libavcodec/ffv1enc_vulkan.c
+++ b/libavcodec/ffv1enc_vulkan.c
@@ -65,7 +65,6 @@ typedef struct VulkanEncodeFFv1Context {
     VulkanEncodeFFv1FrameData *exec_ctx_info;
     int in_flight;
     int async_depth;
-    size_t max_heap_size;
 
     FFVulkanShader rct_search;
     FFVulkanShader remap;
@@ -91,7 +90,10 @@ typedef struct VulkanEncodeFFv1Context {
     /* Output data buffer */
     AVBufferPool *out_data_pool;
 
-    /* Gathered (contiguous) output buffer pool */
+    /* Gathered (contiguous) device-local buffer pool */
+    AVBufferPool *gathered_data_pool;
+
+    /* Host-visible readback buffer pool */
     AVBufferPool *compacted_data_pool;
 
     /* Intermediate frame pool */
@@ -301,6 +303,8 @@ static int vulkan_encode_ffv1_submit_frame(AVCodecContext 
*avctx,
     /* Output data */
     size_t maxsize;
     FFVkBuffer *out_data_buf;
+    AVBufferRef *gathered_ref = NULL;
+    FFVkBuffer *gathered_buf;
     FFVkBuffer *compacted_buf;
 
     int has_inter = avctx->gop_size > 1;
@@ -372,29 +376,30 @@ static int vulkan_encode_ffv1_submit_frame(AVCodecContext 
*avctx,
     maxsize = ffv1_vk_buffer_size(avctx);
     maxsize = FFMIN(maxsize, fv->s.props_11.maxMemoryAllocationSize);
 
-    /* Sparse per-slice output: written by encode, read by gather, never by the
-     * CPU, so device-local unless it won't fit in VRAM. */
-    VkMemoryPropertyFlagBits out_buf_flags;
-    if (maxsize < fv->max_heap_size)
-        out_buf_flags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
-    else
-        out_buf_flags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
-                        fv->s.host_cached_flag;
-
+    /* Sparse per-slice slots: written by encode, read by gather. */
     RET(ff_vk_get_pooled_buffer(&fv->s, &fv->out_data_pool,
                                 &fd->out_data_ref,
-                                VK_BUFFER_USAGE_TRANSFER_SRC_BIT |
                                 VK_BUFFER_USAGE_STORAGE_BUFFER_BIT |
                                 VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
-                                NULL, maxsize, out_buf_flags));
+                                NULL, maxsize,
+                                VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT));
     out_data_buf = (FFVkBuffer *)fd->out_data_ref->data;
 
-    /* Contiguous gathered output, read back by the CPU. */
-    RET(ff_vk_get_pooled_buffer(&fv->s, &fv->compacted_data_pool,
-                                &fd->compacted_data_ref,
+    /* Device-local gather destination */
+    RET(ff_vk_get_pooled_buffer(&fv->s, &fv->gathered_data_pool,
+                                &gathered_ref,
+                                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));
+    gathered_buf = (FFVkBuffer *)gathered_ref->data;
+
+    /* 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,
+                                NULL, maxsize,
                                 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
                                 fv->s.host_cached_flag));
     compacted_buf = (FFVkBuffer *)fd->compacted_data_ref->data;
@@ -464,6 +469,8 @@ static int vulkan_encode_ffv1_submit_frame(AVCodecContext 
*avctx,
 
     ff_vk_exec_add_dep_buf(&fv->s, exec, &slice_data_ref, 1, has_inter);
     ff_vk_exec_add_dep_buf(&fv->s, exec, &fd->out_data_ref, 1, 1);
+    ff_vk_exec_add_dep_buf(&fv->s, exec, &gathered_ref, 1, 0);
+    gathered_ref = NULL; /* Ownership passed */
     ff_vk_exec_add_dep_buf(&fv->s, exec, &fd->compacted_data_ref, 1, 1);
     if (f->remap_mode) {
         ff_vk_exec_add_dep_buf(&fv->s, exec, &remap_data_ref, 1, 0);
@@ -699,8 +706,8 @@ 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 host-visible buffer,
-     * in the same submission (no separate transfer pass). */
+    /* Gather the per-slice slots into one contiguous 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,
@@ -719,7 +726,7 @@ static int vulkan_encode_ffv1_submit_frame(AVCodecContext 
*avctx,
 
     SegGatherPushData gather_pd = {
         .sparse    = out_data_buf->address,
-        .compacted = compacted_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,
@@ -733,6 +740,23 @@ static int vulkan_encode_ffv1_submit_frame(AVCodecContext 
*avctx,
                                    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 });
+
     /* Submit */
     err = ff_vk_exec_submit(&fv->s, exec);
     if (err < 0)
@@ -747,6 +771,7 @@ static int vulkan_encode_ffv1_submit_frame(AVCodecContext 
*avctx,
 
 fail:
     av_frame_free(&tmp);
+    av_buffer_unref(&gathered_ref);
     ff_vk_exec_discard_deps(&fv->s, exec);
 
     return err;
@@ -1290,7 +1315,7 @@ fail:
 static av_cold int vulkan_encode_ffv1_init(AVCodecContext *avctx)
 {
     int err;
-    size_t maxsize, max_heap_size, max_host_size;
+    size_t maxsize;
     VulkanEncodeFFv1Context *fv = avctx->priv_data;
     FFV1Context *f = &fv->ctx;
 
@@ -1398,19 +1423,6 @@ static av_cold int 
vulkan_encode_ffv1_init(AVCodecContext *avctx)
         return err;
     }
 
-    /* Try to measure VRAM size */
-    max_heap_size = 0;
-    max_host_size = 0;
-    for (int i = 0; i < fv->s.mprops.memoryHeapCount; i++) {
-        if (fv->s.mprops.memoryHeaps[i].flags & 
VK_MEMORY_HEAP_DEVICE_LOCAL_BIT)
-            max_heap_size = FFMAX(max_heap_size,
-                                  fv->s.mprops.memoryHeaps[i].size);
-        if (!(fv->s.mprops.memoryHeaps[i].flags & 
VK_MEMORY_HEAP_DEVICE_LOCAL_BIT))
-            max_host_size = FFMAX(max_host_size,
-                                  fv->s.mprops.memoryHeaps[i].size);
-    }
-    fv->max_heap_size = max_heap_size;
-
     maxsize = ffv1_vk_buffer_size(avctx);
     if (maxsize > fv->s.props_11.maxMemoryAllocationSize) {
         av_log(avctx, AV_LOG_WARNING, "Encoding buffer size (%zu) larger "
@@ -1419,21 +1431,9 @@ static av_cold int 
vulkan_encode_ffv1_init(AVCodecContext *avctx)
         maxsize = fv->s.props_11.maxMemoryAllocationSize;
     }
 
-    if (max_heap_size < maxsize) {
-        av_log(avctx, AV_LOG_WARNING, "Encoding buffer (%zu) larger than VRAM 
(%zu), "
-                                      "using host memory (slower)\n",
-               maxsize, fv->max_heap_size);
-
-        /* Keep 1/2th of RAM as headroom */
-        max_heap_size = max_host_size - (max_host_size >> 1);
-    } else {
-        /* Keep 1/8th of VRAM as headroom */
-        max_heap_size = max_heap_size - (max_heap_size >> 3);
-    }
-
     av_log(avctx, AV_LOG_INFO, "Async buffers: %zuMiB per context, %zuMiB 
total, depth: %i\n",
-           maxsize / (1024*1024),
-           (fv->async_depth * maxsize) / (1024*1024),
+           2*maxsize / (1024*1024),
+           (fv->async_depth * 2*maxsize) / (1024*1024),
            fv->async_depth);
 
     err = ff_vk_exec_pool_init(&fv->s, fv->qf, &fv->exec_pool,
@@ -1602,6 +1602,7 @@ static av_cold int 
vulkan_encode_ffv1_close(AVCodecContext *avctx)
     av_buffer_unref(&fv->intermediate_frames_ref);
 
     av_buffer_pool_uninit(&fv->out_data_pool);
+    av_buffer_pool_uninit(&fv->gathered_data_pool);
     av_buffer_pool_uninit(&fv->compacted_data_pool);
 
     av_buffer_unref(&fv->keyframe_slice_data_ref);

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

Reply via email to