avutil/hwcontext_vulkan: add support for exporting memory via Win32 Handles

This commit is contained in:
Timo Rothenpieler 2021-11-13 20:00:50 +01:00
parent fedf4ff85c
commit 2ece70090d
1 changed files with 96 additions and 6 deletions

View File

@ -21,6 +21,7 @@
#ifdef _WIN32
#include <windows.h> /* Included to prevent conflicts with CreateSemaphore */
#include <versionhelpers.h>
#include "compat/w32dlfcn.h"
#else
#include <dlfcn.h>
@ -123,6 +124,10 @@ typedef struct AVVkFrameInternal {
CUmipmappedArray cu_mma[AV_NUM_DATA_POINTERS];
CUarray cu_array[AV_NUM_DATA_POINTERS];
CUexternalSemaphore cu_sem[AV_NUM_DATA_POINTERS];
#ifdef _WIN32
HANDLE ext_mem_handle[AV_NUM_DATA_POINTERS];
HANDLE ext_sem_handle[AV_NUM_DATA_POINTERS];
#endif
#endif
} AVVkFrameInternal;
@ -309,6 +314,10 @@ static const VulkanOptExtension optional_device_exts[] = {
{ VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME, FF_VK_EXT_DRM_MODIFIER_FLAGS },
{ VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME, FF_VK_EXT_EXTERNAL_FD_SEM },
{ VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME, FF_VK_EXT_EXTERNAL_HOST_MEMORY },
#ifdef _WIN32
{ VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME, FF_VK_EXT_EXTERNAL_WIN32_MEMORY },
{ VK_KHR_EXTERNAL_SEMAPHORE_WIN32_EXTENSION_NAME, FF_VK_EXT_EXTERNAL_WIN32_SEM },
#endif
/* Video encoding/decoding */
{ VK_KHR_VIDEO_QUEUE_EXTENSION_NAME, FF_VK_EXT_NO_FLAG },
@ -1575,6 +1584,12 @@ static void vulkan_free_internal(AVVkFrame *f)
CHECK_CU(cu->cuMipmappedArrayDestroy(internal->cu_mma[i]));
if (internal->ext_mem[i])
CHECK_CU(cu->cuDestroyExternalMemory(internal->ext_mem[i]));
#ifdef _WIN32
if (internal->ext_sem_handle[i])
CloseHandle(internal->ext_sem_handle[i]);
if (internal->ext_mem_handle[i])
CloseHandle(internal->ext_mem_handle[i]);
#endif
}
av_buffer_unref(&internal->cuda_fc_ref);
@ -1811,12 +1826,22 @@ static int create_frame(AVHWFramesContext *hwfc, AVVkFrame **frame,
VkExportSemaphoreCreateInfo ext_sem_info = {
.sType = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO,
#ifdef _WIN32
.handleTypes = IsWindows8OrGreater()
? VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT
: VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT,
#else
.handleTypes = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT,
#endif
};
VkSemaphoreTypeCreateInfo sem_type_info = {
.sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO,
#ifdef _WIN32
.pNext = p->extensions & FF_VK_EXT_EXTERNAL_WIN32_SEM ? &ext_sem_info : NULL,
#else
.pNext = p->extensions & FF_VK_EXT_EXTERNAL_FD_SEM ? &ext_sem_info : NULL,
#endif
.semaphoreType = VK_SEMAPHORE_TYPE_TIMELINE,
.initialValue = 0,
};
@ -1947,6 +1972,12 @@ static AVBufferRef *vulkan_pool_alloc(void *opaque, size_t size)
.pNext = hwctx->create_pnext,
};
#ifdef _WIN32
if (p->extensions & FF_VK_EXT_EXTERNAL_WIN32_MEMORY)
try_export_flags(hwfc, &eiinfo.handleTypes, &e, IsWindows8OrGreater()
? VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT
: VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT);
#else
if (p->extensions & FF_VK_EXT_EXTERNAL_FD_MEMORY)
try_export_flags(hwfc, &eiinfo.handleTypes, &e,
VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT);
@ -1954,6 +1985,7 @@ static AVBufferRef *vulkan_pool_alloc(void *opaque, size_t size)
if (p->extensions & (FF_VK_EXT_EXTERNAL_DMABUF_MEMORY | FF_VK_EXT_DRM_MODIFIER_FLAGS))
try_export_flags(hwfc, &eiinfo.handleTypes, &e,
VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT);
#endif
for (int i = 0; i < av_pix_fmt_count_planes(hwfc->sw_format); i++) {
eminfo[i].sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO;
@ -2651,6 +2683,43 @@ static int vulkan_export_to_cuda(AVHWFramesContext *hwfc,
},
.numLevels = 1,
};
int p_w, p_h;
#ifdef _WIN32
CUDA_EXTERNAL_MEMORY_HANDLE_DESC ext_desc = {
.type = IsWindows8OrGreater()
? CU_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32
: CU_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT,
.size = dst_f->size[i],
};
VkMemoryGetWin32HandleInfoKHR export_info = {
.sType = VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR,
.memory = dst_f->mem[i],
.handleType = IsWindows8OrGreater()
? VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT
: VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT,
};
VkSemaphoreGetWin32HandleInfoKHR sem_export = {
.sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_WIN32_HANDLE_INFO_KHR,
.semaphore = dst_f->sem[i],
.handleType = IsWindows8OrGreater()
? VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT
: VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT,
};
CUDA_EXTERNAL_SEMAPHORE_HANDLE_DESC ext_sem_desc = {
.type = 10 /* TODO: CU_EXTERNAL_SEMAPHORE_HANDLE_TYPE_TIMELINE_SEMAPHORE_WIN32 */,
};
ret = vk->GetMemoryWin32HandleKHR(hwctx->act_dev, &export_info,
&ext_desc.handle.win32.handle);
if (ret != VK_SUCCESS) {
av_log(hwfc, AV_LOG_ERROR, "Unable to export the image as a Win32 Handle: %s!\n",
vk_ret2str(ret));
err = AVERROR_EXTERNAL;
goto fail;
}
dst_int->ext_mem_handle[i] = ext_desc.handle.win32.handle;
#else
CUDA_EXTERNAL_MEMORY_HANDLE_DESC ext_desc = {
.type = CU_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD,
.size = dst_f->size[i],
@ -2669,12 +2738,6 @@ static int vulkan_export_to_cuda(AVHWFramesContext *hwfc,
.type = 9 /* TODO: CU_EXTERNAL_SEMAPHORE_HANDLE_TYPE_TIMELINE_SEMAPHORE_FD */,
};
int p_w, p_h;
get_plane_wh(&p_w, &p_h, hwfc->sw_format, hwfc->width, hwfc->height, i);
tex_desc.arrayDesc.Width = p_w;
tex_desc.arrayDesc.Height = p_h;
ret = vk->GetMemoryFdKHR(hwctx->act_dev, &export_info,
&ext_desc.handle.fd);
if (ret != VK_SUCCESS) {
@ -2683,14 +2746,21 @@ static int vulkan_export_to_cuda(AVHWFramesContext *hwfc,
err = AVERROR_EXTERNAL;
goto fail;
}
#endif
ret = CHECK_CU(cu->cuImportExternalMemory(&dst_int->ext_mem[i], &ext_desc));
if (ret < 0) {
#ifndef _WIN32
close(ext_desc.handle.fd);
#endif
err = AVERROR_EXTERNAL;
goto fail;
}
get_plane_wh(&p_w, &p_h, hwfc->sw_format, hwfc->width, hwfc->height, i);
tex_desc.arrayDesc.Width = p_w;
tex_desc.arrayDesc.Height = p_h;
ret = CHECK_CU(cu->cuExternalMemoryGetMappedMipmappedArray(&dst_int->cu_mma[i],
dst_int->ext_mem[i],
&tex_desc));
@ -2706,19 +2776,29 @@ static int vulkan_export_to_cuda(AVHWFramesContext *hwfc,
goto fail;
}
#ifdef _WIN32
ret = vk->GetSemaphoreWin32HandleKHR(hwctx->act_dev, &sem_export,
&ext_sem_desc.handle.win32.handle);
#else
ret = vk->GetSemaphoreFdKHR(hwctx->act_dev, &sem_export,
&ext_sem_desc.handle.fd);
#endif
if (ret != VK_SUCCESS) {
av_log(ctx, AV_LOG_ERROR, "Failed to export semaphore: %s\n",
vk_ret2str(ret));
err = AVERROR_EXTERNAL;
goto fail;
}
#ifdef _WIN32
dst_int->ext_sem_handle[i] = ext_sem_desc.handle.win32.handle;
#endif
ret = CHECK_CU(cu->cuImportExternalSemaphore(&dst_int->cu_sem[i],
&ext_sem_desc));
if (ret < 0) {
#ifndef _WIN32
close(ext_sem_desc.handle.fd);
#endif
err = AVERROR_EXTERNAL;
goto fail;
}
@ -3544,8 +3624,13 @@ static int vulkan_transfer_data_to(AVHWFramesContext *hwfc, AVFrame *dst,
switch (src->format) {
#if CONFIG_CUDA
case AV_PIX_FMT_CUDA:
#ifdef _WIN32
if ((p->extensions & FF_VK_EXT_EXTERNAL_WIN32_MEMORY) &&
(p->extensions & FF_VK_EXT_EXTERNAL_WIN32_SEM))
#else
if ((p->extensions & FF_VK_EXT_EXTERNAL_FD_MEMORY) &&
(p->extensions & FF_VK_EXT_EXTERNAL_FD_SEM))
#endif
return vulkan_transfer_data_from_cuda(hwfc, dst, src);
#endif
default:
@ -3657,8 +3742,13 @@ static int vulkan_transfer_data_from(AVHWFramesContext *hwfc, AVFrame *dst,
switch (dst->format) {
#if CONFIG_CUDA
case AV_PIX_FMT_CUDA:
#ifdef _WIN32
if ((p->extensions & FF_VK_EXT_EXTERNAL_WIN32_MEMORY) &&
(p->extensions & FF_VK_EXT_EXTERNAL_WIN32_SEM))
#else
if ((p->extensions & FF_VK_EXT_EXTERNAL_FD_MEMORY) &&
(p->extensions & FF_VK_EXT_EXTERNAL_FD_SEM))
#endif
return vulkan_transfer_data_to_cuda(hwfc, dst, src);
#endif
default: