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]
