Files
jellyfin-ffmpeg/debian/patches/0079-add-fixes-for-vaapi-drm-prime-vulkan-interop.patch
T
2026-08-18 03:28:50 +08:00

770 lines
34 KiB
Diff

Index: FFmpeg/libavutil/hwcontext_vulkan.c
===================================================================
--- FFmpeg.orig/libavutil/hwcontext_vulkan.c
+++ FFmpeg/libavutil/hwcontext_vulkan.c
@@ -59,11 +59,47 @@
#include <xf86drm.h>
#include <drm_fourcc.h>
#include "hwcontext_drm.h"
+#ifndef DRM_FORMAT_P010
+#define DRM_FORMAT_P010 fourcc_code('P', '0', '1', '0')
+#define DRM_FORMAT_P012 fourcc_code('P', '0', '1', '2')
+#define DRM_FORMAT_P016 fourcc_code('P', '0', '1', '6')
+#endif
+#ifndef DRM_FORMAT_P210
+#define DRM_FORMAT_P210 fourcc_code('P', '2', '1', '0')
+#endif
+#ifndef DRM_FORMAT_S010
+#define DRM_FORMAT_S010 fourcc_code('S', '0', '1', '0')
+#define DRM_FORMAT_S210 fourcc_code('S', '2', '1', '0')
+#define DRM_FORMAT_S410 fourcc_code('S', '4', '1', '0')
+#define DRM_FORMAT_S012 fourcc_code('S', '0', '1', '2')
+#define DRM_FORMAT_S212 fourcc_code('S', '2', '1', '2')
+#define DRM_FORMAT_S412 fourcc_code('S', '4', '1', '2')
+#define DRM_FORMAT_S016 fourcc_code('S', '0', '1', '6')
+#define DRM_FORMAT_S216 fourcc_code('S', '2', '1', '6')
+#define DRM_FORMAT_S416 fourcc_code('S', '4', '1', '6')
+#endif
#endif
#if HAVE_LINUX_DMA_BUF_H
#include <sys/ioctl.h>
#include <linux/dma-buf.h>
+/* dma-buf export/import sync is only available in v6.0+ */
+#ifndef DMA_BUF_IOCTL_EXPORT_SYNC_FILE
+struct dma_buf_export_sync_file {
+ uint32_t flags;
+ int32_t fd;
+};
+#define DMA_BUF_IOCTL_EXPORT_SYNC_FILE \
+ _IOWR(DMA_BUF_BASE, 2, struct dma_buf_export_sync_file)
+#endif
+#ifndef DMA_BUF_IOCTL_IMPORT_SYNC_FILE
+struct dma_buf_import_sync_file {
+ uint32_t flags;
+ int32_t fd;
+};
+#define DMA_BUF_IOCTL_IMPORT_SYNC_FILE \
+ _IOW(DMA_BUF_BASE, 3, struct dma_buf_import_sync_file)
+#endif
#endif
#if CONFIG_CUDA
@@ -167,6 +203,11 @@ typedef struct VulkanDevicePriv {
/* Maximum queues */
int limit_queues;
+
+ /* DRM dma-buf sync file ioctl ret code, tested on first use.
+ * 0: success, other: fail (use fallback) */
+ int drm_export_sync_file_ret;
+ int drm_import_sync_file_ret;
} VulkanDevicePriv;
typedef struct VulkanFramesPriv {
@@ -1794,6 +1835,7 @@ static void vulkan_device_uninit(AVHWDev
static int vulkan_device_create_internal(AVHWDeviceContext *ctx,
VulkanDeviceSelection *dev_select,
+ int use_linear_images,
int disable_multiplane,
AVDictionary *opts, int flags)
{
@@ -1866,10 +1908,14 @@ static int vulkan_device_create_internal
goto end;
}
- /* Tiled images setting, use them by default */
- opt_d = av_dict_get(opts, "linear_images", NULL, 0);
- if (opt_d)
- p->use_linear_images = strtol(opt_d->value, NULL, 10);
+ /* Tiled images setting, use them by default.
+ * The use_linear_images argument takes precedent over the option */
+ p->use_linear_images = use_linear_images;
+ if (!p->use_linear_images) {
+ opt_d = av_dict_get(opts, "linear_images", NULL, 0);
+ if (opt_d)
+ p->use_linear_images = strtol(opt_d->value, NULL, 10);
+ }
/* The disable_multiplane argument takes precedent over the option */
p->disable_multiplane = disable_multiplane;
@@ -2167,7 +2213,7 @@ static int vulkan_device_create(AVHWDevi
}
}
- return vulkan_device_create_internal(ctx, &dev_select, 0, opts, flags);
+ return vulkan_device_create_internal(ctx, &dev_select, 0, 0, opts, flags);
}
static int vulkan_device_derive(AVHWDeviceContext *ctx,
@@ -2209,7 +2255,8 @@ static int vulkan_device_derive(AVHWDevi
dev_select.vendor_id = 0x1002;
}
- return vulkan_device_create_internal(ctx, &dev_select, 0, opts, flags);
+ /* Linear multiplane image is used to ensure compatibility with VAAPI */
+ return vulkan_device_create_internal(ctx, &dev_select, 1, 0, opts, flags);
}
#endif
#if CONFIG_LIBDRM
@@ -2242,7 +2289,14 @@ static int vulkan_device_derive(AVHWDevi
drmFreeDevice(&drm_dev_info);
- return vulkan_device_create_internal(ctx, &dev_select, 0, opts, flags);
+ /* Linear multiplane image is used to ensure compatibility with DRM */
+ return vulkan_device_create_internal(ctx, &dev_select, 1, 0, opts, flags);
+ }
+#endif
+#if CONFIG_RKMPP
+ case AV_HWDEVICE_TYPE_RKMPP: {
+ /* Linear multiplane image is used to ensure compatibility with RKMPP */
+ return vulkan_device_create_internal(ctx, &dev_select, 1, 0, opts, flags);
}
#endif
#if CONFIG_CUDA
@@ -2265,7 +2319,7 @@ static int vulkan_device_derive(AVHWDevi
* CUDA is not able to import multiplane images, so always derive a
* Vulkan device with multiplane disabled.
*/
- return vulkan_device_create_internal(ctx, &dev_select, 1, opts, flags);
+ return vulkan_device_create_internal(ctx, &dev_select, 0, 1, opts, flags);
}
#endif
default:
@@ -2874,6 +2928,8 @@ static void try_export_flags(AVHWFramesC
.flags = (hwctx->tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT && has_mods) ?
(hwctx->img_flags) : hwctx->img_flags ? hwctx->img_flags : (VkImageCreateFlags)(VK_IMAGE_CREATE_ALIAS_BIT),
};
+ VkPhysicalDeviceImageFormatInfo2 pinfo_fallback = pinfo;
+ pinfo_fallback.format = av_vkfmt_from_pixfmt(hwfc->sw_format)[0];
nb_mods = has_mods ? drm_mod_info->drmFormatModifierCount : 1;
for (int i = 0; i < nb_mods; i++) {
@@ -2881,7 +2937,10 @@ static void try_export_flags(AVHWFramesC
phy_dev_mod_info.drmFormatModifier = drm_mod_info->pDrmFormatModifiers[i];
ret = vk->GetPhysicalDeviceImageFormatProperties2(dev_hwctx->phys_dev,
- &pinfo, &props);
+ &pinfo, &props);
+ if (ret != VK_SUCCESS)
+ ret = vk->GetPhysicalDeviceImageFormatProperties2(dev_hwctx->phys_dev,
+ &pinfo_fallback, &props);
if (has_mods)
av_log(hwfc, AV_LOG_VERBOSE, "GetPhysicalDeviceImageFormatProperties2: mod[%d]=0x%llx -> %s\n",
@@ -3285,28 +3344,65 @@ static void vulkan_unmap_from_drm(AVHWFr
static const struct {
uint32_t drm_fourcc;
VkFormat vk_format;
+ int nb_planes;
+ uint32_t fallbacks[AV_DRM_MAX_PLANES];
} vulkan_drm_format_map[] = {
- { DRM_FORMAT_R8, VK_FORMAT_R8_UNORM },
- { DRM_FORMAT_R16, VK_FORMAT_R16_UNORM },
- { DRM_FORMAT_GR88, VK_FORMAT_R8G8_UNORM },
- { DRM_FORMAT_RG88, VK_FORMAT_R8G8_UNORM },
- { DRM_FORMAT_GR1616, VK_FORMAT_R16G16_UNORM },
- { DRM_FORMAT_RG1616, VK_FORMAT_R16G16_UNORM },
- { DRM_FORMAT_ARGB8888, VK_FORMAT_B8G8R8A8_UNORM },
- { DRM_FORMAT_XRGB8888, VK_FORMAT_B8G8R8A8_UNORM },
- { DRM_FORMAT_ABGR8888, VK_FORMAT_R8G8B8A8_UNORM },
- { DRM_FORMAT_XBGR8888, VK_FORMAT_R8G8B8A8_UNORM },
- { DRM_FORMAT_ARGB2101010, VK_FORMAT_A2B10G10R10_UNORM_PACK32 },
- { DRM_FORMAT_ABGR2101010, VK_FORMAT_A2R10G10B10_UNORM_PACK32 },
- { DRM_FORMAT_XRGB2101010, VK_FORMAT_A2B10G10R10_UNORM_PACK32 },
- { DRM_FORMAT_XBGR2101010, VK_FORMAT_A2R10G10B10_UNORM_PACK32 },
+ { DRM_FORMAT_R8, VK_FORMAT_R8_UNORM, 1, { DRM_FORMAT_R8 } },
+ { DRM_FORMAT_R16, VK_FORMAT_R16_UNORM, 1, { DRM_FORMAT_R16 } },
+ { DRM_FORMAT_GR88, VK_FORMAT_R8G8_UNORM, 1, { DRM_FORMAT_GR88 } },
+ { DRM_FORMAT_RG88, VK_FORMAT_R8G8_UNORM, 1, { DRM_FORMAT_RG88 } },
+ { DRM_FORMAT_GR1616, VK_FORMAT_R16G16_UNORM, 1, { DRM_FORMAT_GR1616 } },
+ { DRM_FORMAT_RG1616, VK_FORMAT_R16G16_UNORM, 1, { DRM_FORMAT_RG1616 } },
+ { DRM_FORMAT_ARGB8888, VK_FORMAT_B8G8R8A8_UNORM, 1, { DRM_FORMAT_ARGB8888 } },
+ { DRM_FORMAT_XRGB8888, VK_FORMAT_B8G8R8A8_UNORM, 1, { DRM_FORMAT_XRGB8888 } },
+ { DRM_FORMAT_ABGR8888, VK_FORMAT_R8G8B8A8_UNORM, 1, { DRM_FORMAT_ABGR8888 } },
+ { DRM_FORMAT_XBGR8888, VK_FORMAT_R8G8B8A8_UNORM, 1, { DRM_FORMAT_XBGR8888 } },
+ { DRM_FORMAT_ARGB2101010, VK_FORMAT_A2B10G10R10_UNORM_PACK32, 1, { DRM_FORMAT_ARGB2101010 } },
+ { DRM_FORMAT_ABGR2101010, VK_FORMAT_A2R10G10B10_UNORM_PACK32, 1, { DRM_FORMAT_ABGR2101010 } },
+ { DRM_FORMAT_XRGB2101010, VK_FORMAT_A2B10G10R10_UNORM_PACK32, 1, { DRM_FORMAT_XRGB2101010 } },
+ { DRM_FORMAT_XBGR2101010, VK_FORMAT_A2R10G10B10_UNORM_PACK32, 1, { DRM_FORMAT_XBGR2101010 } },
// All these DRM_FORMATs were added in the same libdrm commit.
#ifdef DRM_FORMAT_XYUV8888
- { DRM_FORMAT_XYUV8888, VK_FORMAT_R8G8B8A8_UNORM },
- { DRM_FORMAT_XVYU2101010, VK_FORMAT_A2R10G10B10_UNORM_PACK32 } ,
- { DRM_FORMAT_XVYU12_16161616, VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16 } ,
- { DRM_FORMAT_XVYU16161616, VK_FORMAT_R16G16B16A16_UNORM } ,
+ { DRM_FORMAT_XYUV8888, VK_FORMAT_R8G8B8A8_UNORM, 1, { DRM_FORMAT_XYUV8888 } },
+ { DRM_FORMAT_XVYU2101010, VK_FORMAT_A2R10G10B10_UNORM_PACK32, 1, { DRM_FORMAT_XVYU2101010 } },
+ { DRM_FORMAT_XVYU12_16161616, VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16, 1, { DRM_FORMAT_XVYU12_16161616 } },
+ { DRM_FORMAT_XVYU16161616, VK_FORMAT_R16G16B16A16_UNORM, 1, { DRM_FORMAT_XVYU16161616 } },
+#endif
+
+ { DRM_FORMAT_RGB888, VK_FORMAT_R8G8B8_UNORM, 1, { DRM_FORMAT_RGB888 } },
+ { DRM_FORMAT_BGR888, VK_FORMAT_B8G8R8_UNORM, 1, { DRM_FORMAT_BGR888 } },
+
+ { DRM_FORMAT_NV12, VK_FORMAT_G8_B8R8_2PLANE_420_UNORM, 2, { DRM_FORMAT_R8, DRM_FORMAT_GR88 } },
+ { DRM_FORMAT_NV16, VK_FORMAT_G8_B8R8_2PLANE_422_UNORM, 2, { DRM_FORMAT_R8, DRM_FORMAT_GR88 } },
+ { DRM_FORMAT_NV24, VK_FORMAT_G8_B8R8_2PLANE_444_UNORM, 2, { DRM_FORMAT_R8, DRM_FORMAT_GR88 } },
+
+ // All these DRM_FORMATs were added in the same libdrm commit.
+#ifdef DRM_FORMAT_P010
+ { DRM_FORMAT_P010, VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16, 2, { DRM_FORMAT_R16, DRM_FORMAT_GR1616 } },
+ { DRM_FORMAT_P012, VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16, 2, { DRM_FORMAT_R16, DRM_FORMAT_GR1616 } },
+ { DRM_FORMAT_P016, VK_FORMAT_G16_B16R16_2PLANE_420_UNORM, 2, { DRM_FORMAT_R16, DRM_FORMAT_GR1616 } },
+#endif
+
+#ifdef DRM_FORMAT_P210
+ { DRM_FORMAT_P210, VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16, 2, { DRM_FORMAT_R16, DRM_FORMAT_GR1616 } },
+#endif
+
+ { DRM_FORMAT_YUV420, VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM, 3, { DRM_FORMAT_R8, DRM_FORMAT_R8, DRM_FORMAT_R8 } },
+ { DRM_FORMAT_YUV422, VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM, 3, { DRM_FORMAT_R8, DRM_FORMAT_R8, DRM_FORMAT_R8 } },
+ { DRM_FORMAT_YUV444, VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM, 3, { DRM_FORMAT_R8, DRM_FORMAT_R8, DRM_FORMAT_R8 } },
+
+ // All these DRM_FORMATs were added in the same libdrm commit.
+#ifdef DRM_FORMAT_S010
+ { DRM_FORMAT_S010, VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM, 3, { DRM_FORMAT_R16, DRM_FORMAT_R16, DRM_FORMAT_R16 } },
+ { DRM_FORMAT_S012, VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM, 3, { DRM_FORMAT_R16, DRM_FORMAT_R16, DRM_FORMAT_R16 } },
+ { DRM_FORMAT_S016, VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM, 3, { DRM_FORMAT_R16, DRM_FORMAT_R16, DRM_FORMAT_R16 } },
+ { DRM_FORMAT_S210, VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM, 3, { DRM_FORMAT_R16, DRM_FORMAT_R16, DRM_FORMAT_R16 } },
+ { DRM_FORMAT_S212, VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM, 3, { DRM_FORMAT_R16, DRM_FORMAT_R16, DRM_FORMAT_R16 } },
+ { DRM_FORMAT_S216, VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM, 3, { DRM_FORMAT_R16, DRM_FORMAT_R16, DRM_FORMAT_R16 } },
+ { DRM_FORMAT_S410, VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM, 3, { DRM_FORMAT_R16, DRM_FORMAT_R16, DRM_FORMAT_R16 } },
+ { DRM_FORMAT_S412, VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM, 3, { DRM_FORMAT_R16, DRM_FORMAT_R16, DRM_FORMAT_R16 } },
+ { DRM_FORMAT_S416, VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM, 3, { DRM_FORMAT_R16, DRM_FORMAT_R16, DRM_FORMAT_R16 } },
#endif
};
@@ -3318,6 +3414,51 @@ static inline VkFormat drm_to_vulkan_fmt
return VK_FORMAT_UNDEFINED;
}
+static inline int decompose_drm_frame_desc(AVDRMFrameDescriptor *dst,
+ const AVDRMFrameDescriptor *src)
+{
+ int map_idx = -1;
+ int p = 0;
+
+ if (!src || !dst)
+ return AVERROR(EINVAL);
+
+ for (int i = 0; i < FF_ARRAY_ELEMS(vulkan_drm_format_map); i++) {
+ if (vulkan_drm_format_map[i].drm_fourcc == src->layers[0].format) {
+ map_idx = i;
+ break;
+ }
+ }
+ if (map_idx == -1)
+ return AVERROR(ENOSYS);
+ if (vulkan_drm_format_map[map_idx].nb_planes == 1 &&
+ vulkan_drm_format_map[map_idx].fallbacks[0] == src->layers[0].format) {
+ return AVERROR(ENOSYS);
+ }
+
+ dst->nb_objects = src->nb_objects;
+ memcpy(dst->objects, src->objects, sizeof(src->objects));
+
+ for (int i = 0; i < src->nb_layers; i++) {
+ for (int j = 0; j < src->layers[i].nb_planes; j++) {
+ if (p >= vulkan_drm_format_map[map_idx].nb_planes)
+ goto end;
+
+ dst->layers[p].format = vulkan_drm_format_map[map_idx].fallbacks[p];
+ dst->layers[p].nb_planes = 1;
+ dst->layers[p].planes[0] = src->layers[i].planes[j];
+ p++;
+ }
+ }
+
+end:
+ dst->nb_layers = p;
+ return 0;
+}
+
+static VkImageAspectFlags plane_index_to_aspect(int plane);
+static VkImageAspectFlags plane_index_to_aspect_linear(int plane, int nb_images, int nb_planes);
+
static int vulkan_map_from_drm_frame_desc(AVHWFramesContext *hwfc, AVVkFrame **frame,
const AVFrame *src, int flags)
{
@@ -3329,10 +3470,15 @@ static int vulkan_map_from_drm_frame_des
VulkanDevicePriv *p = ctx->hwctx;
AVVulkanDeviceContext *hwctx = &p->p;
FFVulkanFunctions *vk = &p->vkctx.vkfn;
- const AVDRMFrameDescriptor *desc = (AVDRMFrameDescriptor *)src->data[0];
+ AVDRMFrameDescriptor desc_decomposed = { 0 };
+ AVDRMFrameDescriptor *desc_src = (AVDRMFrameDescriptor *)src->data[0];
+ AVDRMFrameDescriptor *desc = desc_src;
VkBindImageMemoryInfo bind_info[AV_DRM_MAX_PLANES];
VkBindImagePlaneMemoryInfo plane_info[AV_DRM_MAX_PLANES];
+ const int has_modifiers = !!(p->vkctx.extensions & FF_VK_EXT_DRM_MODIFIER_FLAGS);
+ int retry = 0;
+start:
for (int i = 0; i < desc->nb_layers; i++) {
if (drm_to_vulkan_fmt(desc->layers[i].format) == VK_FORMAT_UNDEFINED) {
av_log(ctx, AV_LOG_ERROR, "Unsupported DMABUF layer format %#08x!\n",
@@ -3341,13 +3487,21 @@ static int vulkan_map_from_drm_frame_des
}
}
+ if (!has_modifiers &&
+ desc->objects[0].format_modifier != DRM_FORMAT_MOD_LINEAR &&
+ desc->objects[0].format_modifier != DRM_FORMAT_MOD_INVALID) {
+ av_log(ctx, AV_LOG_ERROR, "Cannot map non-linear tiling image from DRM!\n");
+ err = AVERROR_EXTERNAL;
+ goto fail;
+ }
+
if (!(f = av_vk_frame_alloc())) {
av_log(ctx, AV_LOG_ERROR, "Unable to allocate memory for AVVkFrame!\n");
err = AVERROR(ENOMEM);
goto fail;
}
- f->tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT;
+ f->tiling = has_modifiers ? VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT : VK_IMAGE_TILING_LINEAR;
for (int i = 0; i < desc->nb_layers; i++) {
const int planes = desc->layers[i].nb_planes;
@@ -3385,7 +3539,7 @@ static int vulkan_map_from_drm_frame_des
.mipLevels = 1,
.arrayLayers = 1,
.flags = 0x0,
- .tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT,
+ .tiling = f->tiling,
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, /* specs say so */
.usage = 0x0, /* filled in below */
.samples = VK_SAMPLE_COUNT_1_BIT,
@@ -3426,7 +3580,7 @@ static int vulkan_map_from_drm_frame_des
fmt_props = (VkPhysicalDeviceImageFormatInfo2) {
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,
- .pNext = &props_ext,
+ .pNext = has_modifiers ? &props_ext : NULL,
.format = create_info.format,
.type = create_info.imageType,
.tiling = create_info.tiling,
@@ -3438,6 +3592,13 @@ static int vulkan_map_from_drm_frame_des
ret = vk->GetPhysicalDeviceImageFormatProperties2(hwctx->phys_dev,
&fmt_props, &props_ret);
if (ret != VK_SUCCESS) {
+ /* Decompose the AVDRMFrameDescriptor and retry */
+ if (!retry && !decompose_drm_frame_desc(&desc_decomposed, desc_src)) {
+ retry++;
+ desc = &desc_decomposed;
+ vulkan_frame_free(hwfc, f);
+ goto start;
+ }
av_log(ctx, AV_LOG_ERROR, "Cannot map DRM frame to Vulkan: %s\n",
ff_vk_ret2str(ret));
err = AVERROR_EXTERNAL;
@@ -3549,9 +3710,12 @@ static int vulkan_map_from_drm_frame_des
for (int i = 0; i < desc->nb_layers; i++) {
const int planes = desc->layers[i].nb_planes;
for (int j = 0; j < planes; j++) {
- VkImageAspectFlagBits aspect = j == 0 ? VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT :
- j == 1 ? VK_IMAGE_ASPECT_MEMORY_PLANE_1_BIT_EXT :
- VK_IMAGE_ASPECT_MEMORY_PLANE_2_BIT_EXT;
+ VkImageAspectFlagBits aspect;
+
+ if (has_modifiers)
+ aspect = plane_index_to_aspect(j);
+ else
+ aspect = plane_index_to_aspect_linear(j, desc->nb_layers, planes);
plane_info[bind_counts].sType = VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO;
plane_info[bind_counts].pNext = NULL;
@@ -3592,15 +3756,20 @@ static int vulkan_map_from_drm_frame_syn
const AVDRMFrameDescriptor *desc, int flags)
{
int err;
+#ifdef DMA_BUF_IOCTL_EXPORT_SYNC_FILE
VkResult ret;
+#endif
AVHWDeviceContext *ctx = hwfc->device_ctx;
VulkanDevicePriv *p = ctx->hwctx;
VulkanFramesPriv *fp = hwfc->hwctx;
AVVulkanDeviceContext *hwctx = &p->p;
+#ifdef DMA_BUF_IOCTL_EXPORT_SYNC_FILE
FFVulkanFunctions *vk = &p->vkctx.vkfn;
+#endif
#ifdef DMA_BUF_IOCTL_EXPORT_SYNC_FILE
- if (p->vkctx.extensions & FF_VK_EXT_EXTERNAL_FD_SEM) {
+ if ((p->vkctx.extensions & FF_VK_EXT_EXTERNAL_FD_SEM) &&
+ !p->drm_export_sync_file_ret) {
VkCommandBuffer cmd_buf;
FFVkExecContext *exec;
VkImageMemoryBarrier2 img_bar[AV_NUM_DATA_POINTERS];
@@ -3618,18 +3787,19 @@ static int vulkan_map_from_drm_frame_syn
};
VkImportSemaphoreFdInfoKHR import_info;
struct dma_buf_export_sync_file implicit_fd_info = {
- .flags = DMA_BUF_SYNC_READ,
+ .flags = DMA_BUF_SYNC_RW,
.fd = -1,
};
- if (ioctl(desc->objects[i].fd, DMA_BUF_IOCTL_EXPORT_SYNC_FILE,
- &implicit_fd_info)) {
+ if (p->drm_export_sync_file_ret = ioctl(desc->objects[i].fd,
+ DMA_BUF_IOCTL_EXPORT_SYNC_FILE,
+ &implicit_fd_info)) {
err = AVERROR(errno);
- av_log(hwctx, AV_LOG_ERROR, "Failed to retrieve implicit DRM sync file: %s\n",
- av_err2str(err));
+ av_log(hwctx, AV_LOG_WARNING, "Failed to retrieve implicit DRM sync file: %s, "
+ "disabling for future frames\n", av_err2str(err));
for (; i >= 0; i--)
vk->DestroySemaphore(hwctx->act_dev, drm_sync_sem[i], hwctx->alloc);
- return err;
+ goto fallback;
}
ret = vk->CreateSemaphore(hwctx->act_dev, &sem_spawn,
@@ -3638,6 +3808,7 @@ static int vulkan_map_from_drm_frame_syn
av_log(hwctx, AV_LOG_ERROR, "Failed to create semaphore: %s\n",
ff_vk_ret2str(ret));
err = AVERROR_EXTERNAL;
+ close(implicit_fd_info.fd);
for (; i >= 0; i--)
vk->DestroySemaphore(hwctx->act_dev, drm_sync_sem[i], hwctx->alloc);
return err;
@@ -3656,6 +3827,7 @@ static int vulkan_map_from_drm_frame_syn
av_log(hwctx, AV_LOG_ERROR, "Failed to import semaphore: %s\n",
ff_vk_ret2str(ret));
err = AVERROR_EXTERNAL;
+ close(implicit_fd_info.fd);
for (; i >= 0; i--)
vk->DestroySemaphore(hwctx->act_dev, drm_sync_sem[i], hwctx->alloc);
return err;
@@ -3672,13 +3844,13 @@ static int vulkan_map_from_drm_frame_syn
drm_sync_sem, desc->nb_objects,
VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, 1);
if (err < 0)
- return err;
+ goto fail;
err = ff_vk_exec_add_dep_frame(&p->vkctx, exec, dst,
VK_PIPELINE_STAGE_2_NONE,
VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT);
if (err < 0)
- return err;
+ goto fail;
ff_vk_frame_barrier(&p->vkctx, exec, dst, img_bar, &nb_img_bar,
VK_PIPELINE_STAGE_2_NONE,
@@ -3698,14 +3870,22 @@ static int vulkan_map_from_drm_frame_syn
err = ff_vk_exec_submit(&p->vkctx, exec);
if (err < 0)
- return err;
+ goto fail;
+
+ return 0;
+fail:
+ ff_vk_exec_discard_deps(&p->vkctx, exec);
+ return err;
} else
#endif
{
- AVVkFrame *f = (AVVkFrame *)dst->data[0];
- av_log(hwctx, AV_LOG_WARNING, "No support for synchronization when importing DMA-BUFs, "
- "image may be corrupted.\n");
- err = prepare_frame(hwfc, &fp->compute_exec, f, PREP_MODE_EXTERNAL_IMPORT);
+#ifdef DMA_BUF_IOCTL_EXPORT_SYNC_FILE
+fallback:
+#endif
+ av_log(hwctx, AV_LOG_DEBUG, "No support for synchronization when importing DMA-BUFs, "
+ "image may be corrupted.\n");
+ err = prepare_frame(hwfc, &fp->compute_exec,
+ (AVVkFrame *)dst->data[0], PREP_MODE_EXTERNAL_IMPORT);
if (err)
return err;
}
@@ -3742,7 +3922,7 @@ static int vulkan_map_from_drm(AVHWFrame
return 0;
fail:
- vulkan_frame_free(hwfc->device_ctx->hwctx, f);
+ vulkan_frame_free(hwfc, f);
dst->data[0] = NULL;
return err;
}
@@ -4112,16 +4292,10 @@ static int vulkan_map_to(AVHWFramesConte
#if CONFIG_LIBDRM
#if CONFIG_VAAPI
case AV_PIX_FMT_VAAPI:
- if (p->vkctx.extensions & FF_VK_EXT_DRM_MODIFIER_FLAGS)
- return vulkan_map_from_vaapi(hwfc, dst, src, flags);
- else
- return AVERROR(ENOSYS);
+ return vulkan_map_from_vaapi(hwfc, dst, src, flags);
#endif
case AV_PIX_FMT_DRM_PRIME:
- if (p->vkctx.extensions & FF_VK_EXT_DRM_MODIFIER_FLAGS)
- return vulkan_map_from_drm(hwfc, dst, src, flags);
- else
- return AVERROR(ENOSYS);
+ return vulkan_map_from_drm(hwfc, dst, src, flags);
#endif
default:
return AVERROR(ENOSYS);
@@ -4137,10 +4311,51 @@ typedef struct VulkanDRMMapping {
static void vulkan_unmap_to_drm(AVHWFramesContext *hwfc, HWMapDescriptor *hwmap)
{
AVDRMFrameDescriptor *drm_desc = hwmap->priv;
+#ifdef DMA_BUF_IOCTL_EXPORT_SYNC_FILE
+ AVVkFrame *f = (AVVkFrame *)hwmap->source->data[0];
+ AVHWDeviceContext *ctx = hwfc->device_ctx;
+ VulkanDevicePriv *p = ctx->hwctx;
+ AVVulkanDeviceContext *hwctx = &p->p;
+ FFVulkanFunctions *vk = &p->vkctx.vkfn;
+#endif
+
+ /* On unmap from DRM, import any fences the external consumer attached
+ * back into the original Vulkan frame's semaphore, so Vulkan waits on
+ * them before reusing the frame. We don't know if the consumer did reads
+ * or writes, so export both. */
+#ifdef DMA_BUF_IOCTL_EXPORT_SYNC_FILE
+ if ((p->vkctx.extensions & FF_VK_EXT_EXTERNAL_FD_SEM) &&
+ !p->drm_export_sync_file_ret) {
+ for (int i = 0; i < drm_desc->nb_objects; i++) {
+ struct dma_buf_export_sync_file implicit_fd_info = {
+ .flags = DMA_BUF_SYNC_RW,
+ .fd = -1,
+ };
- /* on unmap from DRM, make sure to import sync objects so that we are sync'd with any work that was
- * done on the buffer while exported. We don't know if who used the dmabuf did reads or writes, so protect against both */
- vulkan_map_from_drm_frame_sync(hwfc, hwmap->source, drm_desc, AV_HWFRAME_MAP_READ | AV_HWFRAME_MAP_WRITE);
+ if (drm_desc->objects[i].fd < 0)
+ break;
+
+ if (p->drm_export_sync_file_ret = ioctl(drm_desc->objects[i].fd,
+ DMA_BUF_IOCTL_EXPORT_SYNC_FILE,
+ &implicit_fd_info)) {
+ av_log(hwfc, AV_LOG_WARNING, "DMA_BUF_IOCTL_EXPORT_SYNC_FILE failed: %s, "
+ "disabling for future frames\n", av_err2str(AVERROR(errno)));
+ break;
+ }
+
+ VkImportSemaphoreFdInfoKHR import_info = {
+ .sType = VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR,
+ .semaphore = f->sem[i],
+ .handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
+ .flags = VK_SEMAPHORE_IMPORT_TEMPORARY_BIT,
+ .fd = implicit_fd_info.fd,
+ };
+
+ if (vk->ImportSemaphoreFdKHR(hwctx->act_dev, &import_info) != VK_SUCCESS)
+ close(implicit_fd_info.fd);
+ }
+ }
+#endif
for (int i = 0; i < drm_desc->nb_objects; i++)
close(drm_desc->objects[i].fd);
@@ -4167,6 +4382,20 @@ static VkImageAspectFlags plane_index_to
return VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT;
}
+static VkImageAspectFlags plane_index_to_aspect_linear(int plane, int nb_images, int nb_planes)
+{
+ if (nb_images == 1 && nb_planes > 1) {
+ if (plane == 0) return VK_IMAGE_ASPECT_PLANE_0_BIT;
+ if (plane == 1) return VK_IMAGE_ASPECT_PLANE_1_BIT;
+ if (plane == 2) return VK_IMAGE_ASPECT_PLANE_2_BIT;
+
+ av_assert2(0 && "Invalid plane index");
+ return VK_IMAGE_ASPECT_PLANE_0_BIT;
+ }
+
+ return VK_IMAGE_ASPECT_COLOR_BIT;
+}
+
#ifdef DMA_BUF_IOCTL_EXPORT_SYNC_FILE
static int vulkan_drm_export_sync_fd(AVHWFramesContext *hwfc, AVVkFrame *f,
VulkanFramesPriv *fp, int nb_sems)
@@ -4245,14 +4474,22 @@ static int vulkan_map_to_drm(AVHWFramesC
VulkanFramesPriv *fp = hwfc->hwctx;
const int planes = av_pix_fmt_count_planes(hwfc->sw_format);
const int nb_images = ff_vk_count_images(f);
+ const int is_modifier_tiling = (p->vkctx.extensions & FF_VK_EXT_DRM_MODIFIER_FLAGS) &&
+ f->tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT;
VkImageDrmFormatModifierPropertiesEXT drm_mod = {
.sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT,
};
const int nb_sems = nb_images;
int free_drm_desc_on_err = 1;
int sync_fd = -1;
+ AVDRMFrameDescriptor *drm_desc = NULL;
- AVDRMFrameDescriptor *drm_desc = av_mallocz(sizeof(*drm_desc));
+ if (f->tiling == VK_IMAGE_TILING_OPTIMAL) {
+ av_log(hwfc, AV_LOG_ERROR, "Cannot map optimal tiling image to DRM!\n");
+ return AVERROR(EINVAL);
+ }
+
+ drm_desc = av_mallocz(sizeof(*drm_desc));
if (!drm_desc)
return AVERROR(ENOMEM);
@@ -4261,8 +4498,9 @@ static int vulkan_map_to_drm(AVHWFramesC
goto end;
#ifdef DMA_BUF_IOCTL_EXPORT_SYNC_FILE
- if ((p->vkctx.extensions & FF_VK_EXT_EXTERNAL_FD_SEM) &&
- f->tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT &&
+ // Known to be not working on AMD GPU with VAAPI, disable it for now
+ if (0 && (p->vkctx.extensions & FF_VK_EXT_EXTERNAL_FD_SEM) &&
+ !p->drm_import_sync_file_ret &&
vk->GetSemaphoreFdKHR && vk->CreateSemaphore) {
err = vulkan_drm_export_sync_fd(hwfc, f, fp, nb_sems);
if (err < 0)
@@ -4290,13 +4528,16 @@ static int vulkan_map_to_drm(AVHWFramesC
/* It will be freed in ff_hwframe_map_create callback */
free_drm_desc_on_err = 0;
- ret = vk->GetImageDrmFormatModifierPropertiesEXT(hwctx->act_dev, f->img[0],
- &drm_mod);
- if (ret != VK_SUCCESS) {
- av_log(hwfc, AV_LOG_ERROR, "Failed to retrieve DRM format modifier!\n");
- err = AVERROR_EXTERNAL;
- goto end;
- }
+ if (is_modifier_tiling) {
+ ret = vk->GetImageDrmFormatModifierPropertiesEXT(hwctx->act_dev, f->img[0],
+ &drm_mod);
+ if (ret != VK_SUCCESS) {
+ av_log(hwfc, AV_LOG_ERROR, "Failed to retrieve DRM format modifier!\n");
+ err = AVERROR_EXTERNAL;
+ goto end;
+ }
+ } else
+ drm_mod.drmFormatModifier = DRM_FORMAT_MOD_LINEAR;
for (int i = 0; (i < planes) && (f->mem[i]); i++) {
VkMemoryGetFdInfoKHR export_info = {
@@ -4313,16 +4554,20 @@ static int vulkan_map_to_drm(AVHWFramesC
goto end;
}
-#if HAVE_LINUX_DMA_BUF_H && defined(DMA_BUF_IOCTL_IMPORT_SYNC_FILE)
- if (sync_fd >= 0) {
+#ifdef DMA_BUF_IOCTL_IMPORT_SYNC_FILE
+ // Known to be not working on AMD GPU with VAAPI, disable it for now
+ if (0 && sync_fd >= 0 && !p->drm_import_sync_file_ret) {
int dup_fd = dup(sync_fd);
if (dup_fd >= 0) {
struct dma_buf_import_sync_file import_info = {
- .flags = DMA_BUF_SYNC_WRITE,
+ .flags = DMA_BUF_SYNC_RW,
.fd = dup_fd,
};
- if (ioctl(drm_desc->objects[i].fd, DMA_BUF_IOCTL_IMPORT_SYNC_FILE, &import_info) < 0)
- av_log(hwfc, AV_LOG_WARNING, "DMA_BUF_IOCTL_IMPORT_SYNC_FILE failed: %s\n", av_err2str(AVERROR(errno)));
+ if (p->drm_import_sync_file_ret = ioctl(drm_desc->objects[i].fd,
+ DMA_BUF_IOCTL_IMPORT_SYNC_FILE,
+ &import_info))
+ av_log(hwfc, AV_LOG_WARNING, "DMA_BUF_IOCTL_IMPORT_SYNC_FILE failed: %s, "
+ "disabling for future frames\n", av_err2str(AVERROR(errno)));
close(dup_fd);
} else {
av_log(hwfc, AV_LOG_WARNING, "dup(sync_fd) failed: %s\n", av_err2str(AVERROR(errno)));
@@ -4341,8 +4586,13 @@ static int vulkan_map_to_drm(AVHWFramesC
VkFormat plane_vkfmt = av_vkfmt_from_pixfmt(hwfc->sw_format)[i];
drm_desc->layers[i].format = vulkan_fmt_to_drm(plane_vkfmt);
- drm_desc->layers[i].nb_planes = fp->drm_format_modifier_properties[i].drmFormatModifierPlaneCount;
+ drm_desc->layers[i].nb_planes = is_modifier_tiling ? fp->drm_format_modifier_properties[i].drmFormatModifierPlaneCount : 1;
+ if (drm_desc->layers[i].format == DRM_FORMAT_INVALID) {
+ av_log(hwfc, AV_LOG_ERROR, "Cannot map to DRM layer, unsupported!\n");
+ err = AVERROR_PATCHWELCOME;
+ goto end;
+ }
if (drm_desc->layers[i].nb_planes > MAX_MEMORY_PLANES) {
av_log(hwfc, AV_LOG_ERROR, "Too many memory planes for DRM format!\n");
err = AVERROR_EXTERNAL;
@@ -4351,10 +4601,13 @@ static int vulkan_map_to_drm(AVHWFramesC
for (int j = 0; j < drm_desc->layers[i].nb_planes; j++) {
VkSubresourceLayout layout;
- int aspect_plane = (nb_images == 1) ? i : j;
- VkImageSubresource sub = {
- .aspectMask = plane_index_to_aspect(aspect_plane),
- };
+ VkImageSubresource sub = { 0 };
+
+ if (is_modifier_tiling) {
+ int aspect_plane = (nb_images == 1) ? i : j;
+ sub.aspectMask = plane_index_to_aspect(aspect_plane);
+ } else
+ sub.aspectMask = plane_index_to_aspect_linear(i, nb_images, planes);
drm_desc->layers[i].planes[j].object_index = FFMIN(i, drm_desc->nb_objects - 1);
@@ -4362,34 +4615,24 @@ static int vulkan_map_to_drm(AVHWFramesC
drm_desc->layers[i].planes[j].offset = layout.offset;
drm_desc->layers[i].planes[j].pitch = layout.rowPitch;
}
-
- if (drm_desc->layers[i].format == DRM_FORMAT_INVALID) {
- av_log(hwfc, AV_LOG_ERROR, "Cannot map to DRM layer, unsupported!\n");
- err = AVERROR_PATCHWELCOME;
- goto end;
- }
-
-
- if (f->tiling == VK_IMAGE_TILING_OPTIMAL)
- continue;
-
}
dst->width = src->width;
dst->height = src->height;
dst->data[0] = (uint8_t *)drm_desc;
- dst->hw_frames_ctx = av_buffer_ref(src->hw_frames_ctx);
if (sync_fd >= 0)
close(sync_fd);
- av_log(hwfc, AV_LOG_VERBOSE, "Mapped AVVkFrame to a DRM object!\n");
+ av_log(hwfc, AV_LOG_DEBUG, "Mapped AVVkFrame to a DRM object!\n");
return 0;
end:
- for (int i = 0; i < drm_desc->nb_objects; i++)
+ for (int i = 0; i < drm_desc->nb_objects; i++) {
close(drm_desc->objects[i].fd);
+ drm_desc->objects[i].fd = -1;
+ }
if (free_drm_desc_on_err)
av_free(drm_desc);
if (sync_fd >= 0)
@@ -4433,16 +4676,10 @@ static int vulkan_map_from(AVHWFramesCon
switch (dst->format) {
#if CONFIG_LIBDRM
case AV_PIX_FMT_DRM_PRIME:
- if (p->vkctx.extensions & FF_VK_EXT_DRM_MODIFIER_FLAGS)
- return vulkan_map_to_drm(hwfc, dst, src, flags);
- else
- return AVERROR(ENOSYS);
+ return vulkan_map_to_drm(hwfc, dst, src, flags);
#if CONFIG_VAAPI
case AV_PIX_FMT_VAAPI:
- if (p->vkctx.extensions & FF_VK_EXT_DRM_MODIFIER_FLAGS)
- return vulkan_map_to_vaapi(hwfc, dst, src, flags);
- else
- return AVERROR(ENOSYS);
+ return vulkan_map_to_vaapi(hwfc, dst, src, flags);
#endif
#endif
default: