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

Applications that initialize Vulkan themselves (perhaps via libplacebo or other 
libraries) don't currently have a way to identify the optional device/instance 
extensions that FFmpeg might be able to use. Instead, they have to resort to 
keeping a hardcoded list, like `ffplay` does, which is fragile and hinders 
further use of newer extensions in FFmpeg. Even the in-tree `ffplay` tool is 
already out of sync with `hwcontext_vulkan.c` (using 
`"VK_MESA_video_decode_av1"` instead of 
`VK_KHR_VIDEO_DECODE_AV1_EXTENSION_NAME`, among others).

This PR adds new APIs to query these optional device/instance extensions and 
replaces the hardcoded device extension list in `ffplay`.


>From 4344accd80d5e145da2c655800d359e422c60b19 Mon Sep 17 00:00:00 2001
From: Cameron Gutman <[email protected]>
Date: Sun, 7 Dec 2025 13:51:05 -0600
Subject: [PATCH 1/2] hwcontext_vulkan: add APIs to get optional extensions

These provide a way for apps that initialize Vulkan themselves to know
which extensions we may be able to use without having to hardcode it.

Signed-off-by: Cameron Gutman <[email protected]>
---
 libavutil/hwcontext_vulkan.c | 32 ++++++++++++++++++++++++++++++++
 libavutil/hwcontext_vulkan.h | 18 ++++++++++++++++++
 2 files changed, 50 insertions(+)

diff --git a/libavutil/hwcontext_vulkan.c b/libavutil/hwcontext_vulkan.c
index a120e6185c..c3e57744af 100644
--- a/libavutil/hwcontext_vulkan.c
+++ b/libavutil/hwcontext_vulkan.c
@@ -693,6 +693,38 @@ static const VulkanOptExtension optional_device_exts[] = {
     { VK_KHR_VIDEO_DECODE_AV1_EXTENSION_NAME,                 
FF_VK_EXT_VIDEO_DECODE_AV1       },
 };
 
+const char **av_vk_get_optional_instance_extensions(int* count)
+{
+    const char **exts = av_malloc_array(sizeof(*exts),
+                                        
FF_ARRAY_ELEMS(optional_instance_exts));
+    if (!exts) {
+        return NULL;
+    }
+
+    for (int i = 0; i < FF_ARRAY_ELEMS(optional_instance_exts); i++) {
+        exts[i] = optional_instance_exts[i].name;
+    }
+
+    *count = FF_ARRAY_ELEMS(optional_instance_exts);
+    return exts;
+}
+
+const char **av_vk_get_optional_device_extensions(int* count)
+{
+    const char **exts = av_malloc_array(sizeof(*exts),
+                                        FF_ARRAY_ELEMS(optional_device_exts));
+    if (!exts) {
+        return NULL;
+    }
+
+    for (int i = 0; i < FF_ARRAY_ELEMS(optional_device_exts); i++) {
+        exts[i] = optional_device_exts[i].name;
+    }
+
+    *count = FF_ARRAY_ELEMS(optional_device_exts);
+    return exts;
+}
+
 static VkBool32 VKAPI_CALL 
vk_dbg_callback(VkDebugUtilsMessageSeverityFlagBitsEXT severity,
                                            VkDebugUtilsMessageTypeFlagsEXT 
messageType,
                                            const 
VkDebugUtilsMessengerCallbackDataEXT *data,
diff --git a/libavutil/hwcontext_vulkan.h b/libavutil/hwcontext_vulkan.h
index 0bb536ab3f..8e741103f1 100644
--- a/libavutil/hwcontext_vulkan.h
+++ b/libavutil/hwcontext_vulkan.h
@@ -97,6 +97,8 @@ typedef struct AVVulkanDeviceContext {
      * each entry containing the specified Vulkan extension string to enable.
      * Duplicates are possible and accepted.
      * If no extensions are enabled, set these fields to NULL, and 0 
respectively.
+     * av_vk_get_optional_instance_extensions() can be used to enumerate 
extensions
+     * that FFmpeg may use if enabled.
      */
     const char * const *enabled_inst_extensions;
     int nb_enabled_inst_extensions;
@@ -108,6 +110,8 @@ typedef struct AVVulkanDeviceContext {
      * If supplying your own device context, these fields takes the same 
format as
      * the above fields, with the same conditions that duplicates are possible
      * and accepted, and that NULL and 0 respectively means no extensions are 
enabled.
+     * av_vk_get_optional_device_extensions() can be used to enumerate 
extensions
+     * that FFmpeg may use if enabled.
      */
     const char * const *enabled_dev_extensions;
     int nb_enabled_dev_extensions;
@@ -375,4 +379,18 @@ AVVkFrame *av_vk_frame_alloc(void);
  */
 const VkFormat *av_vkfmt_from_pixfmt(enum AVPixelFormat p);
 
+/**
+ * Returns an array of optional Vulkan instance extensions that FFmpeg
+ * may use if enabled.
+ * @note Must be freed via av_free()
+ */
+const char **av_vk_get_optional_instance_extensions(int* count);
+
+/**
+ * Returns an array of optional Vulkan device extensions that FFmpeg
+ * may use if enabled.
+ * @note Must be freed via av_free()
+ */
+const char **av_vk_get_optional_device_extensions(int* count);
+
 #endif /* AVUTIL_HWCONTEXT_VULKAN_H */
-- 
2.49.1


>From f176e1d6558c671608bffa5d7d4f98548aee8eb1 Mon Sep 17 00:00:00 2001
From: Cameron Gutman <[email protected]>
Date: Sun, 7 Dec 2025 13:57:42 -0600
Subject: [PATCH 2/2] fftools/ffplay_renderer: use new Vulkan extension API

Signed-off-by: Cameron Gutman <[email protected]>
---
 fftools/ffplay_renderer.c | 41 +++++++++------------------------------
 1 file changed, 9 insertions(+), 32 deletions(-)

diff --git a/fftools/ffplay_renderer.c b/fftools/ffplay_renderer.c
index 699cd6ecd0..1321452ad8 100644
--- a/fftools/ffplay_renderer.c
+++ b/fftools/ffplay_renderer.c
@@ -104,36 +104,6 @@ static void vk_log_cb(void *log_priv, enum pl_log_level 
level,
         av_log(log_priv, level_map[level], "%s\n", msg);
 }
 
-// Should keep sync with optional_device_exts inside hwcontext_vulkan.c
-static const char *optional_device_exts[] = {
-    /* Misc or required by other extensions */
-    VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME,
-    VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME,
-    VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME,
-    VK_EXT_DESCRIPTOR_BUFFER_EXTENSION_NAME,
-    VK_EXT_PHYSICAL_DEVICE_DRM_EXTENSION_NAME,
-    VK_EXT_SHADER_ATOMIC_FLOAT_EXTENSION_NAME,
-    VK_KHR_COOPERATIVE_MATRIX_EXTENSION_NAME,
-
-    /* Imports/exports */
-    VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME,
-    VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME,
-    VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME,
-    VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME,
-    VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME,
-#ifdef _WIN32
-    VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME,
-    VK_KHR_EXTERNAL_SEMAPHORE_WIN32_EXTENSION_NAME,
-#endif
-
-    /* Video encoding/decoding */
-    VK_KHR_VIDEO_QUEUE_EXTENSION_NAME,
-    VK_KHR_VIDEO_DECODE_QUEUE_EXTENSION_NAME,
-    VK_KHR_VIDEO_DECODE_H264_EXTENSION_NAME,
-    VK_KHR_VIDEO_DECODE_H265_EXTENSION_NAME,
-    "VK_MESA_video_decode_av1",
-};
-
 static inline int enable_debug(const AVDictionary *opt)
 {
     AVDictionaryEntry *entry = av_dict_get(opt, "debug", NULL, 0);
@@ -374,6 +344,8 @@ static int create_vk_by_placebo(VkRenderer *renderer,
     int decode_index;
     int decode_count;
     int ret;
+    const char **dev_exts;
+    int num_dev_exts;
 
     ctx->get_proc_addr = SDL_Vulkan_GetVkGetInstanceProcAddr();
 
@@ -388,16 +360,21 @@ static int create_vk_by_placebo(VkRenderer *renderer,
     }
     ctx->inst = ctx->placebo_instance->instance;
 
+    dev_exts = av_vk_get_optional_device_extensions(&num_dev_exts);
+    if (!dev_exts)
+        return AVERROR(ENOMEM);
+
     ctx->placebo_vulkan = pl_vulkan_create(ctx->vk_log, pl_vulkan_params(
             .instance = ctx->placebo_instance->instance,
             .get_proc_addr = ctx->placebo_instance->get_proc_addr,
             .surface = ctx->vk_surface,
             .allow_software = false,
-            .opt_extensions = optional_device_exts,
-            .num_opt_extensions = FF_ARRAY_ELEMS(optional_device_exts),
+            .opt_extensions = dev_exts,
+            .num_opt_extensions = num_dev_exts,
             .extra_queues = VK_QUEUE_VIDEO_DECODE_BIT_KHR,
             .device_name = select_device(opt),
     ));
+    av_free(dev_exts);
     if (!ctx->placebo_vulkan)
         return AVERROR_EXTERNAL;
     ctx->hw_device_ref = av_hwdevice_ctx_alloc(AV_HWDEVICE_TYPE_VULKAN);
-- 
2.49.1

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

Reply via email to