PR #22438 opened by Lynne
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/22438
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/22438.patch

This removes the need to lock/unlock queues.


>From 00d2e2051cae7184e86fe435c0dbf91c6c61e4d5 Mon Sep 17 00:00:00 2001
From: Lynne <[email protected]>
Date: Sat, 7 Mar 2026 01:37:50 +0100
Subject: [PATCH 1/3] Changelog: add entry for the prores Vulkan encoder

---
 Changelog | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Changelog b/Changelog
index e9d8b4812e..cdda717219 100644
--- a/Changelog
+++ b/Changelog
@@ -27,6 +27,7 @@ version <next>:
 - LCEVC metadata bitstream filter
 - Add vf_deinterlace_d3d12 filter
 - ffprobe: only show refs field in stream section when reading frames
+- ProRes Vulkan encoder
 
 
 version 8.0:
-- 
2.52.0


>From e3000e07820ee8a614445d36e78e000d0ae110a8 Mon Sep 17 00:00:00 2001
From: Lynne <[email protected]>
Date: Sat, 7 Mar 2026 02:11:24 +0100
Subject: [PATCH 2/3] vulkan_ffv1: warn users on low number of slices

Files with a low amount of slices take a considerably longer amount
of time to decode. Experimentally, 16 seems to be a good safe minimum.
---
 libavcodec/vulkan_ffv1.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/libavcodec/vulkan_ffv1.c b/libavcodec/vulkan_ffv1.c
index e807fe4de6..1ea927ccd3 100644
--- a/libavcodec/vulkan_ffv1.c
+++ b/libavcodec/vulkan_ffv1.c
@@ -750,6 +750,12 @@ static int vk_decode_ffv1_init(AVCodecContext *avctx)
         (f->version == 4 && f->micro_version > 3))
         return AVERROR(ENOTSUP);
 
+    /* Streams with a low amount of slices will usually be much slower
+     * to decode, so warn the user. */
+    if (f->slice_count < 16)
+        av_log(avctx, AV_LOG_WARNING, "Stream has a low number of slices (%i), 
"
+               "decoding may be very slow\n", f->slice_count);
+
     err = ff_vk_decode_init(avctx);
     if (err < 0)
         return err;
-- 
2.52.0


>From e85cefc851171907c6ef1399b7d311516cb4c538 Mon Sep 17 00:00:00 2001
From: Lynne <[email protected]>
Date: Sat, 7 Mar 2026 14:56:01 +0100
Subject: [PATCH 3/3] hwcontext_vulkan: use internal queue synchronization

Thanks to VK_KHR_internally_synchronized_queues, we no longer need global 
queues.
Once the API is removed, we will hard-require internally synchronized queues.
---
 doc/APIchanges               |  4 +++
 libavutil/hwcontext_vulkan.c | 65 ++++++++++++++++++++++++------------
 libavutil/hwcontext_vulkan.h |  8 +++++
 libavutil/version.h          |  1 +
 libavutil/vulkan_functions.h |  1 +
 libavutil/vulkan_loader.h    |  3 ++
 6 files changed, 61 insertions(+), 21 deletions(-)

diff --git a/doc/APIchanges b/doc/APIchanges
index 88005bb28e..48f263d9da 100644
--- a/doc/APIchanges
+++ b/doc/APIchanges
@@ -2,6 +2,10 @@ The last version increases of all libraries were on 2025-03-28
 
 API changes, most recent first:
 
+2026-03-xx - xxxxxxxxxx - lavu 60.25.100 - hwcontext_vulkan.h
+  Deprecate AVVulkanDeviceContext.lock_queue and
+  AVVulkanDeviceContext.unlock_queue without replacement.
+
 2026-02-xx - xxxxxxxxxx - lsws 9.4.100 - swscale.h
   Add sws_test_hw_format().
 
diff --git a/libavutil/hwcontext_vulkan.c b/libavutil/hwcontext_vulkan.c
index 6c104b7204..ba991e2f86 100644
--- a/libavutil/hwcontext_vulkan.c
+++ b/libavutil/hwcontext_vulkan.c
@@ -117,6 +117,10 @@ typedef struct VulkanDeviceFeatures {
 #ifdef VK_KHR_shader_relaxed_extended_instruction
     VkPhysicalDeviceShaderRelaxedExtendedInstructionFeaturesKHR 
relaxed_extended_instruction;
 #endif
+
+#ifdef VK_KHR_internally_synchronized_queues
+    VkPhysicalDeviceInternallySynchronizedQueuesFeaturesKHR 
internal_queue_sync;
+#endif
 } VulkanDeviceFeatures;
 
 typedef struct VulkanDevicePriv {
@@ -282,6 +286,11 @@ static void device_features_init(AVHWDeviceContext *ctx, 
VulkanDeviceFeatures *f
     FF_VK_STRUCT_EXT(s, &feats->device, &feats->relaxed_extended_instruction, 
FF_VK_EXT_RELAXED_EXTENDED_INSTR,
                      
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_RELAXED_EXTENDED_INSTRUCTION_FEATURES_KHR);
 #endif
+
+#ifdef VK_KHR_internally_synchronized_queues
+    FF_VK_STRUCT_EXT(s, &feats->device, &feats->internal_queue_sync, 
FF_VK_EXT_INTERNAL_QUEUE_SYNC,
+                     
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INTERNALLY_SYNCHRONIZED_QUEUES_FEATURES_KHR);
+#endif
 }
 
 /* Copy all needed device features */
@@ -387,6 +396,10 @@ static void 
device_features_copy_needed(VulkanDeviceFeatures *dst, VulkanDeviceF
     COPY_VAL(expect_assume.shaderExpectAssume);
 #endif
 
+#ifdef VK_KHR_internally_synchronized_queues
+    COPY_VAL(internal_queue_sync.internallySynchronizedQueues);
+#endif
+
 #undef COPY_VAL
 }
 
@@ -707,6 +720,9 @@ static const VulkanOptExtension optional_device_exts[] = {
 #ifdef VK_KHR_video_maintenance2
     { VK_KHR_VIDEO_MAINTENANCE_2_EXTENSION_NAME,              
FF_VK_EXT_VIDEO_MAINTENANCE_2    },
 #endif
+#ifdef VK_KHR_internally_synchronized_queues
+    { VK_KHR_INTERNALLY_SYNCHRONIZED_QUEUES_EXTENSION_NAME,   
FF_VK_EXT_INTERNAL_QUEUE_SYNC    },
+#endif
 
     /* Imports/exports */
     { VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME,               
FF_VK_EXT_EXTERNAL_FD_MEMORY     },
@@ -1776,11 +1792,13 @@ static void vulkan_device_uninit(AVHWDeviceContext *ctx)
 {
     VulkanDevicePriv *p = ctx->hwctx;
 
-    for (uint32_t i = 0; i < p->nb_tot_qfs; i++) {
-        pthread_mutex_destroy(p->qf_mutex[i]);
-        av_freep(&p->qf_mutex[i]);
+    if (p->qf_mutex) {
+        for (uint32_t i = 0; i < p->nb_tot_qfs; i++) {
+            pthread_mutex_destroy(p->qf_mutex[i]);
+            av_freep(&p->qf_mutex[i]);
+        }
+        av_freep(&p->qf_mutex);
     }
-    av_freep(&p->qf_mutex);
 
     ff_vk_uninit(&p->vkctx);
 }
@@ -1895,13 +1913,15 @@ end:
 static void lock_queue(AVHWDeviceContext *ctx, uint32_t queue_family, uint32_t 
index)
 {
     VulkanDevicePriv *p = ctx->hwctx;
-    pthread_mutex_lock(&p->qf_mutex[queue_family][index]);
+    if (p->qf_mutex)
+        pthread_mutex_lock(&p->qf_mutex[queue_family][index]);
 }
 
 static void unlock_queue(AVHWDeviceContext *ctx, uint32_t queue_family, 
uint32_t index)
 {
     VulkanDevicePriv *p = ctx->hwctx;
-    pthread_mutex_unlock(&p->qf_mutex[queue_family][index]);
+    if (p->qf_mutex)
+        pthread_mutex_unlock(&p->qf_mutex[queue_family][index]);
 }
 
 static int vulkan_device_init(AVHWDeviceContext *ctx)
@@ -1999,28 +2019,31 @@ static int vulkan_device_init(AVHWDeviceContext *ctx)
 
     vk->GetPhysicalDeviceQueueFamilyProperties2(hwctx->phys_dev, &qf_num, qf);
 
-    p->qf_mutex = av_calloc(qf_num, sizeof(*p->qf_mutex));
-    if (!p->qf_mutex) {
-        err = AVERROR(ENOMEM);
-        goto end;
-    }
     p->nb_tot_qfs = qf_num;
 
-    for (uint32_t i = 0; i < qf_num; i++) {
-        p->qf_mutex[i] = av_calloc(qf[i].queueFamilyProperties.queueCount,
-                                   sizeof(**p->qf_mutex));
-        if (!p->qf_mutex[i]) {
+    if (!(p->vkctx.extensions & FF_VK_EXT_INTERNAL_QUEUE_SYNC)) {
+        p->qf_mutex = av_calloc(qf_num, sizeof(*p->qf_mutex));
+        if (!p->qf_mutex) {
             err = AVERROR(ENOMEM);
             goto end;
         }
-        for (uint32_t j = 0; j < qf[i].queueFamilyProperties.queueCount; j++) {
-            err = pthread_mutex_init(&p->qf_mutex[i][j], NULL);
-            if (err != 0) {
-                av_log(ctx, AV_LOG_ERROR, "pthread_mutex_init failed : %s\n",
-                       av_err2str(err));
-                err = AVERROR(err);
+
+        for (uint32_t i = 0; i < qf_num; i++) {
+            p->qf_mutex[i] = av_calloc(qf[i].queueFamilyProperties.queueCount,
+                                       sizeof(**p->qf_mutex));
+            if (!p->qf_mutex[i]) {
+                err = AVERROR(ENOMEM);
                 goto end;
             }
+            for (uint32_t j = 0; j < qf[i].queueFamilyProperties.queueCount; 
j++) {
+                err = pthread_mutex_init(&p->qf_mutex[i][j], NULL);
+                if (err != 0) {
+                    av_log(ctx, AV_LOG_ERROR, "pthread_mutex_init failed : 
%s\n",
+                           av_err2str(err));
+                    err = AVERROR(err);
+                    goto end;
+                }
+            }
         }
     }
 
diff --git a/libavutil/hwcontext_vulkan.h b/libavutil/hwcontext_vulkan.h
index 77d53289b4..b9a841a197 100644
--- a/libavutil/hwcontext_vulkan.h
+++ b/libavutil/hwcontext_vulkan.h
@@ -168,18 +168,26 @@ typedef struct AVVulkanDeviceContext {
     int nb_decode_queues;
 #endif
 
+#if FF_API_VULKAN_SYNC_QUEUES
     /**
      * Locks a queue, preventing other threads from submitting any command
      * buffers to this queue.
      * If set to NULL, will be set to lavu-internal functions that utilize a
      * mutex.
+     *
+     * Deprecated: use VK_KHR_internally_synchronized_queues.
      */
+    attribute_deprecated
     void (*lock_queue)(struct AVHWDeviceContext *ctx, uint32_t queue_family, 
uint32_t index);
 
     /**
      * Similar to lock_queue(), unlocks a queue. Must only be called after 
locking.
+     *
+     * Deprecated: use VK_KHR_internally_synchronized_queues.
      */
+    attribute_deprecated
     void (*unlock_queue)(struct AVHWDeviceContext *ctx, uint32_t queue_family, 
uint32_t index);
+#endif
 
     /**
      * Queue families used. Must be preferentially ordered. List may contain
diff --git a/libavutil/version.h b/libavutil/version.h
index a42ae73884..06b730276a 100644
--- a/libavutil/version.h
+++ b/libavutil/version.h
@@ -113,6 +113,7 @@
 #define FF_API_CPU_FLAG_FORCE           (LIBAVUTIL_VERSION_MAJOR < 61)
 #define FF_API_DOVI_L11_INVALID_PROPS   (LIBAVUTIL_VERSION_MAJOR < 61)
 #define FF_API_ASSERT_FPU               (LIBAVUTIL_VERSION_MAJOR < 61)
+#define FF_API_VULKAN_SYNC_QUEUES       (LIBAVUTIL_VERSION_MAJOR < 62)
 
 /**
  * @}
diff --git a/libavutil/vulkan_functions.h b/libavutil/vulkan_functions.h
index d4be2ca4e0..3c4deef0a2 100644
--- a/libavutil/vulkan_functions.h
+++ b/libavutil/vulkan_functions.h
@@ -53,6 +53,7 @@ typedef uint64_t FFVulkanExtensions;
 #define FF_VK_EXT_EXPLICIT_MEM_LAYOUT    (1ULL << 20) /* 
VK_KHR_workgroup_memory_explicit_layout */
 #define FF_VK_EXT_REPLICATED_COMPOSITES  (1ULL << 21) /* 
VK_EXT_shader_replicated_composites */
 #define FF_VK_EXT_LONG_VECTOR            (1ULL << 22) /* 
VK_EXT_shader_long_vector */
+#define FF_VK_EXT_INTERNAL_QUEUE_SYNC    (1ULL << 23) /* 
VK_KHR_internally_synchronized_queues */
 
 /* Video extensions */
 #define FF_VK_EXT_VIDEO_QUEUE            (1ULL << 36) /* VK_KHR_video_queue */
diff --git a/libavutil/vulkan_loader.h b/libavutil/vulkan_loader.h
index 45a296e2fa..a65707b975 100644
--- a/libavutil/vulkan_loader.h
+++ b/libavutil/vulkan_loader.h
@@ -95,6 +95,9 @@ static inline uint64_t ff_vk_extensions_to_mask(const char * 
const *extensions,
 #endif
 #ifdef VK_KHR_video_encode_av1
         { VK_KHR_VIDEO_ENCODE_AV1_EXTENSION_NAME,          
FF_VK_EXT_VIDEO_ENCODE_AV1       },
+#endif
+#define VK_KHR_internally_synchronized_queues
+        { VK_KHR_INTERNALLY_SYNCHRONIZED_QUEUES_EXTENSION_NAME, 
FF_VK_EXT_INTERNAL_QUEUE_SYNC   },
 #endif
     };
 
-- 
2.52.0

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

Reply via email to