History

hwcontext_vulkan: fix exporting multi-plane DRM modifiers

Previously, it was assumed that `drmFormatModifierPlaneCount` was one for all modifiers when exporting, which is not always the case, in particular for AMD GPUs and maybe others. Fetch the number of memory planes and fill the structs appropriately in this situation. The encoded stream is still bad in the case whre modifers are involved, but I think this patch still stands on its own and I suspect that may be a driver bug. A potential improvement that could be make is to cache the format information, so we can avoid the two GetPhysicalDeviceFormatProperties2 calls for each export, as well as the allocation. I doubt this is very expensive, but seemed worth noting. v2 changes: query the format properties with the test image created in `vulkan_frames_init` to avoid allocating space for the query during export

Russell Greene committed 1 year ago

Commit e0440eb1 parent cc126af1 file · +94 −10Browse files

Unified · Split

libavutil/hwcontext_vulkan.c+94−10
@@ -172,6 +172,9 @@ typedef struct VulkanFramesPriv { · 171 unmodified lines
172 172
173 /* Modifier info list to free at uninit */173 /* Modifier info list to free at uninit */
174 VkImageDrmFormatModifierListCreateInfoEXT *modifier_info;174 VkImageDrmFormatModifierListCreateInfoEXT *modifier_info;
175
176 /* Properties for DRM modifier for each plane in the image */
177 VkDrmFormatModifierPropertiesEXT drm_format_modifier_properties[5];
175} VulkanFramesPriv;178} VulkanFramesPriv;
176 179
177typedef struct AVVkFrameInternal {180typedef struct AVVkFrameInternal {
@@ -2803,7 +2806,9 @@ static int vulkan_frames_init(AVHWFramesContext *hwfc) · 2625 unmodified lines
2803 VulkanFramesPriv *fp = hwfc->hwctx;2806 VulkanFramesPriv *fp = hwfc->hwctx;
2804 AVVulkanFramesContext *hwctx = &fp->p;2807 AVVulkanFramesContext *hwctx = &fp->p;
2805 VulkanDevicePriv *p = hwfc->device_ctx->hwctx;2808 VulkanDevicePriv *p = hwfc->device_ctx->hwctx;
2809 AVVulkanDeviceContext *dev_hwctx = &p->p;
2806 VkImageUsageFlagBits supported_usage;2810 VkImageUsageFlagBits supported_usage;
2811 FFVulkanFunctions *vk = &p->vkctx.vkfn;
2807 const struct FFVkFormatEntry *fmt;2812 const struct FFVkFormatEntry *fmt;
2808 int disable_multiplane = p->disable_multiplane ||2813 int disable_multiplane = p->disable_multiplane ||
2809 (hwctx->flags & AV_VK_FRAME_FLAG_DISABLE_MULTIPLANE);2814 (hwctx->flags & AV_VK_FRAME_FLAG_DISABLE_MULTIPLANE);
@@ -2949,6 +2954,63 @@ static int vulkan_frames_init(AVHWFramesContext *hwfc) · 139 unmodified lines
2949 if (err)2954 if (err)
2950 return err;2955 return err;
2951 2956
2957 /* Collect `VkDrmFormatModifierPropertiesEXT` for each plane. Required for DRM export. */
2958 if (p->vkctx.extensions & FF_VK_EXT_DRM_MODIFIER_FLAGS && hwctx->tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT) {
2959 VkImageDrmFormatModifierPropertiesEXT drm_mod = {
2960 .sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT,
2961 };
2962 err = vk->GetImageDrmFormatModifierPropertiesEXT(dev_hwctx->act_dev, f->img[0],
2963 &drm_mod);
2964 if (err != VK_SUCCESS) {
2965 av_log(hwfc, AV_LOG_ERROR, "Failed to get image DRM format modifier properties");
2966 vulkan_frame_free(hwfc, f);
2967 return AVERROR_EXTERNAL;
2968 }
2969 for (int i = 0; i < fmt->vk_planes; ++i) {
2970 VkDrmFormatModifierPropertiesListEXT modp;
2971 VkFormatProperties2 fmtp;
2972 VkDrmFormatModifierPropertiesEXT *mod_props = NULL;
2973
2974 modp = (VkDrmFormatModifierPropertiesListEXT) {
2975 .sType = VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT,
2976 };
2977 fmtp = (VkFormatProperties2) {
2978 .sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2,
2979 .pNext = &modp,
2980 };
2981
2982 /* query drmFormatModifierCount by keeping pDrmFormatModifierProperties NULL */
2983 vk->GetPhysicalDeviceFormatProperties2(dev_hwctx->phys_dev, fmt->fallback[i], &fmtp);
2984
2985 modp.pDrmFormatModifierProperties =
2986 av_calloc(modp.drmFormatModifierCount, sizeof(*modp.pDrmFormatModifierProperties));
2987 if (!modp.pDrmFormatModifierProperties) {
2988 vulkan_frame_free(hwfc, f);
2989 return AVERROR(ENOMEM);
2990 }
2991 vk->GetPhysicalDeviceFormatProperties2(dev_hwctx->phys_dev, fmt->fallback[i], &fmtp);
2992
2993 for (uint32_t i = 0; i < modp.drmFormatModifierCount; ++i) {
2994 VkDrmFormatModifierPropertiesEXT *m = &modp.pDrmFormatModifierProperties[i];
2995 if (m->drmFormatModifier == drm_mod.drmFormatModifier) {
2996 mod_props = m;
2997 break;
2998 }
2999 }
3000
3001 if (mod_props == NULL) {
3002 av_log(hwfc, AV_LOG_ERROR, "No DRM format modifier properties found for modifier 0x%016lx\n",
3003 drm_mod.drmFormatModifier);
3004 av_free(modp.pDrmFormatModifierProperties);
3005 vulkan_frame_free(hwfc, f);
3006 return AVERROR_EXTERNAL;
3007 }
3008
3009 fp->drm_format_modifier_properties[i] = *mod_props;
3010 av_free(modp.pDrmFormatModifierProperties);
3011 }
3012 }
3013
2952 vulkan_frame_free(hwfc, f);3014 vulkan_frame_free(hwfc, f);
2953 3015
2954 /* If user did not specify a pool, hwfc->pool will be set to the internal one3016 /* If user did not specify a pool, hwfc->pool will be set to the internal one
@@ -3879,6 +3941,17 @@ static inline uint32_t vulkan_fmt_to_drm(VkFormat vkfmt) · 924 unmodified lines
3879 return DRM_FORMAT_INVALID;3941 return DRM_FORMAT_INVALID;
3880}3942}
3881 3943
3944#define MAX_MEMORY_PLANES 4
3945static VkImageAspectFlags plane_index_to_aspect(int plane) {
3946 if (plane == 0) return VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT;
3947 if (plane == 1) return VK_IMAGE_ASPECT_MEMORY_PLANE_1_BIT_EXT;
3948 if (plane == 2) return VK_IMAGE_ASPECT_MEMORY_PLANE_2_BIT_EXT;
3949 if (plane == 3) return VK_IMAGE_ASPECT_MEMORY_PLANE_3_BIT_EXT;
3950
3951 av_assert2 (false && "Invalid plane index");
3952 return VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT;
3953}
3954
3882static int vulkan_map_to_drm(AVHWFramesContext *hwfc, AVFrame *dst,3955static int vulkan_map_to_drm(AVHWFramesContext *hwfc, AVFrame *dst,
3883 const AVFrame *src, int flags)3956 const AVFrame *src, int flags)
3884{3957{
@@ -3947,14 +4020,29 @@ static int vulkan_map_to_drm(AVHWFramesContext *hwfc, AVFrame *dst, · 62 unmodified lines
3947 4020
3948 drm_desc->nb_layers = planes;4021 drm_desc->nb_layers = planes;
3949 for (int i = 0; i < drm_desc->nb_layers; i++) {4022 for (int i = 0; i < drm_desc->nb_layers; i++) {
3950 VkSubresourceLayout layout;
3951 VkImageSubresource sub = {
3952 .aspectMask = VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT,
3953 };
3954 VkFormat plane_vkfmt = av_vkfmt_from_pixfmt(hwfc->sw_format)[i];4023 VkFormat plane_vkfmt = av_vkfmt_from_pixfmt(hwfc->sw_format)[i];
3955 4024
3956 drm_desc->layers[i].format = vulkan_fmt_to_drm(plane_vkfmt);4025 drm_desc->layers[i].format = vulkan_fmt_to_drm(plane_vkfmt);
3957 drm_desc->layers[i].nb_planes = 1;4026 drm_desc->layers[i].nb_planes = fp->drm_format_modifier_properties[i].drmFormatModifierPlaneCount;
4027
4028 if (drm_desc->layers[i].nb_planes > MAX_MEMORY_PLANES) {
4029 av_log(hwfc, AV_LOG_ERROR, "Too many memory planes for DRM format!\n");
4030 err = AVERROR_EXTERNAL;
4031 goto end;
4032 }
4033
4034 for (int j = 0; j < drm_desc->layers[i].nb_planes; j++) {
4035 VkSubresourceLayout layout;
4036 VkImageSubresource sub = {
4037 .aspectMask = plane_index_to_aspect(j),
4038 };
4039
4040 drm_desc->layers[i].planes[j].object_index = FFMIN(i, drm_desc->nb_objects - 1);
4041
4042 vk->GetImageSubresourceLayout(hwctx->act_dev, f->img[i], &sub, &layout);
4043 drm_desc->layers[i].planes[j].offset = layout.offset;
4044 drm_desc->layers[i].planes[j].pitch = layout.rowPitch;
4045 }
3958 4046
3959 if (drm_desc->layers[i].format == DRM_FORMAT_INVALID) {4047 if (drm_desc->layers[i].format == DRM_FORMAT_INVALID) {
3960 av_log(hwfc, AV_LOG_ERROR, "Cannot map to DRM layer, unsupported!\n");4048 av_log(hwfc, AV_LOG_ERROR, "Cannot map to DRM layer, unsupported!\n");
@@ -3962,14 +4050,10 @@ static int vulkan_map_to_drm(AVHWFramesContext *hwfc, AVFrame *dst, · 1 unmodified line
3962 goto end;4050 goto end;
3963 }4051 }
3964 4052
3965 drm_desc->layers[i].planes[0].object_index = FFMIN(i, drm_desc->nb_objects - 1);
3966 4053
3967 if (f->tiling == VK_IMAGE_TILING_OPTIMAL)4054 if (f->tiling == VK_IMAGE_TILING_OPTIMAL)
3968 continue;4055 continue;
3969 4056
3970 vk->GetImageSubresourceLayout(hwctx->act_dev, f->img[i], &sub, &layout);
3971 drm_desc->layers[i].planes[0].offset = layout.offset;
3972 drm_desc->layers[i].planes[0].pitch = layout.rowPitch;
3973 }4057 }
3974 4058
3975 dst->width = src->width;4059 dst->width = src->width;

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t