Unverified Commit 3c5e5a50 authored by Lynne's avatar Lynne

hwcontext_vulkan: let users enable device and instance extensions using options

Also documents all options supported by the hwdevice.
This lets users enable all extensions they need without writing their own
instance initialization code.
parent 6db81e93
...@@ -1034,6 +1034,18 @@ If @var{device} is an integer, it selects the device by its index in a ...@@ -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 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. 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: Examples:
@table @emph @table @emph
@item -init_hw_device vulkan:1 @item -init_hw_device vulkan:1
...@@ -1041,6 +1053,9 @@ Choose the second device on the system. ...@@ -1041,6 +1053,9 @@ Choose the second device on the system.
@item -init_hw_device vulkan:RADV @item -init_hw_device vulkan:RADV
Choose the first device with a name containing the string @emph{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
@end table @end table
......
...@@ -98,9 +98,13 @@ typedef struct AVVkFrameInternal { ...@@ -98,9 +98,13 @@ typedef struct AVVkFrameInternal {
list = av_realloc_array(list, sizeof(*list), ++count); \ list = av_realloc_array(list, sizeof(*list), ++count); \
if (!list) { \ if (!list) { \
err = AVERROR(ENOMEM); \ 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) } while(0)
static const struct { static const struct {
...@@ -261,7 +265,7 @@ static VkBool32 vk_dbg_callback(VkDebugUtilsMessageSeverityFlagBitsEXT severity, ...@@ -261,7 +265,7 @@ static VkBool32 vk_dbg_callback(VkDebugUtilsMessageSeverityFlagBitsEXT severity,
return 0; 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 * const **dst, uint32_t *num, int debug)
{ {
const char *tstr; const char *tstr;
...@@ -273,6 +277,8 @@ static int check_extensions(AVHWDeviceContext *ctx, int dev, ...@@ -273,6 +277,8 @@ static int check_extensions(AVHWDeviceContext *ctx, int dev,
const char *mod; const char *mod;
int optional_exts_num; int optional_exts_num;
uint32_t sup_ext_count; uint32_t sup_ext_count;
char *user_exts_str = NULL;
AVDictionaryEntry *user_exts;
VkExtensionProperties *sup_ext; VkExtensionProperties *sup_ext;
const VulkanOptExtension *optional_exts; const VulkanOptExtension *optional_exts;
...@@ -280,6 +286,14 @@ static int check_extensions(AVHWDeviceContext *ctx, int dev, ...@@ -280,6 +286,14 @@ static int check_extensions(AVHWDeviceContext *ctx, int dev,
mod = "instance"; mod = "instance";
optional_exts = optional_instance_exts; optional_exts = optional_instance_exts;
optional_exts_num = FF_ARRAY_ELEMS(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); vkEnumerateInstanceExtensionProperties(NULL, &sup_ext_count, NULL);
sup_ext = av_malloc_array(sup_ext_count, sizeof(VkExtensionProperties)); sup_ext = av_malloc_array(sup_ext_count, sizeof(VkExtensionProperties));
if (!sup_ext) if (!sup_ext)
...@@ -289,6 +303,14 @@ static int check_extensions(AVHWDeviceContext *ctx, int dev, ...@@ -289,6 +303,14 @@ static int check_extensions(AVHWDeviceContext *ctx, int dev,
mod = "device"; mod = "device";
optional_exts = optional_device_exts; optional_exts = optional_device_exts;
optional_exts_num = FF_ARRAY_ELEMS(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, vkEnumerateDeviceExtensionProperties(hwctx->phys_dev, NULL,
&sup_ext_count, NULL); &sup_ext_count, NULL);
sup_ext = av_malloc_array(sup_ext_count, sizeof(VkExtensionProperties)); sup_ext = av_malloc_array(sup_ext_count, sizeof(VkExtensionProperties));
...@@ -336,19 +358,52 @@ static int check_extensions(AVHWDeviceContext *ctx, int dev, ...@@ -336,19 +358,52 @@ static int check_extensions(AVHWDeviceContext *ctx, int dev,
} }
} }
if (found) { if (found) {
av_log(ctx, AV_LOG_VERBOSE, "Using %s extension \"%s\"\n", mod, tstr);
ADD_VAL_TO_LIST(extension_names, extensions_found, tstr); ADD_VAL_TO_LIST(extension_names, extensions_found, tstr);
} else { } else {
av_log(ctx, AV_LOG_ERROR, "Debug extension \"%s\" not found!\n", av_log(ctx, AV_LOG_ERROR, "Debug extension \"%s\" not found!\n",
tstr); tstr);
err = AVERROR(EINVAL); 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; *dst = extension_names;
*num = extensions_found; *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); av_free(sup_ext);
return err; return err;
} }
...@@ -376,7 +431,7 @@ static int create_instance(AVHWDeviceContext *ctx, AVDictionary *opts) ...@@ -376,7 +431,7 @@ static int create_instance(AVHWDeviceContext *ctx, AVDictionary *opts)
}; };
/* Check for present/missing extensions */ /* 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); &inst_props.enabledExtensionCount, debug_mode);
if (err < 0) if (err < 0)
return err; return err;
...@@ -391,6 +446,8 @@ static int create_instance(AVHWDeviceContext *ctx, AVDictionary *opts) ...@@ -391,6 +446,8 @@ static int create_instance(AVHWDeviceContext *ctx, AVDictionary *opts)
ret = vkCreateInstance(&inst_props, hwctx->alloc, &hwctx->inst); ret = vkCreateInstance(&inst_props, hwctx->alloc, &hwctx->inst);
/* Free used memory */ /* 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); av_free((void *)inst_props.ppEnabledExtensionNames);
/* Check for errors */ /* Check for errors */
...@@ -777,13 +834,15 @@ static int vulkan_device_create_internal(AVHWDeviceContext *ctx, ...@@ -777,13 +834,15 @@ static int vulkan_device_create_internal(AVHWDeviceContext *ctx,
if ((err = search_queue_families(ctx, &dev_info))) if ((err = search_queue_families(ctx, &dev_info)))
goto end; 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))) &dev_info.enabledExtensionCount, 0)))
goto end; goto end;
ret = vkCreateDevice(hwctx->phys_dev, &dev_info, hwctx->alloc, ret = vkCreateDevice(hwctx->phys_dev, &dev_info, hwctx->alloc,
&hwctx->act_dev); &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); av_free((void *)dev_info.ppEnabledExtensionNames);
if (ret != VK_SUCCESS) { if (ret != VK_SUCCESS) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment