summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/ffmpeg.texi15
-rw-r--r--libavutil/hwcontext_vulkan.c73
2 files changed, 81 insertions, 7 deletions
diff --git a/doc/ffmpeg.texi b/doc/ffmpeg.texi
index 29753f06ca..ed437bb16f 100644
--- a/doc/ffmpeg.texi
+++ b/doc/ffmpeg.texi
@@ -1034,6 +1034,18 @@ If @var{device} is an integer, it selects the device by its index in a
system-dependent list of devices. If @var{device} is any other string, it
selects the first device with a name containing that string as a substring.
+The following options are recognized:
+@table @option
+@item debug
+If set to 1, enables the validation layer, if installed.
+@item linear_images
+If set to 1, images allocated by the hwcontext will be linear and locally mappable.
+@item instance_extensions
+A plus separated list of additional instance extensions to enable.
+@item device_extensions
+A plus separated list of additional device extensions to enable.
+@end table
+
Examples:
@table @emph
@item -init_hw_device vulkan:1
@@ -1041,6 +1053,9 @@ Choose the second device on the system.
@item -init_hw_device vulkan:RADV
Choose the first device with a name containing the string @emph{RADV}.
+
+@item -init_hw_device vulkan:0,instance_extensions=VK_KHR_wayland_surface+VK_KHR_xcb_surface
+Choose the first device and enable the Wayland and XCB instance extensions.
@end table
@end table
diff --git a/libavutil/hwcontext_vulkan.c b/libavutil/hwcontext_vulkan.c
index 43e7cddbc5..cb805b0d1b 100644
--- a/libavutil/hwcontext_vulkan.c
+++ b/libavutil/hwcontext_vulkan.c
@@ -98,9 +98,13 @@ typedef struct AVVkFrameInternal {
list = av_realloc_array(list, sizeof(*list), ++count); \
if (!list) { \
err = AVERROR(ENOMEM); \
- goto end; \
+ goto fail; \
+ } \
+ list[count - 1] = av_strdup(val); \
+ if (!list[count - 1]) { \
+ err = AVERROR(ENOMEM); \
+ goto fail; \
} \
- list[count - 1] = val; \
} while(0)
static const struct {
@@ -261,7 +265,7 @@ static VkBool32 vk_dbg_callback(VkDebugUtilsMessageSeverityFlagBitsEXT severity,
return 0;
}
-static int check_extensions(AVHWDeviceContext *ctx, int dev,
+static int check_extensions(AVHWDeviceContext *ctx, int dev, AVDictionary *opts,
const char * const **dst, uint32_t *num, int debug)
{
const char *tstr;
@@ -273,6 +277,8 @@ static int check_extensions(AVHWDeviceContext *ctx, int dev,
const char *mod;
int optional_exts_num;
uint32_t sup_ext_count;
+ char *user_exts_str = NULL;
+ AVDictionaryEntry *user_exts;
VkExtensionProperties *sup_ext;
const VulkanOptExtension *optional_exts;
@@ -280,6 +286,14 @@ static int check_extensions(AVHWDeviceContext *ctx, int dev,
mod = "instance";
optional_exts = optional_instance_exts;
optional_exts_num = FF_ARRAY_ELEMS(optional_instance_exts);
+ user_exts = av_dict_get(opts, "instance_extensions", NULL, 0);
+ if (user_exts) {
+ user_exts_str = av_strdup(user_exts->value);
+ if (!user_exts_str) {
+ err = AVERROR(ENOMEM);
+ goto fail;
+ }
+ }
vkEnumerateInstanceExtensionProperties(NULL, &sup_ext_count, NULL);
sup_ext = av_malloc_array(sup_ext_count, sizeof(VkExtensionProperties));
if (!sup_ext)
@@ -289,6 +303,14 @@ static int check_extensions(AVHWDeviceContext *ctx, int dev,
mod = "device";
optional_exts = optional_device_exts;
optional_exts_num = FF_ARRAY_ELEMS(optional_device_exts);
+ user_exts = av_dict_get(opts, "device_extensions", NULL, 0);
+ if (user_exts) {
+ user_exts_str = av_strdup(user_exts->value);
+ if (!user_exts_str) {
+ err = AVERROR(ENOMEM);
+ goto fail;
+ }
+ }
vkEnumerateDeviceExtensionProperties(hwctx->phys_dev, NULL,
&sup_ext_count, NULL);
sup_ext = av_malloc_array(sup_ext_count, sizeof(VkExtensionProperties));
@@ -336,19 +358,52 @@ static int check_extensions(AVHWDeviceContext *ctx, int dev,
}
}
if (found) {
+ av_log(ctx, AV_LOG_VERBOSE, "Using %s extension \"%s\"\n", mod, tstr);
ADD_VAL_TO_LIST(extension_names, extensions_found, tstr);
} else {
av_log(ctx, AV_LOG_ERROR, "Debug extension \"%s\" not found!\n",
tstr);
err = AVERROR(EINVAL);
- goto end;
+ goto fail;
+ }
+ }
+
+ if (user_exts_str) {
+ char *save, *token = av_strtok(user_exts_str, "+", &save);
+ while (token) {
+ found = 0;
+ for (int j = 0; j < sup_ext_count; j++) {
+ if (!strcmp(token, sup_ext[j].extensionName)) {
+ found = 1;
+ break;
+ }
+ }
+ if (found) {
+ av_log(ctx, AV_LOG_VERBOSE, "Using %s extension \"%s\"\n", mod, tstr);
+ ADD_VAL_TO_LIST(extension_names, extensions_found, token);
+ } else {
+ av_log(ctx, AV_LOG_ERROR, "%s extension \"%s\" not found!\n",
+ mod, token);
+ err = AVERROR(EINVAL);
+ goto fail;
+ }
+ token = av_strtok(NULL, "+", &save);
}
}
*dst = extension_names;
*num = extensions_found;
-end:
+ av_free(user_exts_str);
+ av_free(sup_ext);
+ return 0;
+
+fail:
+ if (extension_names)
+ for (int i = 0; i < extensions_found; i++)
+ av_free((void *)extension_names[i]);
+ av_free(extension_names);
+ av_free(user_exts_str);
av_free(sup_ext);
return err;
}
@@ -376,7 +431,7 @@ static int create_instance(AVHWDeviceContext *ctx, AVDictionary *opts)
};
/* Check for present/missing extensions */
- err = check_extensions(ctx, 0, &inst_props.ppEnabledExtensionNames,
+ err = check_extensions(ctx, 0, opts, &inst_props.ppEnabledExtensionNames,
&inst_props.enabledExtensionCount, debug_mode);
if (err < 0)
return err;
@@ -391,6 +446,8 @@ static int create_instance(AVHWDeviceContext *ctx, AVDictionary *opts)
ret = vkCreateInstance(&inst_props, hwctx->alloc, &hwctx->inst);
/* Free used memory */
+ for (int i = 0; i < inst_props.enabledExtensionCount; i++)
+ av_free((void *)inst_props.ppEnabledExtensionNames[i]);
av_free((void *)inst_props.ppEnabledExtensionNames);
/* Check for errors */
@@ -777,13 +834,15 @@ static int vulkan_device_create_internal(AVHWDeviceContext *ctx,
if ((err = search_queue_families(ctx, &dev_info)))
goto end;
- if ((err = check_extensions(ctx, 1, &dev_info.ppEnabledExtensionNames,
+ if ((err = check_extensions(ctx, 1, opts, &dev_info.ppEnabledExtensionNames,
&dev_info.enabledExtensionCount, 0)))
goto end;
ret = vkCreateDevice(hwctx->phys_dev, &dev_info, hwctx->alloc,
&hwctx->act_dev);
+ for (int i = 0; i < dev_info.enabledExtensionCount; i++)
+ av_free((void *)dev_info.ppEnabledExtensionNames[i]);
av_free((void *)dev_info.ppEnabledExtensionNames);
if (ret != VK_SUCCESS) {