mirror of
https://mirror.skon.top/https://github.com/FFmpeg/FFmpeg
synced 2026-04-20 21:00:41 +08:00
vulkan: fix DRM map, decode barriers, and video frame setup for modifier output
When mapping Vulkan Video frames to DMA-BUF, synchronize using an exportable binary semaphore and sync_fd where supported. Submit a lightweight exec that waits on each plane's timeline semaphore at the current value, signals a SYNC_FD-exportable binary semaphore, then export with vkGetSemaphoreFdKHR. Store that binary semaphore in AVVkFrameInternal and reuse it across maps instead of creating and destroying each time: for VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT, copy transference means a successful vkGetSemaphoreFdKHR unsignals the semaphore like a wait, so it can be signaled again on the next map submit. If export is unavailable, fall back to vkWaitSemaphores. Moved drm_sync_sem destroy to vulkan_free_internal Export dma-buf fds with GetMemoryFdKHR for each populated f->mem[i], iterating up to the sw_format plane count instead of stopping at the image count, so multi-memory bindings are not skipped. Describe DRM layers using max(sw planes, image count) and query subresource layout with the correct aspect and image index when one VkImage backs multiple planes. Reference the source hw_frames_ctx on the mapped frame and close dma-buf fds on failure paths. For DMA-BUF-capable pools, honor VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT from format export queries when binding memory. With DRM modifiers and a video profile in create_pnext, preserve caller usage and image flags instead of overwriting them from generic supported_usage probing; use the modifier list create info when probing export flags for modifier tiling. Include VK_IMAGE_USAGE_VIDEO_DECODE_DPB_BIT_KHR from the output frames context's usage together with DST (fixes VUID-VkVideoBeginCodingInfoKHR-slotIndex-07245) instead of adding DPB usage only when !is_current. In ff_vk_decode_add_slice, pass VkVideoProfileListInfoKHR (from the output frames context's create_pnext) as the pNext argument to ff_vk_get_pooled_buffer instead of the full create_pnext chain. In ff_vk_frame_params, set tiling to OPTIMAL only when it is not already DRM_FORMAT_MODIFIER_EXT. In ff_vk_decode_init, when the output pool's create_pnext includes VkImageDrmFormatModifierListCreateInfoEXT, initialize the DPB pool with that modifier-list pNext and DRM_FORMAT_MODIFIER_EXT tiling; otherwise use VkVideoProfileListInfoKHR and OPTIMAL as before. When VK_VIDEO_DECODE_CAPABILITY_DPB_AND_OUTPUT_DISTINCT_BIT_KHR is unset, the output and DPB pools cannot use different layouts or tiling, so the DPB pool must match the output pool. Also fix av_hwframe_map ioctl sync_fd export, multi-planar semaphore handling, and related failure-path cleanup. Signed-off-by: Tymur Boiko <tboiko@nvidia.com>
This commit is contained in:
@@ -233,7 +233,8 @@ int ff_vk_decode_prepare_frame(FFVulkanDecodeContext *dec, AVFrame *pic,
|
||||
(AVVkFrame *)pic->data[0],
|
||||
hwfc->format[0],
|
||||
VK_IMAGE_USAGE_VIDEO_DECODE_DST_BIT_KHR |
|
||||
(!is_current ? VK_IMAGE_USAGE_VIDEO_DECODE_DPB_BIT_KHR : 0));
|
||||
(hwfc->usage & VK_IMAGE_USAGE_VIDEO_DECODE_DPB_BIT_KHR));
|
||||
// the above fixes VUID-VkVideoBeginCodingInfoKHR-slotIndex-07245
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
@@ -335,12 +336,21 @@ int ff_vk_decode_add_slice(AVCodecContext *avctx, FFVulkanDecodePicture *vp,
|
||||
* easier, and gives us ample headroom. */
|
||||
buf_size = 2 << av_log2(buf_size);
|
||||
|
||||
/* When the frames context uses DRM modifier tiling,
|
||||
* hwctx->create_pnext contains VkImageDrmFormatModifierListCreateInfoEXT,
|
||||
* which per spec does not extend VkBufferCreateInfo, so we need to find
|
||||
* the VkVideoProfileListInfoKHR structure within it. */
|
||||
void *buf_pnext = ctx->s.hwfc->create_pnext;
|
||||
if (ctx->s.hwfc->tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT)
|
||||
buf_pnext = (void *)ff_vk_find_struct(ctx->s.hwfc->create_pnext,
|
||||
VK_STRUCTURE_TYPE_VIDEO_PROFILE_LIST_INFO_KHR);
|
||||
|
||||
err = ff_vk_get_pooled_buffer(&ctx->s, &ctx->buf_pool, &new_ref,
|
||||
DECODER_IS_SDR(avctx->codec_id) ?
|
||||
(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT |
|
||||
VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT) :
|
||||
VK_BUFFER_USAGE_VIDEO_DECODE_SRC_BIT_KHR,
|
||||
ctx->s.hwfc->create_pnext, buf_size,
|
||||
buf_pnext, buf_size,
|
||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
|
||||
(DECODER_IS_SDR(avctx->codec_id) ?
|
||||
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT : 0x0));
|
||||
@@ -1217,7 +1227,9 @@ int ff_vk_frame_params(AVCodecContext *avctx, AVBufferRef *hw_frames_ctx)
|
||||
}
|
||||
}
|
||||
|
||||
hwfc->tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||
if (hwfc->tiling != VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT)
|
||||
hwfc->tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||
|
||||
hwfc->usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
|
||||
VK_IMAGE_USAGE_STORAGE_BIT |
|
||||
VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||
@@ -1382,10 +1394,22 @@ int ff_vk_decode_init(AVCodecContext *avctx)
|
||||
dpb_frames->height = s->frames->height;
|
||||
|
||||
dpb_hwfc = dpb_frames->hwctx;
|
||||
dpb_hwfc->create_pnext = (void *)ff_vk_find_struct(ctx->s.hwfc->create_pnext,
|
||||
VK_STRUCTURE_TYPE_VIDEO_PROFILE_LIST_INFO_KHR);
|
||||
void *profile_list = (void *)ff_vk_find_struct(ctx->s.hwfc->create_pnext,
|
||||
VK_STRUCTURE_TYPE_VIDEO_PROFILE_LIST_INFO_KHR);
|
||||
/* Reference (DPB) images use the same tiling and pNext chain as output.
|
||||
* If VK_VIDEO_DECODE_CAPABILITY_DPB_AND_OUTPUT_DISTINCT_BIT_KHR is 0, the
|
||||
* driver does not support separate output and DPB with different layouts/tiling. */
|
||||
void *drm_create_pnext = ff_vk_find_struct(ctx->s.hwfc->create_pnext,
|
||||
VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT);
|
||||
if (drm_create_pnext) {
|
||||
dpb_hwfc->create_pnext = drm_create_pnext;
|
||||
dpb_hwfc->tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT;
|
||||
av_assert2(ff_vk_find_struct(drm_create_pnext, VK_STRUCTURE_TYPE_VIDEO_PROFILE_LIST_INFO_KHR));
|
||||
} else {
|
||||
dpb_hwfc->create_pnext = profile_list;
|
||||
dpb_hwfc->tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||
}
|
||||
dpb_hwfc->format[0] = s->hwfc->format[0];
|
||||
dpb_hwfc->tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||
dpb_hwfc->usage = VK_IMAGE_USAGE_VIDEO_DECODE_DPB_BIT_KHR;
|
||||
|
||||
if (ctx->common.layered_dpb)
|
||||
|
||||
@@ -190,11 +190,18 @@ typedef struct VulkanFramesPriv {
|
||||
|
||||
/* Properties for DRM modifier for each plane in the image */
|
||||
VkDrmFormatModifierPropertiesEXT drm_format_modifier_properties[5];
|
||||
|
||||
/* Set when physical device reports DEDICATED_ONLY for DMA-BUF export (try_export_flags) */
|
||||
int export_requires_dedicated;
|
||||
} VulkanFramesPriv;
|
||||
|
||||
typedef struct AVVkFrameInternal {
|
||||
pthread_mutex_t update_mutex;
|
||||
|
||||
/* Binary semaphore for SYNC_FD export at DRM map time. Created once lazily,
|
||||
* re-signaled each time via a submit in vulkan_map_to_drm. */
|
||||
VkSemaphore drm_sync_sem;
|
||||
|
||||
#if CONFIG_CUDA
|
||||
/* Importing external memory into cuda is really expensive so we keep the
|
||||
* memory imported all the time */
|
||||
@@ -2369,7 +2376,7 @@ static int alloc_mem(AVHWDeviceContext *ctx, VkMemoryRequirements *req,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void vulkan_free_internal(AVVkFrame *f)
|
||||
static void vulkan_free_internal(VulkanDevicePriv *p, AVVkFrame *f)
|
||||
{
|
||||
av_unused AVVkFrameInternal *internal = f->internal;
|
||||
|
||||
@@ -2401,6 +2408,10 @@ static void vulkan_free_internal(AVVkFrame *f)
|
||||
}
|
||||
#endif
|
||||
|
||||
if (internal->drm_sync_sem != VK_NULL_HANDLE)
|
||||
p->vkctx.vkfn.DestroySemaphore(p->p.act_dev, internal->drm_sync_sem,
|
||||
p->p.alloc);
|
||||
|
||||
pthread_mutex_destroy(&internal->update_mutex);
|
||||
av_freep(&f->internal);
|
||||
}
|
||||
@@ -2428,7 +2439,7 @@ static void vulkan_frame_free(AVHWFramesContext *hwfc, AVVkFrame *f)
|
||||
vk->WaitSemaphores(hwctx->act_dev, &sem_wait, UINT64_MAX);
|
||||
}
|
||||
|
||||
vulkan_free_internal(f);
|
||||
vulkan_free_internal(p, f);
|
||||
|
||||
for (int i = 0; i < nb_images; i++) {
|
||||
vk->DestroyImage(hwctx->act_dev, f->img[i], hwctx->alloc);
|
||||
@@ -2475,6 +2486,10 @@ static int alloc_bind_mem(AVHWFramesContext *hwfc, AVVkFrame *f,
|
||||
|
||||
vk->GetImageMemoryRequirements2(hwctx->act_dev, &req_desc, &req);
|
||||
|
||||
av_log(hwfc, AV_LOG_TRACE,
|
||||
"plane %d: driver reports prefersDedicatedAllocation=%i requiresDedicatedAllocation=%i\n",
|
||||
img_cnt, ded_req.prefersDedicatedAllocation, ded_req.requiresDedicatedAllocation);
|
||||
|
||||
if (f->tiling == VK_IMAGE_TILING_LINEAR)
|
||||
req.memoryRequirements.size = FFALIGN(req.memoryRequirements.size,
|
||||
p->props.properties.limits.minMemoryMapAlignment);
|
||||
@@ -2482,6 +2497,8 @@ static int alloc_bind_mem(AVHWFramesContext *hwfc, AVVkFrame *f,
|
||||
/* In case the implementation prefers/requires dedicated allocation */
|
||||
use_ded_mem = ded_req.prefersDedicatedAllocation |
|
||||
ded_req.requiresDedicatedAllocation;
|
||||
if (((VulkanFramesPriv *)hwfc->hwctx)->export_requires_dedicated)
|
||||
use_ded_mem = 1;
|
||||
if (use_ded_mem)
|
||||
ded_alloc.image = f->img[img_cnt];
|
||||
|
||||
@@ -2853,7 +2870,8 @@ static void try_export_flags(AVHWFramesContext *hwfc,
|
||||
.type = VK_IMAGE_TYPE_2D,
|
||||
.tiling = hwctx->tiling,
|
||||
.usage = hwctx->usage,
|
||||
.flags = VK_IMAGE_CREATE_ALIAS_BIT,
|
||||
.flags = (hwctx->tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT && has_mods) ?
|
||||
(hwctx->img_flags) : (VkImageCreateFlags)(VK_IMAGE_CREATE_ALIAS_BIT),
|
||||
};
|
||||
|
||||
nb_mods = has_mods ? drm_mod_info->drmFormatModifierCount : 1;
|
||||
@@ -2864,9 +2882,17 @@ static void try_export_flags(AVHWFramesContext *hwfc,
|
||||
ret = vk->GetPhysicalDeviceImageFormatProperties2(dev_hwctx->phys_dev,
|
||||
&pinfo, &props);
|
||||
|
||||
av_log(hwfc, AV_LOG_VERBOSE, "GetPhysicalDeviceImageFormatProperties2: mod[%d]=0x%llx -> %s\n",
|
||||
i, has_mods ? (unsigned long long)phy_dev_mod_info.drmFormatModifier : 0ULL,
|
||||
ret == VK_SUCCESS ? "OK" : "FAIL");
|
||||
if (ret == VK_SUCCESS) {
|
||||
*iexp |= exp;
|
||||
*comp_handle_types |= eprops.externalMemoryProperties.compatibleHandleTypes;
|
||||
if (exp == VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT) {
|
||||
VulkanFramesPriv *fp = hwfc->hwctx;
|
||||
fp->export_requires_dedicated = !!(eprops.externalMemoryProperties.externalMemoryFeatures &
|
||||
VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2894,7 +2920,8 @@ static AVBufferRef *vulkan_pool_alloc(void *opaque, size_t size)
|
||||
? VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT
|
||||
: VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT);
|
||||
#else
|
||||
if (p->vkctx.extensions & FF_VK_EXT_EXTERNAL_FD_MEMORY)
|
||||
if ((p->vkctx.extensions & FF_VK_EXT_EXTERNAL_FD_MEMORY) &&
|
||||
(hwctx->tiling != VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT))
|
||||
try_export_flags(hwfc, &eiinfo.handleTypes, &e,
|
||||
VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT);
|
||||
|
||||
@@ -2913,8 +2940,10 @@ static AVBufferRef *vulkan_pool_alloc(void *opaque, size_t size)
|
||||
err = create_frame(hwfc, &f, hwctx->tiling, hwctx->usage, hwctx->img_flags,
|
||||
hwctx->nb_layers,
|
||||
eiinfo.handleTypes ? &eiinfo : hwctx->create_pnext);
|
||||
if (err)
|
||||
if (err) {
|
||||
av_log(hwfc, AV_LOG_ERROR, "vulkan_pool_alloc failed: create_frame failed: %d\n", err);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
err = alloc_bind_mem(hwfc, f, eminfo, sizeof(*eminfo));
|
||||
if (err)
|
||||
@@ -2942,6 +2971,7 @@ static AVBufferRef *vulkan_pool_alloc(void *opaque, size_t size)
|
||||
return avbuf;
|
||||
|
||||
fail:
|
||||
av_log(hwfc, AV_LOG_ERROR, "vulkan_pool_alloc failed with error %d\n", err);
|
||||
vulkan_frame_free(hwfc, f);
|
||||
return NULL;
|
||||
}
|
||||
@@ -3043,7 +3073,14 @@ static int vulkan_frames_init(AVHWFramesContext *hwfc)
|
||||
}
|
||||
|
||||
/* Lone DPB images do not need additional flags. */
|
||||
if (!is_lone_dpb) {
|
||||
/* With DRM modifier + video profile the caller has already chosen a valid
|
||||
* usage/img_flags/chain; do not add usage or img_flags (supported_usage does
|
||||
* not consider the actual modifier or video profile). */
|
||||
int drm_mod_with_video = (hwctx->tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT &&
|
||||
ff_vk_find_struct(hwctx->create_pnext,
|
||||
VK_STRUCTURE_TYPE_VIDEO_PROFILE_LIST_INFO_KHR));
|
||||
|
||||
if (!is_lone_dpb && !drm_mod_with_video) {
|
||||
/* Image usage flags */
|
||||
hwctx->usage |= supported_usage & (VK_IMAGE_USAGE_TRANSFER_DST_BIT |
|
||||
VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
|
||||
@@ -3968,7 +4005,7 @@ static int vulkan_export_to_cuda(AVHWFramesContext *hwfc,
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
vulkan_free_internal(dst_f);
|
||||
vulkan_free_internal(p, dst_f);
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -3979,6 +4016,7 @@ static int vulkan_transfer_data_from_cuda(AVHWFramesContext *hwfc,
|
||||
CUcontext dummy;
|
||||
AVVkFrame *dst_f;
|
||||
AVVkFrameInternal *dst_int;
|
||||
VulkanDevicePriv *p = hwfc->device_ctx->hwctx;
|
||||
VulkanFramesPriv *fp = hwfc->hwctx;
|
||||
const int planes = av_pix_fmt_count_planes(hwfc->sw_format);
|
||||
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(hwfc->sw_format);
|
||||
@@ -4057,7 +4095,7 @@ static int vulkan_transfer_data_from_cuda(AVHWFramesContext *hwfc,
|
||||
|
||||
fail:
|
||||
CHECK_CU(cu->cuCtxPopCurrent(&dummy));
|
||||
vulkan_free_internal(dst_f);
|
||||
vulkan_free_internal(p, dst_f);
|
||||
av_buffer_unref(&dst->buf[0]);
|
||||
return err;
|
||||
}
|
||||
@@ -4127,6 +4165,72 @@ static VkImageAspectFlags plane_index_to_aspect(int plane) {
|
||||
return VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT;
|
||||
}
|
||||
|
||||
#ifdef DMA_BUF_IOCTL_EXPORT_SYNC_FILE
|
||||
static int vulkan_drm_export_sync_fd(AVHWFramesContext *hwfc, AVVkFrame *f,
|
||||
VulkanFramesPriv *fp, int nb_sems)
|
||||
{
|
||||
int sync_fd = -1;
|
||||
VkResult ret;
|
||||
VulkanDevicePriv *p = hwfc->device_ctx->hwctx;
|
||||
AVVulkanDeviceContext *hwctx = &p->p;
|
||||
FFVulkanFunctions *vk = &p->vkctx.vkfn;
|
||||
|
||||
if (f->internal->drm_sync_sem == VK_NULL_HANDLE) {
|
||||
VkExportSemaphoreCreateInfo exp_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO,
|
||||
.handleTypes = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
|
||||
};
|
||||
VkSemaphoreTypeCreateInfo type_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO,
|
||||
.pNext = &exp_info,
|
||||
.semaphoreType = VK_SEMAPHORE_TYPE_BINARY,
|
||||
};
|
||||
VkSemaphoreCreateInfo sem_create = {
|
||||
.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
|
||||
.pNext = &type_info,
|
||||
};
|
||||
ret = vk->CreateSemaphore(hwctx->act_dev, &sem_create, hwctx->alloc,
|
||||
&f->internal->drm_sync_sem);
|
||||
if (ret != VK_SUCCESS) {
|
||||
av_log(hwctx, AV_LOG_ERROR, "Failed to create DRM export semaphore: %s\n",
|
||||
ff_vk_ret2str(ret));
|
||||
return AVERROR_EXTERNAL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Submit a lightweight exec that waits on the timeline semaphore
|
||||
* (true last operation on the frame) and signals the binary semaphore,
|
||||
* so any Vulkan frame can get a SYNC_FD regardless of origin. */
|
||||
FFVkExecContext *exec = ff_vk_exec_get(&p->vkctx, &fp->compute_exec);
|
||||
if (ff_vk_exec_start(&p->vkctx, exec) >= 0) {
|
||||
for (int i = 0; i < nb_sems; i++)
|
||||
ff_vk_exec_add_dep_wait_sem(&p->vkctx, exec, f->sem[i],
|
||||
f->sem_value[i],
|
||||
VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT);
|
||||
ff_vk_exec_add_dep_bool_sem(&p->vkctx, exec, &f->internal->drm_sync_sem, 1,
|
||||
VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, 0);
|
||||
if (ff_vk_exec_submit(&p->vkctx, exec) >= 0) {
|
||||
VkSemaphoreGetFdInfoKHR get_fd_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR,
|
||||
.semaphore = f->internal->drm_sync_sem,
|
||||
.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
|
||||
};
|
||||
ret = vk->GetSemaphoreFdKHR(hwctx->act_dev, &get_fd_info, &sync_fd);
|
||||
if (ret != VK_SUCCESS) {
|
||||
av_log(hwctx, AV_LOG_WARNING,
|
||||
"Failed to get sync fd from DRM map export semaphore: %s\n",
|
||||
ff_vk_ret2str(ret));
|
||||
sync_fd = -1;
|
||||
}
|
||||
} else {
|
||||
ff_vk_exec_discard_deps(&p->vkctx, exec);
|
||||
}
|
||||
}
|
||||
|
||||
return sync_fd;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int vulkan_map_to_drm(AVHWFramesContext *hwfc, AVFrame *dst,
|
||||
const AVFrame *src, int flags)
|
||||
{
|
||||
@@ -4137,15 +4241,14 @@ static int vulkan_map_to_drm(AVHWFramesContext *hwfc, AVFrame *dst,
|
||||
AVVulkanDeviceContext *hwctx = &p->p;
|
||||
FFVulkanFunctions *vk = &p->vkctx.vkfn;
|
||||
VulkanFramesPriv *fp = hwfc->hwctx;
|
||||
const int planes = av_pix_fmt_count_planes(hwfc->sw_format);
|
||||
const int nb_images = ff_vk_count_images(f);
|
||||
VkImageDrmFormatModifierPropertiesEXT drm_mod = {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT,
|
||||
};
|
||||
VkSemaphoreWaitInfo wait_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO,
|
||||
.flags = 0x0,
|
||||
.semaphoreCount = nb_images,
|
||||
};
|
||||
const int nb_sems = nb_images;
|
||||
|
||||
int sync_fd = -1;
|
||||
|
||||
AVDRMFrameDescriptor *drm_desc = av_mallocz(sizeof(*drm_desc));
|
||||
if (!drm_desc)
|
||||
@@ -4155,11 +4258,28 @@ static int vulkan_map_to_drm(AVHWFramesContext *hwfc, AVFrame *dst,
|
||||
if (err < 0)
|
||||
goto end;
|
||||
|
||||
/* Wait for the operation to finish so we can cleanly export it. */
|
||||
wait_info.pSemaphores = f->sem;
|
||||
wait_info.pValues = f->sem_value;
|
||||
#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 &&
|
||||
vk->GetSemaphoreFdKHR && vk->CreateSemaphore) {
|
||||
err = vulkan_drm_export_sync_fd(hwfc, f, fp, nb_sems);
|
||||
if (err < 0)
|
||||
goto end;
|
||||
sync_fd = err;
|
||||
err = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
vk->WaitSemaphores(hwctx->act_dev, &wait_info, UINT64_MAX);
|
||||
if (sync_fd < 0) {
|
||||
VkSemaphoreWaitInfo wait_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO,
|
||||
.flags = 0x0,
|
||||
.semaphoreCount = nb_sems,
|
||||
.pSemaphores = f->sem,
|
||||
.pValues = f->sem_value,
|
||||
};
|
||||
vk->WaitSemaphores(hwctx->act_dev, &wait_info, UINT64_MAX);
|
||||
}
|
||||
|
||||
err = ff_hwframe_map_create(src->hw_frames_ctx, dst, src, &vulkan_unmap_to_drm, drm_desc);
|
||||
if (err < 0)
|
||||
@@ -4173,7 +4293,7 @@ static int vulkan_map_to_drm(AVHWFramesContext *hwfc, AVFrame *dst,
|
||||
goto end;
|
||||
}
|
||||
|
||||
for (int i = 0; (i < nb_images) && (f->mem[i]); i++) {
|
||||
for (int i = 0; (i < planes) && (f->mem[i]); i++) {
|
||||
VkMemoryGetFdInfoKHR export_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR,
|
||||
.memory = f->mem[i],
|
||||
@@ -4188,12 +4308,30 @@ static int vulkan_map_to_drm(AVHWFramesContext *hwfc, AVFrame *dst,
|
||||
goto end;
|
||||
}
|
||||
|
||||
#if HAVE_LINUX_DMA_BUF_H && defined(DMA_BUF_IOCTL_IMPORT_SYNC_FILE)
|
||||
if (sync_fd >= 0) {
|
||||
int dup_fd = dup(sync_fd);
|
||||
if (dup_fd >= 0) {
|
||||
struct dma_buf_import_sync_file import_info = {
|
||||
.flags = DMA_BUF_SYNC_WRITE,
|
||||
.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)));
|
||||
close(dup_fd);
|
||||
} else {
|
||||
av_log(hwfc, AV_LOG_WARNING, "dup(sync_fd) failed: %s\n", av_err2str(AVERROR(errno)));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
drm_desc->nb_objects++;
|
||||
drm_desc->objects[i].size = f->size[i];
|
||||
drm_desc->objects[i].format_modifier = drm_mod.drmFormatModifier;
|
||||
}
|
||||
|
||||
drm_desc->nb_layers = nb_images;
|
||||
/* NV12 has 2 planes but 1 image/semaphore */
|
||||
drm_desc->nb_layers = FFMAX(planes, nb_images);
|
||||
for (int i = 0; i < drm_desc->nb_layers; i++) {
|
||||
VkFormat plane_vkfmt = av_vkfmt_from_pixfmt(hwfc->sw_format)[i];
|
||||
|
||||
@@ -4208,13 +4346,14 @@ static int vulkan_map_to_drm(AVHWFramesContext *hwfc, AVFrame *dst,
|
||||
|
||||
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(j),
|
||||
.aspectMask = plane_index_to_aspect(aspect_plane),
|
||||
};
|
||||
|
||||
drm_desc->layers[i].planes[j].object_index = FFMIN(i, drm_desc->nb_objects - 1);
|
||||
|
||||
vk->GetImageSubresourceLayout(hwctx->act_dev, f->img[i], &sub, &layout);
|
||||
vk->GetImageSubresourceLayout(hwctx->act_dev, f->img[FFMIN(i, nb_images - 1)], &sub, &layout);
|
||||
drm_desc->layers[i].planes[j].offset = layout.offset;
|
||||
drm_desc->layers[i].planes[j].pitch = layout.rowPitch;
|
||||
}
|
||||
@@ -4234,13 +4373,21 @@ static int vulkan_map_to_drm(AVHWFramesContext *hwfc, AVFrame *dst,
|
||||
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");
|
||||
|
||||
return 0;
|
||||
|
||||
end:
|
||||
for (int i = 0; i < drm_desc->nb_objects; i++)
|
||||
close(drm_desc->objects[i].fd);
|
||||
av_free(drm_desc);
|
||||
if (sync_fd >= 0)
|
||||
close(sync_fd);
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -4720,7 +4867,7 @@ end:
|
||||
static int vulkan_transfer_data_to(AVHWFramesContext *hwfc, AVFrame *dst,
|
||||
const AVFrame *src)
|
||||
{
|
||||
av_unused VulkanDevicePriv *p = hwfc->device_ctx->hwctx;
|
||||
VulkanDevicePriv *p = hwfc->device_ctx->hwctx;
|
||||
|
||||
switch (src->format) {
|
||||
#if CONFIG_CUDA
|
||||
@@ -4750,6 +4897,7 @@ static int vulkan_transfer_data_to_cuda(AVHWFramesContext *hwfc, AVFrame *dst,
|
||||
CUcontext dummy;
|
||||
AVVkFrame *dst_f;
|
||||
AVVkFrameInternal *dst_int;
|
||||
VulkanDevicePriv *p = hwfc->device_ctx->hwctx;
|
||||
VulkanFramesPriv *fp = hwfc->hwctx;
|
||||
const int planes = av_pix_fmt_count_planes(hwfc->sw_format);
|
||||
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(hwfc->sw_format);
|
||||
@@ -4830,7 +4978,7 @@ static int vulkan_transfer_data_to_cuda(AVHWFramesContext *hwfc, AVFrame *dst,
|
||||
|
||||
fail:
|
||||
CHECK_CU(cu->cuCtxPopCurrent(&dummy));
|
||||
vulkan_free_internal(dst_f);
|
||||
vulkan_free_internal(p, dst_f);
|
||||
av_buffer_unref(&dst->buf[0]);
|
||||
return err;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user