PR #24351 opened by t-boiko
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24351
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24351.patch

One VkVideoSessionKHR is round-robined across decode queues. DPB slot state is 
session-owned and checked at device execution time, so unordered queues can 
race. This adds one session timeline semaphore (wait N, signal N+1 on 
VIDEO_DECODE) around reset and decode. It is separate from the per-exec busy 
semaphore. Enabled only when the decode family has more than one queue; 
per-frame image deps are unchanged.


>From cfce772d5eefccc3ec095d632723034e5a39366c Mon Sep 17 00:00:00 2001
From: Tymur Boiko <[email protected]>
Date: Fri, 7 Aug 2026 14:00:27 +0200
Subject: [PATCH] vulkan_decode: serialize multi-queue session submissions

Use one session timeline semaphore to prevent unordered decode queues from 
racing while retaining per-frame resource dependencies.
---
 libavcodec/vulkan_decode.c | 81 +++++++++++++++++++++++++++++++++++++-
 libavcodec/vulkan_decode.h |  6 +++
 2 files changed, 86 insertions(+), 1 deletion(-)

diff --git a/libavcodec/vulkan_decode.c b/libavcodec/vulkan_decode.c
index ab313423e5..61dfb6fc36 100644
--- a/libavcodec/vulkan_decode.c
+++ b/libavcodec/vulkan_decode.c
@@ -140,6 +140,60 @@ static const VkVideoProfileInfoKHR 
*get_video_profile(FFVulkanDecodeShared *ctx,
     return NULL;
 }
 
+static int add_session_sem_dep(FFVulkanDecodeShared *ctx, FFVkExecContext 
*exec)
+{
+    uint64_t value;
+
+    if (ctx->session_sem == VK_NULL_HANDLE)
+        return 0;
+
+    value = atomic_load_explicit(&ctx->session_sem_val, memory_order_relaxed);
+    ff_vk_exec_add_dep_wait_sem(&ctx->s, exec, ctx->session_sem, value,
+                                VK_PIPELINE_STAGE_2_VIDEO_DECODE_BIT_KHR);
+    ff_vk_exec_add_dep_signal_sem(&ctx->s, exec, ctx->session_sem, value + 1,
+                                  VK_PIPELINE_STAGE_2_VIDEO_DECODE_BIT_KHR);
+
+    return 0;
+}
+
+static int vulkan_decode_init_session_sem(AVCodecContext *avctx,
+                                          FFVulkanDecodeShared *ctx)
+{
+    VkResult ret;
+    FFVulkanContext *s = &ctx->s;
+    FFVulkanFunctions *vk = &s->vkfn;
+
+    VkSemaphoreTypeCreateInfo sem_type_info = {
+        .sType         = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO,
+        .semaphoreType = VK_SEMAPHORE_TYPE_TIMELINE,
+        .initialValue  = 0,
+    };
+    VkSemaphoreCreateInfo sem_info = {
+        .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
+        .pNext = &sem_type_info,
+    };
+
+    if (ctx->qf->num <= 1)
+        return 0;
+
+    ret = vk->CreateSemaphore(s->hwctx->act_dev, &sem_info, s->hwctx->alloc,
+                              &ctx->session_sem);
+    if (ret != VK_SUCCESS) {
+        av_log(avctx, AV_LOG_ERROR,
+               "Unable to create session timeline semaphore: %s\n",
+               ff_vk_ret2str(ret));
+        return AVERROR_EXTERNAL;
+    }
+
+    atomic_init(&ctx->session_sem_val, 0);
+
+    av_log(avctx, AV_LOG_VERBOSE,
+           "Serializing video session submissions over %i decode queues "
+           "with a session timeline semaphore\n", ctx->qf->num);
+
+    return 0;
+}
+
 int ff_vk_update_thread_context(AVCodecContext *dst, const AVCodecContext *src)
 {
     FFVulkanDecodeContext *src_ctx = src->internal->hwaccel_priv_data;
@@ -402,7 +456,15 @@ static int decode_reset(AVCodecContext *avctx, 
FFVulkanDecodeShared *ctx)
     vk->CmdControlVideoCodingKHR(exec->buf, &decode_ctrl);
     vk->CmdEndVideoCodingKHR(exec->buf, &decode_end);
 
+    err = add_session_sem_dep(ctx, exec);
+    if (err < 0) {
+        ff_vk_exec_discard(&ctx->s, exec);
+        return err;
+    }
+
     err = ff_vk_exec_submit(&ctx->s, exec);
+    if (err >= 0 && ctx->session_sem != VK_NULL_HANDLE)
+        atomic_fetch_add_explicit(&ctx->session_sem_val, 1, 
memory_order_relaxed);
 
     if (decode_start.videoSessionParameters) {
         /* Wait to complete to delete the temporary session parameters */
@@ -644,8 +706,17 @@ int ff_vk_decode_frame(AVCodecContext *avctx,
     vk->CmdDecodeVideoKHR(cmd_buf, &vp->decode_info);
     vk->CmdEndVideoCodingKHR(cmd_buf, &decode_end);
 
+    err = add_session_sem_dep(ctx, exec);
+    if (err < 0) {
+        ff_vk_exec_discard(&ctx->s, exec);
+        return err;
+    }
+
     /* End recording and submit for execution */
-    return ff_vk_exec_submit(&ctx->s, exec);
+    err = ff_vk_exec_submit(&ctx->s, exec);
+    if (err >= 0 && ctx->session_sem != VK_NULL_HANDLE)
+        atomic_fetch_add_explicit(&ctx->session_sem_val, 1, 
memory_order_relaxed);
+    return err;
 }
 
 void ff_vk_decode_free_frame(AVHWDeviceContext *dev_ctx, FFVulkanDecodePicture 
*vp)
@@ -670,6 +741,10 @@ static void free_common(AVRefStructOpaque unused, void 
*obj)
     /* Wait on and free execution pool */
     ff_vk_exec_pool_free(&ctx->s, &ctx->exec_pool);
 
+    if (ctx->session_sem != VK_NULL_HANDLE)
+        ctx->s.vkfn.DestroySemaphore(ctx->s.hwctx->act_dev, ctx->session_sem,
+                                    ctx->s.hwctx->alloc);
+
     av_refstruct_pool_uninit(&ctx->buf_pool);
 
     ff_vk_video_common_uninit(s, &ctx->common);
@@ -1323,6 +1398,10 @@ int ff_vk_decode_init(AVCodecContext *avctx)
         err = ff_vk_video_common_init(avctx, s, &ctx->common, &session_create);
         if (err < 0)
             goto fail;
+
+        err = vulkan_decode_init_session_sem(avctx, ctx);
+        if (err < 0)
+            goto fail;
     }
 
     /* Out-of-place decoding: create the internal, queue-exclusive DPB pool */
diff --git a/libavcodec/vulkan_decode.h b/libavcodec/vulkan_decode.h
index eb334ea1ae..bee007a1a7 100644
--- a/libavcodec/vulkan_decode.h
+++ b/libavcodec/vulkan_decode.h
@@ -19,6 +19,8 @@
 #ifndef AVCODEC_VULKAN_DECODE_H
 #define AVCODEC_VULKAN_DECODE_H
 
+#include <stdatomic.h>
+
 #include "codec_id.h"
 #include "decode.h"
 #include "hwaccel_internal.h"
@@ -46,6 +48,10 @@ typedef struct FFVulkanDecodeShared {
     VkVideoCapabilitiesKHR caps;
     VkVideoDecodeCapabilitiesKHR dec_caps;
 
+    /* Session-wide submission ordering across decode queues. */
+    VkSemaphore session_sem;
+    atomic_uint_least64_t session_sem_val;
+
     /* Software-defined decoder context */
     void *sd_ctx;
     void (*sd_ctx_free)(struct FFVulkanDecodeShared *ctx);
-- 
2.52.0

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

Reply via email to