mirror of
https://git.ffmpeg.org/ffmpeg.git
synced 2024-12-25 16:52:31 +00:00
hwcontext_vulkan: add support for implicit DRM synchronization
More recent kernel versions allow for users to extract a sync_file handle from a DMA-BUF, which can then be imported into Vulkan as a binary semaphore. This finally allows for synchronization between Vulkan and DMA-BUF images, such as those from screen capture software, or VAAPI, avoiding any corruption artifacts. This is done fully asynchronously, where we use the kernel's given binary semaphores as a dependency to increment the image's usual VkSemaphores we allocate. The old imported binary semaphores are cleaned up after execution as usual. In the future, hwcontext_drm should receive support for explicitly synchronized images as well, which would make the synchronization more robust and portable.
This commit is contained in:
parent
2395444c80
commit
a577d313b2
@ -61,6 +61,11 @@
|
|||||||
#include "hwcontext_drm.h"
|
#include "hwcontext_drm.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if HAVE_LINUX_DMA_BUF_H
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <linux/dma-buf.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#if CONFIG_CUDA
|
#if CONFIG_CUDA
|
||||||
#include "hwcontext_cuda_internal.h"
|
#include "hwcontext_cuda_internal.h"
|
||||||
#include "cuda_check.h"
|
#include "cuda_check.h"
|
||||||
@ -2842,7 +2847,6 @@ static int vulkan_map_from_drm_frame_desc(AVHWFramesContext *hwfc, AVVkFrame **f
|
|||||||
VulkanDevicePriv *p = ctx->hwctx;
|
VulkanDevicePriv *p = ctx->hwctx;
|
||||||
AVVulkanDeviceContext *hwctx = &p->p;
|
AVVulkanDeviceContext *hwctx = &p->p;
|
||||||
FFVulkanFunctions *vk = &p->vkctx.vkfn;
|
FFVulkanFunctions *vk = &p->vkctx.vkfn;
|
||||||
VulkanFramesPriv *fp = hwfc->hwctx;
|
|
||||||
const AVDRMFrameDescriptor *desc = (AVDRMFrameDescriptor *)src->data[0];
|
const AVDRMFrameDescriptor *desc = (AVDRMFrameDescriptor *)src->data[0];
|
||||||
VkBindImageMemoryInfo bind_info[AV_DRM_MAX_PLANES];
|
VkBindImageMemoryInfo bind_info[AV_DRM_MAX_PLANES];
|
||||||
VkBindImagePlaneMemoryInfo plane_info[AV_DRM_MAX_PLANES];
|
VkBindImagePlaneMemoryInfo plane_info[AV_DRM_MAX_PLANES];
|
||||||
@ -2990,12 +2994,7 @@ static int vulkan_map_from_drm_frame_desc(AVHWFramesContext *hwfc, AVVkFrame **f
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We'd import a semaphore onto the one we created using
|
f->queue_family[i] = VK_QUEUE_FAMILY_EXTERNAL;
|
||||||
* vkImportSemaphoreFdKHR but unfortunately neither DRM nor VAAPI
|
|
||||||
* offer us anything we could import and sync with, so instead
|
|
||||||
* just signal the semaphore we created. */
|
|
||||||
|
|
||||||
f->queue_family[i] = p->nb_img_qfs > 1 ? VK_QUEUE_FAMILY_IGNORED : p->img_qfs[0];
|
|
||||||
f->layout[i] = create_info.initialLayout;
|
f->layout[i] = create_info.initialLayout;
|
||||||
f->access[i] = 0x0;
|
f->access[i] = 0x0;
|
||||||
f->sem_value[i] = 0;
|
f->sem_value[i] = 0;
|
||||||
@ -3097,10 +3096,6 @@ static int vulkan_map_from_drm_frame_desc(AVHWFramesContext *hwfc, AVVkFrame **f
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = prepare_frame(hwfc, &fp->compute_exec, f, PREP_MODE_EXTERNAL_IMPORT);
|
|
||||||
if (err)
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
*frame = f;
|
*frame = f;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -3111,6 +3106,133 @@ fail:
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int vulkan_map_from_drm_frame_sync(AVHWFramesContext *hwfc, AVFrame *dst,
|
||||||
|
const AVFrame *src, int flags)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
VkResult ret;
|
||||||
|
AVHWDeviceContext *ctx = hwfc->device_ctx;
|
||||||
|
VulkanDevicePriv *p = ctx->hwctx;
|
||||||
|
VulkanFramesPriv *fp = hwfc->hwctx;
|
||||||
|
AVVulkanDeviceContext *hwctx = &p->p;
|
||||||
|
FFVulkanFunctions *vk = &p->vkctx.vkfn;
|
||||||
|
|
||||||
|
const AVDRMFrameDescriptor *desc = (AVDRMFrameDescriptor *)src->data[0];
|
||||||
|
|
||||||
|
#ifdef DMA_BUF_IOCTL_EXPORT_SYNC_FILE
|
||||||
|
if (p->vkctx.extensions & FF_VK_EXT_EXTERNAL_FD_SEM) {
|
||||||
|
VkCommandBuffer cmd_buf;
|
||||||
|
FFVkExecContext *exec;
|
||||||
|
VkImageMemoryBarrier2 img_bar[AV_NUM_DATA_POINTERS];
|
||||||
|
VkSemaphore drm_sync_sem[AV_DRM_MAX_PLANES] = { 0 };
|
||||||
|
int nb_img_bar = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < desc->nb_objects; i++) {
|
||||||
|
VkSemaphoreTypeCreateInfo sem_type_info = {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO,
|
||||||
|
.semaphoreType = VK_SEMAPHORE_TYPE_BINARY,
|
||||||
|
};
|
||||||
|
VkSemaphoreCreateInfo sem_spawn = {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
|
||||||
|
.pNext = &sem_type_info,
|
||||||
|
};
|
||||||
|
VkImportSemaphoreFdInfoKHR import_info;
|
||||||
|
struct dma_buf_export_sync_file implicit_fd_info = {
|
||||||
|
.flags = DMA_BUF_SYNC_READ,
|
||||||
|
.fd = -1,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (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));
|
||||||
|
for (; i >= 0; i--)
|
||||||
|
vk->DestroySemaphore(hwctx->act_dev, drm_sync_sem[i], hwctx->alloc);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = vk->CreateSemaphore(hwctx->act_dev, &sem_spawn,
|
||||||
|
hwctx->alloc, &drm_sync_sem[i]);
|
||||||
|
if (ret != VK_SUCCESS) {
|
||||||
|
av_log(hwctx, AV_LOG_ERROR, "Failed to create semaphore: %s\n",
|
||||||
|
ff_vk_ret2str(ret));
|
||||||
|
err = AVERROR_EXTERNAL;
|
||||||
|
for (; i >= 0; i--)
|
||||||
|
vk->DestroySemaphore(hwctx->act_dev, drm_sync_sem[i], hwctx->alloc);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
import_info = (VkImportSemaphoreFdInfoKHR) {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR,
|
||||||
|
.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
|
||||||
|
.flags = VK_SEMAPHORE_IMPORT_TEMPORARY_BIT,
|
||||||
|
.semaphore = drm_sync_sem[i],
|
||||||
|
.fd = implicit_fd_info.fd,
|
||||||
|
};
|
||||||
|
|
||||||
|
ret = vk->ImportSemaphoreFdKHR(hwctx->act_dev, &import_info);
|
||||||
|
if (ret != VK_SUCCESS) {
|
||||||
|
av_log(hwctx, AV_LOG_ERROR, "Failed to import semaphore: %s\n",
|
||||||
|
ff_vk_ret2str(ret));
|
||||||
|
err = AVERROR_EXTERNAL;
|
||||||
|
for (; i >= 0; i--)
|
||||||
|
vk->DestroySemaphore(hwctx->act_dev, drm_sync_sem[i], hwctx->alloc);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exec = ff_vk_exec_get(&fp->compute_exec);
|
||||||
|
cmd_buf = exec->buf;
|
||||||
|
|
||||||
|
ff_vk_exec_start(&p->vkctx, exec);
|
||||||
|
|
||||||
|
/* Ownership of semaphores is passed */
|
||||||
|
err = ff_vk_exec_add_dep_bool_sem(&p->vkctx, exec,
|
||||||
|
drm_sync_sem, desc->nb_objects,
|
||||||
|
VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, 1);
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
ff_vk_frame_barrier(&p->vkctx, exec, dst, img_bar, &nb_img_bar,
|
||||||
|
VK_PIPELINE_STAGE_2_NONE,
|
||||||
|
VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
|
||||||
|
((flags & AV_HWFRAME_MAP_READ) ?
|
||||||
|
VK_ACCESS_2_SHADER_SAMPLED_READ_BIT : 0x0) |
|
||||||
|
((flags & AV_HWFRAME_MAP_WRITE) ?
|
||||||
|
VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT : 0x0),
|
||||||
|
VK_IMAGE_LAYOUT_GENERAL,
|
||||||
|
VK_QUEUE_FAMILY_IGNORED);
|
||||||
|
|
||||||
|
vk->CmdPipelineBarrier2(cmd_buf, &(VkDependencyInfo) {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
|
||||||
|
.pImageMemoryBarriers = img_bar,
|
||||||
|
.imageMemoryBarrierCount = nb_img_bar,
|
||||||
|
});
|
||||||
|
|
||||||
|
err = ff_vk_exec_submit(&p->vkctx, exec);
|
||||||
|
if (err < 0)
|
||||||
|
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);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int vulkan_map_from_drm(AVHWFramesContext *hwfc, AVFrame *dst,
|
static int vulkan_map_from_drm(AVHWFramesContext *hwfc, AVFrame *dst,
|
||||||
const AVFrame *src, int flags)
|
const AVFrame *src, int flags)
|
||||||
{
|
{
|
||||||
@ -3130,6 +3252,10 @@ static int vulkan_map_from_drm(AVHWFramesContext *hwfc, AVFrame *dst,
|
|||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
|
err = vulkan_map_from_drm_frame_sync(hwfc, dst, src, flags);
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
|
||||||
av_log(hwfc, AV_LOG_DEBUG, "Mapped DRM object to Vulkan!\n");
|
av_log(hwfc, AV_LOG_DEBUG, "Mapped DRM object to Vulkan!\n");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -114,6 +114,7 @@ typedef enum FFVulkanExtensions {
|
|||||||
\
|
\
|
||||||
/* Semaphores */ \
|
/* Semaphores */ \
|
||||||
MACRO(1, 1, FF_VK_EXT_EXTERNAL_FD_SEM, GetSemaphoreFdKHR) \
|
MACRO(1, 1, FF_VK_EXT_EXTERNAL_FD_SEM, GetSemaphoreFdKHR) \
|
||||||
|
MACRO(1, 1, FF_VK_EXT_EXTERNAL_FD_SEM, ImportSemaphoreFdKHR) \
|
||||||
MACRO(1, 1, FF_VK_EXT_NO_FLAG, CreateSemaphore) \
|
MACRO(1, 1, FF_VK_EXT_NO_FLAG, CreateSemaphore) \
|
||||||
MACRO(1, 1, FF_VK_EXT_NO_FLAG, WaitSemaphores) \
|
MACRO(1, 1, FF_VK_EXT_NO_FLAG, WaitSemaphores) \
|
||||||
MACRO(1, 1, FF_VK_EXT_NO_FLAG, DestroySemaphore) \
|
MACRO(1, 1, FF_VK_EXT_NO_FLAG, DestroySemaphore) \
|
||||||
|
Loading…
Reference in New Issue
Block a user