[FFmpeg-cvslog] hwcontext_vulkan: support creating DRM-tiled images and autodetecting modifiers
Wenbin Chen
git at videolan.org
Fri Dec 10 18:05:06 EET 2021
ffmpeg | branch: master | Wenbin Chen <wenbin.chen at intel.com> | Tue Dec 7 17:05:53 2021 +0800| [83fe28221e92921f74d99ed15c258a3c79f4441d] | committer: Lynne
hwcontext_vulkan: support creating DRM-tiled images and autodetecting modifiers
When vulkan image exports to drm, the tilling need to be
VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT. Now add code to create vulkan
image using this format.
Now the following command line works:
ffmpeg -hwaccel vaapi -hwaccel_device /dev/dri/renderD128 -hwaccel_output_format \
vaapi -i input_1080p.264 -vf "hwmap=derive_device=vulkan,format=vulkan, \
scale_vulkan=1920:1080,hwmap=derive_device=vaapi,format=vaapi" -c:v h264_vaapi output.264
Signed-off-by: Wenbin Chen <wenbin.chen at intel.com>
Further-modifications-by: Lynne <dev at lynne.ee>
> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=83fe28221e92921f74d99ed15c258a3c79f4441d
---
libavutil/hwcontext_vulkan.c | 163 ++++++++++++++++++++++++++++++++++++++++---
libavutil/hwcontext_vulkan.h | 11 ++-
2 files changed, 165 insertions(+), 9 deletions(-)
diff --git a/libavutil/hwcontext_vulkan.c b/libavutil/hwcontext_vulkan.c
index 728f800bb2..507c4f4454 100644
--- a/libavutil/hwcontext_vulkan.c
+++ b/libavutil/hwcontext_vulkan.c
@@ -120,6 +120,9 @@ typedef struct VulkanFramesPriv {
/* Image transfers */
VulkanExecCtx upload_ctx;
VulkanExecCtx download_ctx;
+
+ /* Modifier info list to free at uninit */
+ VkImageDrmFormatModifierListCreateInfoEXT *modifier_info;
} VulkanFramesPriv;
typedef struct AVVkFrameInternal {
@@ -240,6 +243,31 @@ const VkFormat *av_vkfmt_from_pixfmt(enum AVPixelFormat p)
return NULL;
}
+static const void *vk_find_struct(const void *chain, VkStructureType stype)
+{
+ const VkBaseInStructure *in = chain;
+ while (in) {
+ if (in->sType == stype)
+ return in;
+
+ in = in->pNext;
+ }
+
+ return NULL;
+}
+
+static void vk_link_struct(void *chain, void *in)
+{
+ VkBaseOutStructure *out = chain;
+ if (!in)
+ return;
+
+ while (out->pNext)
+ out = out->pNext;
+
+ out->pNext = in;
+}
+
static int pixfmt_is_supported(AVHWDeviceContext *dev_ctx, enum AVPixelFormat p,
int linear)
{
@@ -2099,6 +2127,13 @@ static void try_export_flags(AVHWFramesContext *hwfc,
AVVulkanDeviceContext *dev_hwctx = hwfc->device_ctx->hwctx;
VulkanDevicePriv *p = hwfc->device_ctx->internal->priv;
FFVulkanFunctions *vk = &p->vkfn;
+
+ const VkImageDrmFormatModifierListCreateInfoEXT *drm_mod_info =
+ vk_find_struct(hwctx->create_pnext,
+ VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT);
+ int has_mods = hwctx->tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT && drm_mod_info;
+ int nb_mods;
+
VkExternalImageFormatProperties eprops = {
.sType = VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES_KHR,
};
@@ -2106,9 +2141,18 @@ static void try_export_flags(AVHWFramesContext *hwfc,
.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2,
.pNext = &eprops,
};
+ VkPhysicalDeviceImageDrmFormatModifierInfoEXT phy_dev_mod_info = {
+ .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT,
+ .pNext = NULL,
+ .pQueueFamilyIndices = p->qfs,
+ .queueFamilyIndexCount = p->num_qfs,
+ .sharingMode = p->num_qfs > 1 ? VK_SHARING_MODE_CONCURRENT :
+ VK_SHARING_MODE_EXCLUSIVE,
+ };
VkPhysicalDeviceExternalImageFormatInfo enext = {
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO,
.handleType = exp,
+ .pNext = has_mods ? &phy_dev_mod_info : NULL,
};
VkPhysicalDeviceImageFormatInfo2 pinfo = {
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,
@@ -2120,11 +2164,18 @@ static void try_export_flags(AVHWFramesContext *hwfc,
.flags = VK_IMAGE_CREATE_ALIAS_BIT,
};
- ret = vk->GetPhysicalDeviceImageFormatProperties2(dev_hwctx->phys_dev,
- &pinfo, &props);
- if (ret == VK_SUCCESS) {
- *iexp |= exp;
- *comp_handle_types |= eprops.externalMemoryProperties.compatibleHandleTypes;
+ nb_mods = has_mods ? drm_mod_info->drmFormatModifierCount : 1;
+ for (int i = 0; i < nb_mods; i++) {
+ if (has_mods)
+ phy_dev_mod_info.drmFormatModifier = drm_mod_info->pDrmFormatModifiers[i];
+
+ ret = vk->GetPhysicalDeviceImageFormatProperties2(dev_hwctx->phys_dev,
+ &pinfo, &props);
+
+ if (ret == VK_SUCCESS) {
+ *iexp |= exp;
+ *comp_handle_types |= eprops.externalMemoryProperties.compatibleHandleTypes;
+ }
}
}
@@ -2195,6 +2246,12 @@ static void vulkan_frames_uninit(AVHWFramesContext *hwfc)
{
VulkanFramesPriv *fp = hwfc->internal->priv;
+ if (fp->modifier_info) {
+ if (fp->modifier_info->pDrmFormatModifiers)
+ av_freep(&fp->modifier_info->pDrmFormatModifiers);
+ av_freep(&fp->modifier_info);
+ }
+
free_exec_ctx(hwfc, &fp->conv_ctx);
free_exec_ctx(hwfc, &fp->upload_ctx);
free_exec_ctx(hwfc, &fp->download_ctx);
@@ -2208,10 +2265,14 @@ static int vulkan_frames_init(AVHWFramesContext *hwfc)
VulkanFramesPriv *fp = hwfc->internal->priv;
AVVulkanDeviceContext *dev_hwctx = hwfc->device_ctx->hwctx;
VulkanDevicePriv *p = hwfc->device_ctx->internal->priv;
+ const VkImageDrmFormatModifierListCreateInfoEXT *modifier_info;
+ const int has_modifiers = !!(p->extensions & FF_VK_EXT_DRM_MODIFIER_FLAGS);
- /* Default pool flags */
- hwctx->tiling = hwctx->tiling ? hwctx->tiling : p->use_linear_images ?
- VK_IMAGE_TILING_LINEAR : VK_IMAGE_TILING_OPTIMAL;
+ /* Default tiling flags */
+ hwctx->tiling = hwctx->tiling ? hwctx->tiling :
+ has_modifiers ? VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT :
+ p->use_linear_images ? VK_IMAGE_TILING_LINEAR :
+ VK_IMAGE_TILING_OPTIMAL;
if (!hwctx->usage)
hwctx->usage = FF_VK_DEFAULT_USAGE_FLAGS;
@@ -2222,6 +2283,92 @@ static int vulkan_frames_init(AVHWFramesContext *hwfc)
hwctx->flags |= AV_VK_FRAME_FLAG_CONTIGUOUS_MEMORY;
}
+ modifier_info = vk_find_struct(hwctx->create_pnext,
+ VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT);
+
+ /* Get the supported modifiers if the user has not given any. */
+ if (has_modifiers && !modifier_info) {
+ const VkFormat *fmt = av_vkfmt_from_pixfmt(hwfc->sw_format);
+ VkImageDrmFormatModifierListCreateInfoEXT *modifier_info;
+ FFVulkanFunctions *vk = &p->vkfn;
+ VkDrmFormatModifierPropertiesEXT *mod_props;
+ uint64_t *modifiers;
+ int modifier_count = 0;
+
+ VkDrmFormatModifierPropertiesListEXT mod_props_list = {
+ .sType = VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT,
+ .pNext = NULL,
+ .drmFormatModifierCount = 0,
+ .pDrmFormatModifierProperties = NULL,
+ };
+ VkFormatProperties2 prop = {
+ .sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2,
+ .pNext = &mod_props_list,
+ };
+
+ /* Get all supported modifiers */
+ vk->GetPhysicalDeviceFormatProperties2(dev_hwctx->phys_dev, fmt[0], &prop);
+
+ if (!mod_props_list.drmFormatModifierCount) {
+ av_log(hwfc, AV_LOG_ERROR, "There are no supported modifiers for the given sw_format\n");
+ return AVERROR(EINVAL);
+ }
+
+ /* Createa structure to hold the modifier list info */
+ modifier_info = av_mallocz(sizeof(*modifier_info));
+ if (!modifier_info)
+ return AVERROR(ENOMEM);
+
+ modifier_info->pNext = NULL;
+ modifier_info->sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT;
+
+ /* Add structure to the image creation pNext chain */
+ if (!hwctx->create_pnext)
+ hwctx->create_pnext = modifier_info;
+ else
+ vk_link_struct(hwctx->create_pnext, (void *)modifier_info);
+
+ /* Backup the allocated struct to be freed later */
+ fp->modifier_info = modifier_info;
+
+ /* Allocate list of modifiers */
+ modifiers = av_mallocz(mod_props_list.drmFormatModifierCount *
+ sizeof(*modifiers));
+ if (!modifiers)
+ return AVERROR(ENOMEM);
+
+ modifier_info->pDrmFormatModifiers = modifiers;
+
+ /* Allocate a temporary list to hold all modifiers supported */
+ mod_props = av_mallocz(mod_props_list.drmFormatModifierCount *
+ sizeof(*mod_props));
+ if (!mod_props)
+ return AVERROR(ENOMEM);
+
+ mod_props_list.pDrmFormatModifierProperties = mod_props;
+
+ /* Finally get all modifiers from the device */
+ vk->GetPhysicalDeviceFormatProperties2(dev_hwctx->phys_dev, fmt[0], &prop);
+
+ /* Reject any modifiers that don't match our requirements */
+ for (int i = 0; i < mod_props_list.drmFormatModifierCount; i++) {
+ if (!(mod_props[i].drmFormatModifierTilingFeatures & hwctx->usage))
+ continue;
+
+ modifiers[modifier_count++] = mod_props[i].drmFormatModifier;
+ }
+
+ if (!modifier_count) {
+ av_log(hwfc, AV_LOG_ERROR, "None of the given modifiers supports"
+ " the usage flags!\n");
+ av_freep(&mod_props);
+ return AVERROR(EINVAL);
+ }
+
+ modifier_info->drmFormatModifierCount = modifier_count;
+ av_freep(&mod_props);
+ }
+
err = create_exec_ctx(hwfc, &fp->conv_ctx,
dev_hwctx->queue_family_comp_index,
dev_hwctx->nb_comp_queues);
diff --git a/libavutil/hwcontext_vulkan.h b/libavutil/hwcontext_vulkan.h
index ed59fe9f0a..8de79f5f33 100644
--- a/libavutil/hwcontext_vulkan.h
+++ b/libavutil/hwcontext_vulkan.h
@@ -156,7 +156,10 @@ typedef enum AVVkFrameFlags {
*/
typedef struct AVVulkanFramesContext {
/**
- * Controls the tiling of allocated frames.
+ * Controls the tiling of allocated frames. If left as optimal tiling,
+ * then during av_hwframe_ctx_init() will decide based on whether the device
+ * supports DRM modifiers, or if the linear_images flag is set, otherwise
+ * will allocate optimally-tiled images.
*/
VkImageTiling tiling;
@@ -168,6 +171,12 @@ typedef struct AVVulkanFramesContext {
/**
* Extension data for image creation.
+ * If VkImageDrmFormatModifierListCreateInfoEXT is present in the chain,
+ * and the device supports DRM modifiers, then images will be allocated
+ * with the specific requested DRM modifiers.
+ * Additional structures may be added at av_hwframe_ctx_init() time,
+ * which will be freed automatically on uninit(), so users need only free
+ * any structures they've allocated themselves.
*/
void *create_pnext;
More information about the ffmpeg-cvslog
mailing list