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
172172
173173 /* Modifier info list to free at uninit */
174174 VkImageDrmFormatModifierListCreateInfoEXT *modifier_info;
175+
176+ /* Properties for DRM modifier for each plane in the image */
177+ VkDrmFormatModifierPropertiesEXT drm_format_modifier_properties[5];
175178 } VulkanFramesPriv;
176179
177180 typedef struct AVVkFrameInternal {
@@ -2803,7 +2806,9 @@ static int vulkan_frames_init(AVHWFramesContext *hwfc) · 2625 unmodified lines
28032806 VulkanFramesPriv *fp = hwfc->hwctx;
28042807 AVVulkanFramesContext *hwctx = &fp->p;
28052808 VulkanDevicePriv *p = hwfc->device_ctx->hwctx;
2809+ AVVulkanDeviceContext *dev_hwctx = &p->p;
28062810 VkImageUsageFlagBits supported_usage;
2811+ FFVulkanFunctions *vk = &p->vkctx.vkfn;
28072812 const struct FFVkFormatEntry *fmt;
28082813 int disable_multiplane = p->disable_multiplane ||
28092814 (hwctx->flags & AV_VK_FRAME_FLAG_DISABLE_MULTIPLANE);
@@ -2949,6 +2954,63 @@ static int vulkan_frames_init(AVHWFramesContext *hwfc) · 139 unmodified lines
29492954 if (err)
29502955 return err;
29512956
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+
29523014 vulkan_frame_free(hwfc, f);
29533015
29543016 /* 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
38793941 return DRM_FORMAT_INVALID;
38803942 }
38813943
3944+#define MAX_MEMORY_PLANES 4
3945+static 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+
38823955 static int vulkan_map_to_drm(AVHWFramesContext *hwfc, AVFrame *dst,
38833956 const AVFrame *src, int flags)
38843957 {
@@ -3947,14 +4020,29 @@ static int vulkan_map_to_drm(AVHWFramesContext *hwfc, AVFrame *dst, · 62 unmodified lines
39474020
39484021 drm_desc->nb_layers = planes;
39494022 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− };
39544023 VkFormat plane_vkfmt = av_vkfmt_from_pixfmt(hwfc->sw_format)[i];
39554024
3956− drm_desc->layers[i].format = vulkan_fmt_to_drm(plane_vkfmt);
3957− drm_desc->layers[i].nb_planes = 1;
4025+ drm_desc->layers[i].format = vulkan_fmt_to_drm(plane_vkfmt);
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+ }
39584046
39594047 if (drm_desc->layers[i].format == DRM_FORMAT_INVALID) {
39604048 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
39624050 goto end;
39634051 }
39644052
3965− drm_desc->layers[i].planes[0].object_index = FFMIN(i, drm_desc->nb_objects - 1);
39664053
39674054 if (f->tiling == VK_IMAGE_TILING_OPTIMAL)
39684055 continue;
39694056
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;
39734057 }
39744058
39754059 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