This is an automated email from the git hooks/post-receive script. Git pushed a commit to branch master in repository ffmpeg.
commit cc50be6d0dd0b1fd518b5f12d44a8f163ddafdf1 Author: Kacper Michajłow <[email protected]> AuthorDate: Sat Jun 27 07:20:46 2026 +0200 Commit: Kacper Michajłow <[email protected]> CommitDate: Mon Aug 17 17:23:43 2026 +0200 avutil/hwcontext_vulkan: probe host image transfer support before enabling Drivers may expose the host image transfer format feature, yet reject the final image parameter combination, or provide no memory type from which such an image can be allocated. Notably video decode/encode images are often not possible to allocate from host visible memory type. Validate the final image parameters, including DRM format modifiers, and keep the usage flag only when it is actually usable. Fixes: #21704 Co-authored-by: llyyr <[email protected]> Signed-off-by: Kacper Michajłow <[email protected]> --- libavutil/hwcontext_vulkan.c | 134 +++++++++++++++++++++++++++++++++++++++++++ libavutil/vulkan_functions.h | 1 + 2 files changed, 135 insertions(+) diff --git a/libavutil/hwcontext_vulkan.c b/libavutil/hwcontext_vulkan.c index 2b671beb2a..773fea56fe 100644 --- a/libavutil/hwcontext_vulkan.c +++ b/libavutil/hwcontext_vulkan.c @@ -2990,6 +2990,135 @@ static void vulkan_frames_uninit(AVHWFramesContext *hwfc) av_refstruct_pool_uninit(&fp->tmp); } +/* Probes whether the host transfer usage bit is actually usable in combination + * with the rest of the image creation parameters. Drivers may expose the + * format feature, yet reject the final image, or provide no memory type from + * which such an image can be allocated. Notably video decode/encode images + * are often not possible to allocate from the host visible memory type. */ +static int vulkan_host_transfer_usable(AVHWFramesContext *hwfc) +{ + VulkanFramesPriv *fp = hwfc->hwctx; + AVVulkanFramesContext *hwctx = &fp->p; + VulkanDevicePriv *p = hwfc->device_ctx->hwctx; + AVVulkanDeviceContext *dev_hwctx = &p->p; + FFVulkanFunctions *vk = &p->vkctx.vkfn; + VkResult ret; + + const VkImageDrmFormatModifierListCreateInfoEXT *mod_list = + ff_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 && + mod_list && mod_list->drmFormatModifierCount; + int nb_mods = has_mods ? mod_list->drmFormatModifierCount : 1; + + /* Without a modifier list the final modifier is not knowable here. */ + if (hwctx->tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT && !has_mods) + return 0; + + VkPhysicalDeviceImageDrmFormatModifierInfoEXT mod_info = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT, + .pQueueFamilyIndices = p->img_qfs, + .queueFamilyIndexCount = p->nb_img_qfs, + .sharingMode = p->nb_img_qfs > 1 ? VK_SHARING_MODE_CONCURRENT : + VK_SHARING_MODE_EXCLUSIVE, + }; + VkPhysicalDeviceImageFormatInfo2 pinfo = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2, + .type = VK_IMAGE_TYPE_2D, + .tiling = hwctx->tiling, + .usage = hwctx->usage, + .flags = hwctx->img_flags, + }; + + if (has_mods) + ff_vk_link_struct(&pinfo, &mod_info); + + VkVideoProfileListInfoKHR profile_list; + const VkVideoProfileListInfoKHR *pl = + ff_vk_find_struct(hwctx->create_pnext, + VK_STRUCTURE_TYPE_VIDEO_PROFILE_LIST_INFO_KHR); + if (pl) { + profile_list = *pl; + profile_list.pNext = NULL; + ff_vk_link_struct(&pinfo, &profile_list); + } + + VkImageFormatListCreateInfo format_list; + const VkImageFormatListCreateInfo *fl = + ff_vk_find_struct(hwctx->create_pnext, + VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO); + if (fl) { + format_list = *fl; + format_list.pNext = NULL; + ff_vk_link_struct(&pinfo, &format_list); + } + + /* The same usage is applied to the images of every plane, so each plane + * format has to support host transfers for the usage to be usable. */ + for (int i = 0; i < AV_NUM_DATA_POINTERS && + hwctx->format[i] != VK_FORMAT_UNDEFINED; i++) { + pinfo.format = hwctx->format[i]; + + /* The driver is free to pick any modifier from the list, so all of + * them have to be compatible. */ + for (int j = 0; j < nb_mods; j++) { + VkImageFormatProperties2 props = { + .sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2, + }; + + if (has_mods) + mod_info.drmFormatModifier = mod_list->pDrmFormatModifiers[j]; + + ret = vk->GetPhysicalDeviceImageFormatProperties2(dev_hwctx->phys_dev, + &pinfo, &props); + if (ret != VK_SUCCESS) { + av_log(hwfc, AV_LOG_VERBOSE, "Disabling host image transfers: " + "format %i is not supported: %s\n", + pinfo.format, ff_vk_ret2str(ret)); + return 0; + } + } + } + + if (!p->vkctx.host_image_props.identicalMemoryTypeRequirements) { + VkImageCreateInfo create_info = { + .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, + .pNext = hwctx->create_pnext, + .imageType = VK_IMAGE_TYPE_2D, + .format = hwctx->format[0], + .extent = { hwfc->width, hwfc->height, 1 }, + .mipLevels = 1, + .arrayLayers = hwctx->nb_layers, + .flags = hwctx->img_flags, + .tiling = hwctx->tiling, + .usage = hwctx->usage, + .samples = VK_SAMPLE_COUNT_1_BIT, + .pQueueFamilyIndices = p->img_qfs, + .queueFamilyIndexCount = p->nb_img_qfs, + .sharingMode = p->nb_img_qfs > 1 ? VK_SHARING_MODE_CONCURRENT : + VK_SHARING_MODE_EXCLUSIVE, + }; + VkDeviceImageMemoryRequirements req_info = { + .sType = VK_STRUCTURE_TYPE_DEVICE_IMAGE_MEMORY_REQUIREMENTS, + .pCreateInfo = &create_info, + .planeAspect = hwctx->tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT ? + VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT : 0, + }; + VkMemoryRequirements2 req = { + .sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2, + }; + + vk->GetDeviceImageMemoryRequirements(dev_hwctx->act_dev, &req_info, &req); + if (!req.memoryRequirements.memoryTypeBits) { + av_log(hwfc, AV_LOG_VERBOSE, "Disabling host image transfers: " + "no compatible memory type\n"); + return 0; + } + } + + return 1; +} + static int vulkan_frames_init(AVHWFramesContext *hwfc) { int err; @@ -3128,6 +3257,11 @@ static int vulkan_frames_init(AVHWFramesContext *hwfc) } } + /* Drop the host transfer if it isn't usable for this image configuration. */ + if ((hwctx->usage & VK_IMAGE_USAGE_HOST_TRANSFER_BIT_EXT) && + !vulkan_host_transfer_usable(hwfc)) + hwctx->usage &= ~VK_IMAGE_USAGE_HOST_TRANSFER_BIT_EXT; + if (!hwctx->lock_frame) hwctx->lock_frame = lock_frame; diff --git a/libavutil/vulkan_functions.h b/libavutil/vulkan_functions.h index ff4076e9f5..16398ab9d0 100644 --- a/libavutil/vulkan_functions.h +++ b/libavutil/vulkan_functions.h @@ -171,6 +171,7 @@ typedef uint64_t FFVulkanExtensions; /* Image */ \ MACRO(1, 1, FF_VK_EXT_DRM_MODIFIER_FLAGS, GetImageDrmFormatModifierPropertiesEXT) \ MACRO(1, 1, FF_VK_EXT_NO_FLAG, GetImageMemoryRequirements2) \ + MACRO(1, 1, FF_VK_EXT_NO_FLAG, GetDeviceImageMemoryRequirements) \ MACRO(1, 1, FF_VK_EXT_NO_FLAG, CreateImage) \ MACRO(1, 1, FF_VK_EXT_NO_FLAG, BindImageMemory2) \ MACRO(1, 1, FF_VK_EXT_NO_FLAG, GetImageSubresourceLayout) \ -- To stop receiving notification emails like this one, please contact [email protected]. _______________________________________________ ffmpeg-cvslog mailing list -- [email protected] To unsubscribe send an email to [email protected]
