diff mbox series

[FFmpeg-devel,V2,5/5] libavutil/hwcontext_vulkan: specify the modifier to create VKImage

Message ID 20211124052848.1122682-5-wenbin.chen@intel.com
State New
Headers show
Series [FFmpeg-devel,V2,1/5] hwcontext_vaapi: Use PRIME_2 memory type for modifiers. | expand

Checks

Context Check Description
andriy/make_x86 success Make finished
andriy/make_fate_x86 success Make fate finished
andriy/make_ppc success Make finished
andriy/make_fate_ppc success Make fate finished

Commit Message

Wenbin Chen Nov. 24, 2021, 5:28 a.m. UTC
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@intel.com>
---
 libavutil/hwcontext_vulkan.c | 130 +++++++++++++++++++++++++++++++++--
 1 file changed, 124 insertions(+), 6 deletions(-)

Comments

Lynne Nov. 24, 2021, 11:17 a.m. UTC | #1
24 Nov 2021, 06:28 by wenbin.chen@intel.com:

> 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@intel.com>
> ---
>  libavutil/hwcontext_vulkan.c | 130 +++++++++++++++++++++++++++++++++--
>  1 file changed, 124 insertions(+), 6 deletions(-)
>
> diff --git a/libavutil/hwcontext_vulkan.c b/libavutil/hwcontext_vulkan.c
> index 6421115385..4b951fb202 100644
> --- a/libavutil/hwcontext_vulkan.c
> +++ b/libavutil/hwcontext_vulkan.c
> @@ -230,6 +230,28 @@ const VkFormat *av_vkfmt_from_pixfmt(enum AVPixelFormat p)
>  return NULL;
>  }
>  
> +static void *find_in_structure_list(VkBaseOutStructure *stru_list, VkStructureType sType) {
> +    if (!stru_list)
> +        return NULL;
> +
> +    for(;stru_list;stru_list = stru_list->pNext)
> +        if (stru_list->sType == sType)
> +            return stru_list;
> +
> +    return NULL;
> +}
> +
> +static void append_to_structure_list(VkBaseOutStructure **stru_list, VkBaseOutStructure *added_stru) {
> +    VkBaseOutStructure *p;
> +    if (!*stru_list) {
> +        *stru_list = added_stru;
> +        return;
> +    }
> +    for(p = *stru_list; p->pNext; p = p->pNext);
> +    p->pNext = added_stru;
> +    return;
> +}
> +
>  static int pixfmt_is_supported(AVHWDeviceContext *dev_ctx, enum AVPixelFormat p,
>  int linear)
>  {
> @@ -1979,6 +2001,10 @@ 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 int has_modifiers = hwctx->tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT;
> +    int loop_count;
> +    VkImageDrmFormatModifierListCreateInfoEXT *modifier_info = find_in_structure_list(hwctx->create_pnext,
> +                                        VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT);
>  VkExternalImageFormatProperties eprops = {
>  .sType = VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES_KHR,
>  };
> @@ -1986,9 +2012,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_modifiers && modifier_info ? &phy_dev_mod_info : NULL,
>  };
>  VkPhysicalDeviceImageFormatInfo2 pinfo = {
>  .sType  = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,
> @@ -2000,11 +2035,16 @@ 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;
> +    loop_count = has_modifiers && modifier_info ? modifier_info->drmFormatModifierCount : 1;
> +    for (int i = 0; i < loop_count; i++) {
> +        if (has_modifiers && modifier_info)
> +            phy_dev_mod_info.drmFormatModifier = modifier_info->pDrmFormatModifiers[i];
> +        ret = vk->GetPhysicalDeviceImageFormatProperties2(dev_hwctx->phys_dev,
> +                                                        &pinfo, &props);
> +        if (ret == VK_SUCCESS) {
> +            *iexp |= exp;
> +            *comp_handle_types |= eprops.externalMemoryProperties.compatibleHandleTypes;
> +        }
>  }
>  }
>  
> @@ -2074,6 +2114,20 @@ fail:
>  static void vulkan_frames_uninit(AVHWFramesContext *hwfc)
>  {
>  VulkanFramesPriv *fp = hwfc->internal->priv;
> +    AVVulkanFramesContext *hwctx = hwfc->hwctx;
> +    VkBaseOutStructure *structure_p_next,*structure_p = hwctx->create_pnext;
> +    VkImageDrmFormatModifierListCreateInfoEXT *modifier_info;
> +    while (structure_p) {
> +        structure_p_next = structure_p->pNext;
> +        switch (structure_p->sType) {
> +        case VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT:
> +            modifier_info = (VkImageDrmFormatModifierListCreateInfoEXT *)structure_p;
> +            av_freep(&modifier_info->pDrmFormatModifiers);
> +            av_freep(&modifier_info);
> +            break;
> +        }
> +        structure_p = structure_p_next;
>

This will also free the API user's fields in VkImageDrmFormatModifierListCreateInfoEXT.
If the code below doesn't find the struct in create_pnext, it should allocate the struct,
append it to create_pnext, and save a pointer of it in VulkanFramesPriv,
where if it does exist, it should be freed here in `uninit`.


> +    }
>  
>  free_exec_ctx(hwfc, &fp->conv_ctx);
>  free_exec_ctx(hwfc, &fp->upload_ctx);
> @@ -2088,11 +2142,75 @@ 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 int has_modifiers = !!(p->extensions & FF_VK_EXT_DRM_MODIFIER_FLAGS);
>  
>  /* Default pool flags */
> -    hwctx->tiling = hwctx->tiling ? hwctx->tiling : p->use_linear_images ?
> +    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;
>  
> +    /* get the supported modifier */
> +    if (has_modifiers) {
>

If VkImageDrmFormatModifierListCreateInfoEXT is present in
`hwctx->create_pnext`, shouldn't you use it directly, instead of searching?


> +        const VkFormat *fmt = av_vkfmt_from_pixfmt(hwfc->sw_format);
> +        FFVulkanFunctions *vk = &p->vkfn;
> +        VkImageDrmFormatModifierListCreateInfoEXT *modifier_info;
> +        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,
> +        };
> +        vk->GetPhysicalDeviceFormatProperties2(dev_hwctx->phys_dev, fmt[0], &prop);
> +        if (!mod_props_list.drmFormatModifierCount) {
> +            av_log(hwfc, AV_LOG_ERROR, "There are not supported modifiers for sw_format\n");
> +            return AVERROR(EINVAL);
> +        }
> +
> +        modifier_info = av_malloc(sizeof(*modifier_info));
> +        if (!modifier_info)
> +            return AVERROR(ENOMEM);
> +        append_to_structure_list((VkBaseOutStructure **)&hwctx->create_pnext,
> +                                 (VkBaseOutStructure *)modifier_info);
> +        modifier_info->pNext = NULL;
> +        modifier_info->sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT;
> +
> +        modifiers = av_malloc(mod_props_list.drmFormatModifierCount *
> +                              sizeof(*modifiers));
> +        if (!modifiers)
> +            return AVERROR(ENOMEM);
> +        modifier_info->pDrmFormatModifiers = modifiers;
> +
> +        mod_props = av_malloc(mod_props_list.drmFormatModifierCount *
> +                              sizeof(*mod_props));
> +        if (!mod_props)
> +            return AVERROR(ENOMEM);
> +        mod_props_list.pDrmFormatModifierProperties = mod_props;
> +        vk->GetPhysicalDeviceFormatProperties2(dev_hwctx->phys_dev, fmt[0], &prop);
> +        for (int i = 0; i < mod_props_list.drmFormatModifierCount; i++) {
> +            if (!(mod_props[i].drmFormatModifierTilingFeatures & FF_VK_DEFAULT_USAGE_FLAGS))
> +                continue;
> +            modifiers[modifier_count++] = mod_props[i].drmFormatModifier;
> +        }
> +        if (!modifier_count) {
> +            av_log(hwfc, AV_LOG_ERROR, "The supported modifiers doesn't support "
> +                                       "default usage\n");
> +            av_freep(&mod_props);
> +            return AVERROR(EINVAL);
> +        }
> +        modifier_info->drmFormatModifierCount = modifier_count;
> +        av_freep(&mod_props);
> +    }
> +
> +
>  if (!hwctx->usage)
>  hwctx->usage = FF_VK_DEFAULT_USAGE_FLAGS; 
>

Good, this patch as all the right ideas. I discussed with haasn,
the libplacebo author, and indeed, we should set the tiling of output
images to DRM if not explicitly specified in hwfc and exporting to
DRM is possible. Just make the changes I mentioned and resubmit.
diff mbox series

Patch

diff --git a/libavutil/hwcontext_vulkan.c b/libavutil/hwcontext_vulkan.c
index 6421115385..4b951fb202 100644
--- a/libavutil/hwcontext_vulkan.c
+++ b/libavutil/hwcontext_vulkan.c
@@ -230,6 +230,28 @@  const VkFormat *av_vkfmt_from_pixfmt(enum AVPixelFormat p)
     return NULL;
 }
 
+static void *find_in_structure_list(VkBaseOutStructure *stru_list, VkStructureType sType) {
+    if (!stru_list)
+        return NULL;
+
+    for(;stru_list;stru_list = stru_list->pNext)
+        if (stru_list->sType == sType)
+            return stru_list;
+
+    return NULL;
+}
+
+static void append_to_structure_list(VkBaseOutStructure **stru_list, VkBaseOutStructure *added_stru) {
+    VkBaseOutStructure *p;
+    if (!*stru_list) {
+        *stru_list = added_stru;
+        return;
+    }
+    for(p = *stru_list; p->pNext; p = p->pNext);
+    p->pNext = added_stru;
+    return;
+}
+
 static int pixfmt_is_supported(AVHWDeviceContext *dev_ctx, enum AVPixelFormat p,
                                int linear)
 {
@@ -1979,6 +2001,10 @@  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 int has_modifiers = hwctx->tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT;
+    int loop_count;
+    VkImageDrmFormatModifierListCreateInfoEXT *modifier_info = find_in_structure_list(hwctx->create_pnext,
+                                        VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT);
     VkExternalImageFormatProperties eprops = {
         .sType = VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES_KHR,
     };
@@ -1986,9 +2012,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_modifiers && modifier_info ? &phy_dev_mod_info : NULL,
     };
     VkPhysicalDeviceImageFormatInfo2 pinfo = {
         .sType  = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,
@@ -2000,11 +2035,16 @@  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;
+    loop_count = has_modifiers && modifier_info ? modifier_info->drmFormatModifierCount : 1;
+    for (int i = 0; i < loop_count; i++) {
+        if (has_modifiers && modifier_info)
+            phy_dev_mod_info.drmFormatModifier = modifier_info->pDrmFormatModifiers[i];
+        ret = vk->GetPhysicalDeviceImageFormatProperties2(dev_hwctx->phys_dev,
+                                                        &pinfo, &props);
+        if (ret == VK_SUCCESS) {
+            *iexp |= exp;
+            *comp_handle_types |= eprops.externalMemoryProperties.compatibleHandleTypes;
+        }
     }
 }
 
@@ -2074,6 +2114,20 @@  fail:
 static void vulkan_frames_uninit(AVHWFramesContext *hwfc)
 {
     VulkanFramesPriv *fp = hwfc->internal->priv;
+    AVVulkanFramesContext *hwctx = hwfc->hwctx;
+    VkBaseOutStructure *structure_p_next,*structure_p = hwctx->create_pnext;
+    VkImageDrmFormatModifierListCreateInfoEXT *modifier_info;
+    while (structure_p) {
+        structure_p_next = structure_p->pNext;
+        switch (structure_p->sType) {
+        case VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT:
+            modifier_info = (VkImageDrmFormatModifierListCreateInfoEXT *)structure_p;
+            av_freep(&modifier_info->pDrmFormatModifiers);
+            av_freep(&modifier_info);
+            break;
+        }
+        structure_p = structure_p_next;
+    }
 
     free_exec_ctx(hwfc, &fp->conv_ctx);
     free_exec_ctx(hwfc, &fp->upload_ctx);
@@ -2088,11 +2142,75 @@  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 int has_modifiers = !!(p->extensions & FF_VK_EXT_DRM_MODIFIER_FLAGS);
 
     /* Default pool flags */
-    hwctx->tiling = hwctx->tiling ? hwctx->tiling : p->use_linear_images ?
+    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;
 
+    /* get the supported modifier */
+    if (has_modifiers) {
+        const VkFormat *fmt = av_vkfmt_from_pixfmt(hwfc->sw_format);
+        FFVulkanFunctions *vk = &p->vkfn;
+        VkImageDrmFormatModifierListCreateInfoEXT *modifier_info;
+        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,
+        };
+        vk->GetPhysicalDeviceFormatProperties2(dev_hwctx->phys_dev, fmt[0], &prop);
+        if (!mod_props_list.drmFormatModifierCount) {
+            av_log(hwfc, AV_LOG_ERROR, "There are not supported modifiers for sw_format\n");
+            return AVERROR(EINVAL);
+        }
+
+        modifier_info = av_malloc(sizeof(*modifier_info));
+        if (!modifier_info)
+            return AVERROR(ENOMEM);
+        append_to_structure_list((VkBaseOutStructure **)&hwctx->create_pnext,
+                                 (VkBaseOutStructure *)modifier_info);
+        modifier_info->pNext = NULL;
+        modifier_info->sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT;
+
+        modifiers = av_malloc(mod_props_list.drmFormatModifierCount *
+                              sizeof(*modifiers));
+        if (!modifiers)
+            return AVERROR(ENOMEM);
+        modifier_info->pDrmFormatModifiers = modifiers;
+
+        mod_props = av_malloc(mod_props_list.drmFormatModifierCount *
+                              sizeof(*mod_props));
+        if (!mod_props)
+            return AVERROR(ENOMEM);
+        mod_props_list.pDrmFormatModifierProperties = mod_props;
+        vk->GetPhysicalDeviceFormatProperties2(dev_hwctx->phys_dev, fmt[0], &prop);
+        for (int i = 0; i < mod_props_list.drmFormatModifierCount; i++) {
+            if (!(mod_props[i].drmFormatModifierTilingFeatures & FF_VK_DEFAULT_USAGE_FLAGS))
+                continue;
+            modifiers[modifier_count++] = mod_props[i].drmFormatModifier;
+        }
+        if (!modifier_count) {
+            av_log(hwfc, AV_LOG_ERROR, "The supported modifiers doesn't support "
+                                       "default usage\n");
+            av_freep(&mod_props);
+            return AVERROR(EINVAL);
+        }
+        modifier_info->drmFormatModifierCount = modifier_count;
+        av_freep(&mod_props);
+    }
+
+
     if (!hwctx->usage)
         hwctx->usage = FF_VK_DEFAULT_USAGE_FLAGS;