1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * This file is part of FFmpeg. 3cabdff1aSopenharmony_ci * 4cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or 5cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public 6cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either 7cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version. 8cabdff1aSopenharmony_ci * 9cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful, 10cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 11cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12cabdff1aSopenharmony_ci * Lesser General Public License for more details. 13cabdff1aSopenharmony_ci * 14cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public 15cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software 16cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17cabdff1aSopenharmony_ci */ 18cabdff1aSopenharmony_ci 19cabdff1aSopenharmony_ci#define VK_NO_PROTOTYPES 20cabdff1aSopenharmony_ci#define VK_ENABLE_BETA_EXTENSIONS 21cabdff1aSopenharmony_ci 22cabdff1aSopenharmony_ci#ifdef _WIN32 23cabdff1aSopenharmony_ci#include <windows.h> /* Included to prevent conflicts with CreateSemaphore */ 24cabdff1aSopenharmony_ci#include <versionhelpers.h> 25cabdff1aSopenharmony_ci#include "compat/w32dlfcn.h" 26cabdff1aSopenharmony_ci#else 27cabdff1aSopenharmony_ci#include <dlfcn.h> 28cabdff1aSopenharmony_ci#endif 29cabdff1aSopenharmony_ci 30cabdff1aSopenharmony_ci#include <unistd.h> 31cabdff1aSopenharmony_ci 32cabdff1aSopenharmony_ci#include "config.h" 33cabdff1aSopenharmony_ci#include "pixdesc.h" 34cabdff1aSopenharmony_ci#include "avstring.h" 35cabdff1aSopenharmony_ci#include "imgutils.h" 36cabdff1aSopenharmony_ci#include "hwcontext.h" 37cabdff1aSopenharmony_ci#include "avassert.h" 38cabdff1aSopenharmony_ci#include "hwcontext_internal.h" 39cabdff1aSopenharmony_ci#include "hwcontext_vulkan.h" 40cabdff1aSopenharmony_ci 41cabdff1aSopenharmony_ci#include "vulkan.h" 42cabdff1aSopenharmony_ci#include "vulkan_loader.h" 43cabdff1aSopenharmony_ci 44cabdff1aSopenharmony_ci#if CONFIG_LIBDRM 45cabdff1aSopenharmony_ci#include <xf86drm.h> 46cabdff1aSopenharmony_ci#include <drm_fourcc.h> 47cabdff1aSopenharmony_ci#include "hwcontext_drm.h" 48cabdff1aSopenharmony_ci#if CONFIG_VAAPI 49cabdff1aSopenharmony_ci#include <va/va_drmcommon.h> 50cabdff1aSopenharmony_ci#include "hwcontext_vaapi.h" 51cabdff1aSopenharmony_ci#endif 52cabdff1aSopenharmony_ci#endif 53cabdff1aSopenharmony_ci 54cabdff1aSopenharmony_ci#if CONFIG_CUDA 55cabdff1aSopenharmony_ci#include "hwcontext_cuda_internal.h" 56cabdff1aSopenharmony_ci#include "cuda_check.h" 57cabdff1aSopenharmony_ci#define CHECK_CU(x) FF_CUDA_CHECK_DL(cuda_cu, cu, x) 58cabdff1aSopenharmony_ci#endif 59cabdff1aSopenharmony_ci 60cabdff1aSopenharmony_citypedef struct VulkanQueueCtx { 61cabdff1aSopenharmony_ci VkFence fence; 62cabdff1aSopenharmony_ci VkQueue queue; 63cabdff1aSopenharmony_ci int was_synchronous; 64cabdff1aSopenharmony_ci 65cabdff1aSopenharmony_ci /* Buffer dependencies */ 66cabdff1aSopenharmony_ci AVBufferRef **buf_deps; 67cabdff1aSopenharmony_ci int nb_buf_deps; 68cabdff1aSopenharmony_ci int buf_deps_alloc_size; 69cabdff1aSopenharmony_ci} VulkanQueueCtx; 70cabdff1aSopenharmony_ci 71cabdff1aSopenharmony_citypedef struct VulkanExecCtx { 72cabdff1aSopenharmony_ci VkCommandPool pool; 73cabdff1aSopenharmony_ci VkCommandBuffer *bufs; 74cabdff1aSopenharmony_ci VulkanQueueCtx *queues; 75cabdff1aSopenharmony_ci int nb_queues; 76cabdff1aSopenharmony_ci int cur_queue_idx; 77cabdff1aSopenharmony_ci} VulkanExecCtx; 78cabdff1aSopenharmony_ci 79cabdff1aSopenharmony_citypedef struct VulkanDevicePriv { 80cabdff1aSopenharmony_ci /* Vulkan library and loader functions */ 81cabdff1aSopenharmony_ci void *libvulkan; 82cabdff1aSopenharmony_ci FFVulkanFunctions vkfn; 83cabdff1aSopenharmony_ci 84cabdff1aSopenharmony_ci /* Properties */ 85cabdff1aSopenharmony_ci VkPhysicalDeviceProperties2 props; 86cabdff1aSopenharmony_ci VkPhysicalDeviceMemoryProperties mprops; 87cabdff1aSopenharmony_ci VkPhysicalDeviceExternalMemoryHostPropertiesEXT hprops; 88cabdff1aSopenharmony_ci 89cabdff1aSopenharmony_ci /* Features */ 90cabdff1aSopenharmony_ci VkPhysicalDeviceVulkan11Features device_features_1_1; 91cabdff1aSopenharmony_ci VkPhysicalDeviceVulkan12Features device_features_1_2; 92cabdff1aSopenharmony_ci 93cabdff1aSopenharmony_ci /* Queues */ 94cabdff1aSopenharmony_ci uint32_t qfs[5]; 95cabdff1aSopenharmony_ci int num_qfs; 96cabdff1aSopenharmony_ci 97cabdff1aSopenharmony_ci /* Debug callback */ 98cabdff1aSopenharmony_ci VkDebugUtilsMessengerEXT debug_ctx; 99cabdff1aSopenharmony_ci 100cabdff1aSopenharmony_ci /* Extensions */ 101cabdff1aSopenharmony_ci FFVulkanExtensions extensions; 102cabdff1aSopenharmony_ci 103cabdff1aSopenharmony_ci /* Settings */ 104cabdff1aSopenharmony_ci int use_linear_images; 105cabdff1aSopenharmony_ci 106cabdff1aSopenharmony_ci /* Option to allocate all image planes in a single allocation */ 107cabdff1aSopenharmony_ci int contiguous_planes; 108cabdff1aSopenharmony_ci 109cabdff1aSopenharmony_ci /* Nvidia */ 110cabdff1aSopenharmony_ci int dev_is_nvidia; 111cabdff1aSopenharmony_ci 112cabdff1aSopenharmony_ci /* Intel */ 113cabdff1aSopenharmony_ci int dev_is_intel; 114cabdff1aSopenharmony_ci} VulkanDevicePriv; 115cabdff1aSopenharmony_ci 116cabdff1aSopenharmony_citypedef struct VulkanFramesPriv { 117cabdff1aSopenharmony_ci /* Image conversions */ 118cabdff1aSopenharmony_ci VulkanExecCtx conv_ctx; 119cabdff1aSopenharmony_ci 120cabdff1aSopenharmony_ci /* Image transfers */ 121cabdff1aSopenharmony_ci VulkanExecCtx upload_ctx; 122cabdff1aSopenharmony_ci VulkanExecCtx download_ctx; 123cabdff1aSopenharmony_ci 124cabdff1aSopenharmony_ci /* Modifier info list to free at uninit */ 125cabdff1aSopenharmony_ci VkImageDrmFormatModifierListCreateInfoEXT *modifier_info; 126cabdff1aSopenharmony_ci} VulkanFramesPriv; 127cabdff1aSopenharmony_ci 128cabdff1aSopenharmony_citypedef struct AVVkFrameInternal { 129cabdff1aSopenharmony_ci#if CONFIG_CUDA 130cabdff1aSopenharmony_ci /* Importing external memory into cuda is really expensive so we keep the 131cabdff1aSopenharmony_ci * memory imported all the time */ 132cabdff1aSopenharmony_ci AVBufferRef *cuda_fc_ref; /* Need to keep it around for uninit */ 133cabdff1aSopenharmony_ci CUexternalMemory ext_mem[AV_NUM_DATA_POINTERS]; 134cabdff1aSopenharmony_ci CUmipmappedArray cu_mma[AV_NUM_DATA_POINTERS]; 135cabdff1aSopenharmony_ci CUarray cu_array[AV_NUM_DATA_POINTERS]; 136cabdff1aSopenharmony_ci CUexternalSemaphore cu_sem[AV_NUM_DATA_POINTERS]; 137cabdff1aSopenharmony_ci#ifdef _WIN32 138cabdff1aSopenharmony_ci HANDLE ext_mem_handle[AV_NUM_DATA_POINTERS]; 139cabdff1aSopenharmony_ci HANDLE ext_sem_handle[AV_NUM_DATA_POINTERS]; 140cabdff1aSopenharmony_ci#endif 141cabdff1aSopenharmony_ci#endif 142cabdff1aSopenharmony_ci} AVVkFrameInternal; 143cabdff1aSopenharmony_ci 144cabdff1aSopenharmony_ci#define ADD_VAL_TO_LIST(list, count, val) \ 145cabdff1aSopenharmony_ci do { \ 146cabdff1aSopenharmony_ci list = av_realloc_array(list, sizeof(*list), ++count); \ 147cabdff1aSopenharmony_ci if (!list) { \ 148cabdff1aSopenharmony_ci err = AVERROR(ENOMEM); \ 149cabdff1aSopenharmony_ci goto fail; \ 150cabdff1aSopenharmony_ci } \ 151cabdff1aSopenharmony_ci list[count - 1] = av_strdup(val); \ 152cabdff1aSopenharmony_ci if (!list[count - 1]) { \ 153cabdff1aSopenharmony_ci err = AVERROR(ENOMEM); \ 154cabdff1aSopenharmony_ci goto fail; \ 155cabdff1aSopenharmony_ci } \ 156cabdff1aSopenharmony_ci } while(0) 157cabdff1aSopenharmony_ci 158cabdff1aSopenharmony_ci#define RELEASE_PROPS(props, count) \ 159cabdff1aSopenharmony_ci if (props) { \ 160cabdff1aSopenharmony_ci for (int i = 0; i < count; i++) \ 161cabdff1aSopenharmony_ci av_free((void *)((props)[i])); \ 162cabdff1aSopenharmony_ci av_free((void *)props); \ 163cabdff1aSopenharmony_ci } 164cabdff1aSopenharmony_ci 165cabdff1aSopenharmony_cistatic const struct { 166cabdff1aSopenharmony_ci enum AVPixelFormat pixfmt; 167cabdff1aSopenharmony_ci const VkFormat vkfmts[4]; 168cabdff1aSopenharmony_ci} vk_pixfmt_map[] = { 169cabdff1aSopenharmony_ci { AV_PIX_FMT_GRAY8, { VK_FORMAT_R8_UNORM } }, 170cabdff1aSopenharmony_ci { AV_PIX_FMT_GRAY16, { VK_FORMAT_R16_UNORM } }, 171cabdff1aSopenharmony_ci { AV_PIX_FMT_GRAYF32, { VK_FORMAT_R32_SFLOAT } }, 172cabdff1aSopenharmony_ci 173cabdff1aSopenharmony_ci { AV_PIX_FMT_NV12, { VK_FORMAT_R8_UNORM, VK_FORMAT_R8G8_UNORM } }, 174cabdff1aSopenharmony_ci { AV_PIX_FMT_NV21, { VK_FORMAT_R8_UNORM, VK_FORMAT_R8G8_UNORM } }, 175cabdff1aSopenharmony_ci { AV_PIX_FMT_P010, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16G16_UNORM } }, 176cabdff1aSopenharmony_ci { AV_PIX_FMT_P016, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16G16_UNORM } }, 177cabdff1aSopenharmony_ci 178cabdff1aSopenharmony_ci { AV_PIX_FMT_NV16, { VK_FORMAT_R8_UNORM, VK_FORMAT_R8G8_UNORM } }, 179cabdff1aSopenharmony_ci 180cabdff1aSopenharmony_ci { AV_PIX_FMT_NV24, { VK_FORMAT_R8_UNORM, VK_FORMAT_R8G8_UNORM } }, 181cabdff1aSopenharmony_ci { AV_PIX_FMT_NV42, { VK_FORMAT_R8_UNORM, VK_FORMAT_R8G8_UNORM } }, 182cabdff1aSopenharmony_ci 183cabdff1aSopenharmony_ci { AV_PIX_FMT_YUV420P, { VK_FORMAT_R8_UNORM, VK_FORMAT_R8_UNORM, VK_FORMAT_R8_UNORM } }, 184cabdff1aSopenharmony_ci { AV_PIX_FMT_YUV420P10, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM } }, 185cabdff1aSopenharmony_ci { AV_PIX_FMT_YUV420P12, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM } }, 186cabdff1aSopenharmony_ci { AV_PIX_FMT_YUV420P16, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM } }, 187cabdff1aSopenharmony_ci 188cabdff1aSopenharmony_ci { AV_PIX_FMT_YUV422P, { VK_FORMAT_R8_UNORM, VK_FORMAT_R8_UNORM, VK_FORMAT_R8_UNORM } }, 189cabdff1aSopenharmony_ci { AV_PIX_FMT_YUV422P10, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM } }, 190cabdff1aSopenharmony_ci { AV_PIX_FMT_YUV422P12, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM } }, 191cabdff1aSopenharmony_ci { AV_PIX_FMT_YUV422P16, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM } }, 192cabdff1aSopenharmony_ci 193cabdff1aSopenharmony_ci { AV_PIX_FMT_YUV444P, { VK_FORMAT_R8_UNORM, VK_FORMAT_R8_UNORM, VK_FORMAT_R8_UNORM } }, 194cabdff1aSopenharmony_ci { AV_PIX_FMT_YUV444P10, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM } }, 195cabdff1aSopenharmony_ci { AV_PIX_FMT_YUV444P12, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM } }, 196cabdff1aSopenharmony_ci { AV_PIX_FMT_YUV444P16, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM } }, 197cabdff1aSopenharmony_ci 198cabdff1aSopenharmony_ci { AV_PIX_FMT_YUVA420P, { VK_FORMAT_R8_UNORM, VK_FORMAT_R8_UNORM, VK_FORMAT_R8_UNORM, VK_FORMAT_R8_UNORM } }, 199cabdff1aSopenharmony_ci { AV_PIX_FMT_YUVA420P10, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM } }, 200cabdff1aSopenharmony_ci /* There is no AV_PIX_FMT_YUVA420P12 */ 201cabdff1aSopenharmony_ci { AV_PIX_FMT_YUVA420P16, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM } }, 202cabdff1aSopenharmony_ci 203cabdff1aSopenharmony_ci { AV_PIX_FMT_YUVA422P, { VK_FORMAT_R8_UNORM, VK_FORMAT_R8_UNORM, VK_FORMAT_R8_UNORM, VK_FORMAT_R8_UNORM } }, 204cabdff1aSopenharmony_ci { AV_PIX_FMT_YUVA422P10, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM } }, 205cabdff1aSopenharmony_ci { AV_PIX_FMT_YUVA422P12, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM } }, 206cabdff1aSopenharmony_ci { AV_PIX_FMT_YUVA422P16, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM } }, 207cabdff1aSopenharmony_ci 208cabdff1aSopenharmony_ci { AV_PIX_FMT_YUVA444P, { VK_FORMAT_R8_UNORM, VK_FORMAT_R8_UNORM, VK_FORMAT_R8_UNORM, VK_FORMAT_R8_UNORM } }, 209cabdff1aSopenharmony_ci { AV_PIX_FMT_YUVA444P10, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM } }, 210cabdff1aSopenharmony_ci { AV_PIX_FMT_YUVA444P12, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM } }, 211cabdff1aSopenharmony_ci { AV_PIX_FMT_YUVA444P16, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM } }, 212cabdff1aSopenharmony_ci 213cabdff1aSopenharmony_ci { AV_PIX_FMT_BGRA, { VK_FORMAT_B8G8R8A8_UNORM } }, 214cabdff1aSopenharmony_ci { AV_PIX_FMT_RGBA, { VK_FORMAT_R8G8B8A8_UNORM } }, 215cabdff1aSopenharmony_ci { AV_PIX_FMT_RGB24, { VK_FORMAT_R8G8B8_UNORM } }, 216cabdff1aSopenharmony_ci { AV_PIX_FMT_BGR24, { VK_FORMAT_B8G8R8_UNORM } }, 217cabdff1aSopenharmony_ci { AV_PIX_FMT_RGB48, { VK_FORMAT_R16G16B16_UNORM } }, 218cabdff1aSopenharmony_ci { AV_PIX_FMT_RGBA64, { VK_FORMAT_R16G16B16A16_UNORM } }, 219cabdff1aSopenharmony_ci { AV_PIX_FMT_RGBA64, { VK_FORMAT_R16G16B16A16_UNORM } }, 220cabdff1aSopenharmony_ci { AV_PIX_FMT_RGB565, { VK_FORMAT_R5G6B5_UNORM_PACK16 } }, 221cabdff1aSopenharmony_ci { AV_PIX_FMT_BGR565, { VK_FORMAT_B5G6R5_UNORM_PACK16 } }, 222cabdff1aSopenharmony_ci { AV_PIX_FMT_BGR0, { VK_FORMAT_B8G8R8A8_UNORM } }, 223cabdff1aSopenharmony_ci { AV_PIX_FMT_RGB0, { VK_FORMAT_R8G8B8A8_UNORM } }, 224cabdff1aSopenharmony_ci 225cabdff1aSopenharmony_ci /* Lower priority as there's an endianess-dependent overlap between these 226cabdff1aSopenharmony_ci * and rgba/bgr0, and PACK32 formats are more limited */ 227cabdff1aSopenharmony_ci { AV_PIX_FMT_BGR32, { VK_FORMAT_A8B8G8R8_UNORM_PACK32 } }, 228cabdff1aSopenharmony_ci { AV_PIX_FMT_0BGR32, { VK_FORMAT_A8B8G8R8_UNORM_PACK32 } }, 229cabdff1aSopenharmony_ci 230cabdff1aSopenharmony_ci { AV_PIX_FMT_X2RGB10, { VK_FORMAT_A2R10G10B10_UNORM_PACK32 } }, 231cabdff1aSopenharmony_ci 232cabdff1aSopenharmony_ci { AV_PIX_FMT_GBRAP, { VK_FORMAT_R8_UNORM, VK_FORMAT_R8_UNORM, VK_FORMAT_R8_UNORM, VK_FORMAT_R8_UNORM } }, 233cabdff1aSopenharmony_ci { AV_PIX_FMT_GBRAP16, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM } }, 234cabdff1aSopenharmony_ci { AV_PIX_FMT_GBRPF32, { VK_FORMAT_R32_SFLOAT, VK_FORMAT_R32_SFLOAT, VK_FORMAT_R32_SFLOAT } }, 235cabdff1aSopenharmony_ci { AV_PIX_FMT_GBRAPF32, { VK_FORMAT_R32_SFLOAT, VK_FORMAT_R32_SFLOAT, VK_FORMAT_R32_SFLOAT, VK_FORMAT_R32_SFLOAT } }, 236cabdff1aSopenharmony_ci}; 237cabdff1aSopenharmony_ci 238cabdff1aSopenharmony_ciconst VkFormat *av_vkfmt_from_pixfmt(enum AVPixelFormat p) 239cabdff1aSopenharmony_ci{ 240cabdff1aSopenharmony_ci for (enum AVPixelFormat i = 0; i < FF_ARRAY_ELEMS(vk_pixfmt_map); i++) 241cabdff1aSopenharmony_ci if (vk_pixfmt_map[i].pixfmt == p) 242cabdff1aSopenharmony_ci return vk_pixfmt_map[i].vkfmts; 243cabdff1aSopenharmony_ci return NULL; 244cabdff1aSopenharmony_ci} 245cabdff1aSopenharmony_ci 246cabdff1aSopenharmony_cistatic const void *vk_find_struct(const void *chain, VkStructureType stype) 247cabdff1aSopenharmony_ci{ 248cabdff1aSopenharmony_ci const VkBaseInStructure *in = chain; 249cabdff1aSopenharmony_ci while (in) { 250cabdff1aSopenharmony_ci if (in->sType == stype) 251cabdff1aSopenharmony_ci return in; 252cabdff1aSopenharmony_ci 253cabdff1aSopenharmony_ci in = in->pNext; 254cabdff1aSopenharmony_ci } 255cabdff1aSopenharmony_ci 256cabdff1aSopenharmony_ci return NULL; 257cabdff1aSopenharmony_ci} 258cabdff1aSopenharmony_ci 259cabdff1aSopenharmony_cistatic void vk_link_struct(void *chain, void *in) 260cabdff1aSopenharmony_ci{ 261cabdff1aSopenharmony_ci VkBaseOutStructure *out = chain; 262cabdff1aSopenharmony_ci if (!in) 263cabdff1aSopenharmony_ci return; 264cabdff1aSopenharmony_ci 265cabdff1aSopenharmony_ci while (out->pNext) 266cabdff1aSopenharmony_ci out = out->pNext; 267cabdff1aSopenharmony_ci 268cabdff1aSopenharmony_ci out->pNext = in; 269cabdff1aSopenharmony_ci} 270cabdff1aSopenharmony_ci 271cabdff1aSopenharmony_cistatic int pixfmt_is_supported(AVHWDeviceContext *dev_ctx, enum AVPixelFormat p, 272cabdff1aSopenharmony_ci int linear) 273cabdff1aSopenharmony_ci{ 274cabdff1aSopenharmony_ci AVVulkanDeviceContext *hwctx = dev_ctx->hwctx; 275cabdff1aSopenharmony_ci VulkanDevicePriv *priv = dev_ctx->internal->priv; 276cabdff1aSopenharmony_ci FFVulkanFunctions *vk = &priv->vkfn; 277cabdff1aSopenharmony_ci const VkFormat *fmt = av_vkfmt_from_pixfmt(p); 278cabdff1aSopenharmony_ci int planes = av_pix_fmt_count_planes(p); 279cabdff1aSopenharmony_ci 280cabdff1aSopenharmony_ci if (!fmt) 281cabdff1aSopenharmony_ci return 0; 282cabdff1aSopenharmony_ci 283cabdff1aSopenharmony_ci for (int i = 0; i < planes; i++) { 284cabdff1aSopenharmony_ci VkFormatFeatureFlags flags; 285cabdff1aSopenharmony_ci VkFormatProperties2 prop = { 286cabdff1aSopenharmony_ci .sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2, 287cabdff1aSopenharmony_ci }; 288cabdff1aSopenharmony_ci vk->GetPhysicalDeviceFormatProperties2(hwctx->phys_dev, fmt[i], &prop); 289cabdff1aSopenharmony_ci flags = linear ? prop.formatProperties.linearTilingFeatures : 290cabdff1aSopenharmony_ci prop.formatProperties.optimalTilingFeatures; 291cabdff1aSopenharmony_ci if (!(flags & FF_VK_DEFAULT_USAGE_FLAGS)) 292cabdff1aSopenharmony_ci return 0; 293cabdff1aSopenharmony_ci } 294cabdff1aSopenharmony_ci 295cabdff1aSopenharmony_ci return 1; 296cabdff1aSopenharmony_ci} 297cabdff1aSopenharmony_ci 298cabdff1aSopenharmony_cistatic int load_libvulkan(AVHWDeviceContext *ctx) 299cabdff1aSopenharmony_ci{ 300cabdff1aSopenharmony_ci AVVulkanDeviceContext *hwctx = ctx->hwctx; 301cabdff1aSopenharmony_ci VulkanDevicePriv *p = ctx->internal->priv; 302cabdff1aSopenharmony_ci 303cabdff1aSopenharmony_ci static const char *lib_names[] = { 304cabdff1aSopenharmony_ci#if defined(_WIN32) 305cabdff1aSopenharmony_ci "vulkan-1.dll", 306cabdff1aSopenharmony_ci#elif defined(__APPLE__) 307cabdff1aSopenharmony_ci "libvulkan.dylib", 308cabdff1aSopenharmony_ci "libvulkan.1.dylib", 309cabdff1aSopenharmony_ci "libMoltenVK.dylib", 310cabdff1aSopenharmony_ci#else 311cabdff1aSopenharmony_ci "libvulkan.so.1", 312cabdff1aSopenharmony_ci "libvulkan.so", 313cabdff1aSopenharmony_ci#endif 314cabdff1aSopenharmony_ci }; 315cabdff1aSopenharmony_ci 316cabdff1aSopenharmony_ci for (int i = 0; i < FF_ARRAY_ELEMS(lib_names); i++) { 317cabdff1aSopenharmony_ci p->libvulkan = dlopen(lib_names[i], RTLD_NOW | RTLD_LOCAL); 318cabdff1aSopenharmony_ci if (p->libvulkan) 319cabdff1aSopenharmony_ci break; 320cabdff1aSopenharmony_ci } 321cabdff1aSopenharmony_ci 322cabdff1aSopenharmony_ci if (!p->libvulkan) { 323cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_ERROR, "Unable to open the libvulkan library!\n"); 324cabdff1aSopenharmony_ci return AVERROR_UNKNOWN; 325cabdff1aSopenharmony_ci } 326cabdff1aSopenharmony_ci 327cabdff1aSopenharmony_ci hwctx->get_proc_addr = (PFN_vkGetInstanceProcAddr)dlsym(p->libvulkan, "vkGetInstanceProcAddr"); 328cabdff1aSopenharmony_ci 329cabdff1aSopenharmony_ci return 0; 330cabdff1aSopenharmony_ci} 331cabdff1aSopenharmony_ci 332cabdff1aSopenharmony_citypedef struct VulkanOptExtension { 333cabdff1aSopenharmony_ci const char *name; 334cabdff1aSopenharmony_ci FFVulkanExtensions flag; 335cabdff1aSopenharmony_ci} VulkanOptExtension; 336cabdff1aSopenharmony_ci 337cabdff1aSopenharmony_cistatic const VulkanOptExtension optional_instance_exts[] = { 338cabdff1aSopenharmony_ci /* For future use */ 339cabdff1aSopenharmony_ci}; 340cabdff1aSopenharmony_ci 341cabdff1aSopenharmony_cistatic const VulkanOptExtension optional_device_exts[] = { 342cabdff1aSopenharmony_ci /* Misc or required by other extensions */ 343cabdff1aSopenharmony_ci { VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME, FF_VK_EXT_NO_FLAG }, 344cabdff1aSopenharmony_ci { VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME, FF_VK_EXT_NO_FLAG }, 345cabdff1aSopenharmony_ci { VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME, FF_VK_EXT_NO_FLAG }, 346cabdff1aSopenharmony_ci 347cabdff1aSopenharmony_ci /* Imports/exports */ 348cabdff1aSopenharmony_ci { VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME, FF_VK_EXT_EXTERNAL_FD_MEMORY }, 349cabdff1aSopenharmony_ci { VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME, FF_VK_EXT_EXTERNAL_DMABUF_MEMORY }, 350cabdff1aSopenharmony_ci { VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME, FF_VK_EXT_DRM_MODIFIER_FLAGS }, 351cabdff1aSopenharmony_ci { VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME, FF_VK_EXT_EXTERNAL_FD_SEM }, 352cabdff1aSopenharmony_ci { VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME, FF_VK_EXT_EXTERNAL_HOST_MEMORY }, 353cabdff1aSopenharmony_ci#ifdef _WIN32 354cabdff1aSopenharmony_ci { VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME, FF_VK_EXT_EXTERNAL_WIN32_MEMORY }, 355cabdff1aSopenharmony_ci { VK_KHR_EXTERNAL_SEMAPHORE_WIN32_EXTENSION_NAME, FF_VK_EXT_EXTERNAL_WIN32_SEM }, 356cabdff1aSopenharmony_ci#endif 357cabdff1aSopenharmony_ci}; 358cabdff1aSopenharmony_ci 359cabdff1aSopenharmony_ci/* Converts return values to strings */ 360cabdff1aSopenharmony_cistatic const char *vk_ret2str(VkResult res) 361cabdff1aSopenharmony_ci{ 362cabdff1aSopenharmony_ci#define CASE(VAL) case VAL: return #VAL 363cabdff1aSopenharmony_ci switch (res) { 364cabdff1aSopenharmony_ci CASE(VK_SUCCESS); 365cabdff1aSopenharmony_ci CASE(VK_NOT_READY); 366cabdff1aSopenharmony_ci CASE(VK_TIMEOUT); 367cabdff1aSopenharmony_ci CASE(VK_EVENT_SET); 368cabdff1aSopenharmony_ci CASE(VK_EVENT_RESET); 369cabdff1aSopenharmony_ci CASE(VK_INCOMPLETE); 370cabdff1aSopenharmony_ci CASE(VK_ERROR_OUT_OF_HOST_MEMORY); 371cabdff1aSopenharmony_ci CASE(VK_ERROR_OUT_OF_DEVICE_MEMORY); 372cabdff1aSopenharmony_ci CASE(VK_ERROR_INITIALIZATION_FAILED); 373cabdff1aSopenharmony_ci CASE(VK_ERROR_DEVICE_LOST); 374cabdff1aSopenharmony_ci CASE(VK_ERROR_MEMORY_MAP_FAILED); 375cabdff1aSopenharmony_ci CASE(VK_ERROR_LAYER_NOT_PRESENT); 376cabdff1aSopenharmony_ci CASE(VK_ERROR_EXTENSION_NOT_PRESENT); 377cabdff1aSopenharmony_ci CASE(VK_ERROR_FEATURE_NOT_PRESENT); 378cabdff1aSopenharmony_ci CASE(VK_ERROR_INCOMPATIBLE_DRIVER); 379cabdff1aSopenharmony_ci CASE(VK_ERROR_TOO_MANY_OBJECTS); 380cabdff1aSopenharmony_ci CASE(VK_ERROR_FORMAT_NOT_SUPPORTED); 381cabdff1aSopenharmony_ci CASE(VK_ERROR_FRAGMENTED_POOL); 382cabdff1aSopenharmony_ci CASE(VK_ERROR_SURFACE_LOST_KHR); 383cabdff1aSopenharmony_ci CASE(VK_ERROR_NATIVE_WINDOW_IN_USE_KHR); 384cabdff1aSopenharmony_ci CASE(VK_SUBOPTIMAL_KHR); 385cabdff1aSopenharmony_ci CASE(VK_ERROR_OUT_OF_DATE_KHR); 386cabdff1aSopenharmony_ci CASE(VK_ERROR_INCOMPATIBLE_DISPLAY_KHR); 387cabdff1aSopenharmony_ci CASE(VK_ERROR_VALIDATION_FAILED_EXT); 388cabdff1aSopenharmony_ci CASE(VK_ERROR_INVALID_SHADER_NV); 389cabdff1aSopenharmony_ci CASE(VK_ERROR_OUT_OF_POOL_MEMORY); 390cabdff1aSopenharmony_ci CASE(VK_ERROR_INVALID_EXTERNAL_HANDLE); 391cabdff1aSopenharmony_ci CASE(VK_ERROR_NOT_PERMITTED_EXT); 392cabdff1aSopenharmony_ci CASE(VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT); 393cabdff1aSopenharmony_ci CASE(VK_ERROR_INVALID_DEVICE_ADDRESS_EXT); 394cabdff1aSopenharmony_ci CASE(VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT); 395cabdff1aSopenharmony_ci default: return "Unknown error"; 396cabdff1aSopenharmony_ci } 397cabdff1aSopenharmony_ci#undef CASE 398cabdff1aSopenharmony_ci} 399cabdff1aSopenharmony_ci 400cabdff1aSopenharmony_cistatic VkBool32 VKAPI_CALL vk_dbg_callback(VkDebugUtilsMessageSeverityFlagBitsEXT severity, 401cabdff1aSopenharmony_ci VkDebugUtilsMessageTypeFlagsEXT messageType, 402cabdff1aSopenharmony_ci const VkDebugUtilsMessengerCallbackDataEXT *data, 403cabdff1aSopenharmony_ci void *priv) 404cabdff1aSopenharmony_ci{ 405cabdff1aSopenharmony_ci int l; 406cabdff1aSopenharmony_ci AVHWDeviceContext *ctx = priv; 407cabdff1aSopenharmony_ci 408cabdff1aSopenharmony_ci switch (severity) { 409cabdff1aSopenharmony_ci case VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT: l = AV_LOG_VERBOSE; break; 410cabdff1aSopenharmony_ci case VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT: l = AV_LOG_INFO; break; 411cabdff1aSopenharmony_ci case VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT: l = AV_LOG_WARNING; break; 412cabdff1aSopenharmony_ci case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT: l = AV_LOG_ERROR; break; 413cabdff1aSopenharmony_ci default: l = AV_LOG_DEBUG; break; 414cabdff1aSopenharmony_ci } 415cabdff1aSopenharmony_ci 416cabdff1aSopenharmony_ci av_log(ctx, l, "%s\n", data->pMessage); 417cabdff1aSopenharmony_ci for (int i = 0; i < data->cmdBufLabelCount; i++) 418cabdff1aSopenharmony_ci av_log(ctx, l, "\t%i: %s\n", i, data->pCmdBufLabels[i].pLabelName); 419cabdff1aSopenharmony_ci 420cabdff1aSopenharmony_ci return 0; 421cabdff1aSopenharmony_ci} 422cabdff1aSopenharmony_ci 423cabdff1aSopenharmony_cistatic int check_extensions(AVHWDeviceContext *ctx, int dev, AVDictionary *opts, 424cabdff1aSopenharmony_ci const char * const **dst, uint32_t *num, int debug) 425cabdff1aSopenharmony_ci{ 426cabdff1aSopenharmony_ci const char *tstr; 427cabdff1aSopenharmony_ci const char **extension_names = NULL; 428cabdff1aSopenharmony_ci VulkanDevicePriv *p = ctx->internal->priv; 429cabdff1aSopenharmony_ci FFVulkanFunctions *vk = &p->vkfn; 430cabdff1aSopenharmony_ci AVVulkanDeviceContext *hwctx = ctx->hwctx; 431cabdff1aSopenharmony_ci int err = 0, found, extensions_found = 0; 432cabdff1aSopenharmony_ci 433cabdff1aSopenharmony_ci const char *mod; 434cabdff1aSopenharmony_ci int optional_exts_num; 435cabdff1aSopenharmony_ci uint32_t sup_ext_count; 436cabdff1aSopenharmony_ci char *user_exts_str = NULL; 437cabdff1aSopenharmony_ci AVDictionaryEntry *user_exts; 438cabdff1aSopenharmony_ci VkExtensionProperties *sup_ext; 439cabdff1aSopenharmony_ci const VulkanOptExtension *optional_exts; 440cabdff1aSopenharmony_ci 441cabdff1aSopenharmony_ci if (!dev) { 442cabdff1aSopenharmony_ci mod = "instance"; 443cabdff1aSopenharmony_ci optional_exts = optional_instance_exts; 444cabdff1aSopenharmony_ci optional_exts_num = FF_ARRAY_ELEMS(optional_instance_exts); 445cabdff1aSopenharmony_ci user_exts = av_dict_get(opts, "instance_extensions", NULL, 0); 446cabdff1aSopenharmony_ci if (user_exts) { 447cabdff1aSopenharmony_ci user_exts_str = av_strdup(user_exts->value); 448cabdff1aSopenharmony_ci if (!user_exts_str) { 449cabdff1aSopenharmony_ci err = AVERROR(ENOMEM); 450cabdff1aSopenharmony_ci goto fail; 451cabdff1aSopenharmony_ci } 452cabdff1aSopenharmony_ci } 453cabdff1aSopenharmony_ci vk->EnumerateInstanceExtensionProperties(NULL, &sup_ext_count, NULL); 454cabdff1aSopenharmony_ci sup_ext = av_malloc_array(sup_ext_count, sizeof(VkExtensionProperties)); 455cabdff1aSopenharmony_ci if (!sup_ext) 456cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 457cabdff1aSopenharmony_ci vk->EnumerateInstanceExtensionProperties(NULL, &sup_ext_count, sup_ext); 458cabdff1aSopenharmony_ci } else { 459cabdff1aSopenharmony_ci mod = "device"; 460cabdff1aSopenharmony_ci optional_exts = optional_device_exts; 461cabdff1aSopenharmony_ci optional_exts_num = FF_ARRAY_ELEMS(optional_device_exts); 462cabdff1aSopenharmony_ci user_exts = av_dict_get(opts, "device_extensions", NULL, 0); 463cabdff1aSopenharmony_ci if (user_exts) { 464cabdff1aSopenharmony_ci user_exts_str = av_strdup(user_exts->value); 465cabdff1aSopenharmony_ci if (!user_exts_str) { 466cabdff1aSopenharmony_ci err = AVERROR(ENOMEM); 467cabdff1aSopenharmony_ci goto fail; 468cabdff1aSopenharmony_ci } 469cabdff1aSopenharmony_ci } 470cabdff1aSopenharmony_ci vk->EnumerateDeviceExtensionProperties(hwctx->phys_dev, NULL, 471cabdff1aSopenharmony_ci &sup_ext_count, NULL); 472cabdff1aSopenharmony_ci sup_ext = av_malloc_array(sup_ext_count, sizeof(VkExtensionProperties)); 473cabdff1aSopenharmony_ci if (!sup_ext) 474cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 475cabdff1aSopenharmony_ci vk->EnumerateDeviceExtensionProperties(hwctx->phys_dev, NULL, 476cabdff1aSopenharmony_ci &sup_ext_count, sup_ext); 477cabdff1aSopenharmony_ci } 478cabdff1aSopenharmony_ci 479cabdff1aSopenharmony_ci for (int i = 0; i < optional_exts_num; i++) { 480cabdff1aSopenharmony_ci tstr = optional_exts[i].name; 481cabdff1aSopenharmony_ci found = 0; 482cabdff1aSopenharmony_ci for (int j = 0; j < sup_ext_count; j++) { 483cabdff1aSopenharmony_ci if (!strcmp(tstr, sup_ext[j].extensionName)) { 484cabdff1aSopenharmony_ci found = 1; 485cabdff1aSopenharmony_ci break; 486cabdff1aSopenharmony_ci } 487cabdff1aSopenharmony_ci } 488cabdff1aSopenharmony_ci if (!found) 489cabdff1aSopenharmony_ci continue; 490cabdff1aSopenharmony_ci 491cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_VERBOSE, "Using %s extension %s\n", mod, tstr); 492cabdff1aSopenharmony_ci p->extensions |= optional_exts[i].flag; 493cabdff1aSopenharmony_ci ADD_VAL_TO_LIST(extension_names, extensions_found, tstr); 494cabdff1aSopenharmony_ci } 495cabdff1aSopenharmony_ci 496cabdff1aSopenharmony_ci if (debug && !dev) { 497cabdff1aSopenharmony_ci tstr = VK_EXT_DEBUG_UTILS_EXTENSION_NAME; 498cabdff1aSopenharmony_ci found = 0; 499cabdff1aSopenharmony_ci for (int j = 0; j < sup_ext_count; j++) { 500cabdff1aSopenharmony_ci if (!strcmp(tstr, sup_ext[j].extensionName)) { 501cabdff1aSopenharmony_ci found = 1; 502cabdff1aSopenharmony_ci break; 503cabdff1aSopenharmony_ci } 504cabdff1aSopenharmony_ci } 505cabdff1aSopenharmony_ci if (found) { 506cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_VERBOSE, "Using %s extension %s\n", mod, tstr); 507cabdff1aSopenharmony_ci ADD_VAL_TO_LIST(extension_names, extensions_found, tstr); 508cabdff1aSopenharmony_ci p->extensions |= FF_VK_EXT_DEBUG_UTILS; 509cabdff1aSopenharmony_ci } else { 510cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_ERROR, "Debug extension \"%s\" not found!\n", 511cabdff1aSopenharmony_ci tstr); 512cabdff1aSopenharmony_ci err = AVERROR(EINVAL); 513cabdff1aSopenharmony_ci goto fail; 514cabdff1aSopenharmony_ci } 515cabdff1aSopenharmony_ci } 516cabdff1aSopenharmony_ci 517cabdff1aSopenharmony_ci if (user_exts_str) { 518cabdff1aSopenharmony_ci char *save, *token = av_strtok(user_exts_str, "+", &save); 519cabdff1aSopenharmony_ci while (token) { 520cabdff1aSopenharmony_ci found = 0; 521cabdff1aSopenharmony_ci for (int j = 0; j < sup_ext_count; j++) { 522cabdff1aSopenharmony_ci if (!strcmp(token, sup_ext[j].extensionName)) { 523cabdff1aSopenharmony_ci found = 1; 524cabdff1aSopenharmony_ci break; 525cabdff1aSopenharmony_ci } 526cabdff1aSopenharmony_ci } 527cabdff1aSopenharmony_ci if (found) { 528cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_VERBOSE, "Using %s extension \"%s\"\n", mod, token); 529cabdff1aSopenharmony_ci ADD_VAL_TO_LIST(extension_names, extensions_found, token); 530cabdff1aSopenharmony_ci } else { 531cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_WARNING, "%s extension \"%s\" not found, excluding.\n", 532cabdff1aSopenharmony_ci mod, token); 533cabdff1aSopenharmony_ci } 534cabdff1aSopenharmony_ci token = av_strtok(NULL, "+", &save); 535cabdff1aSopenharmony_ci } 536cabdff1aSopenharmony_ci } 537cabdff1aSopenharmony_ci 538cabdff1aSopenharmony_ci *dst = extension_names; 539cabdff1aSopenharmony_ci *num = extensions_found; 540cabdff1aSopenharmony_ci 541cabdff1aSopenharmony_ci av_free(user_exts_str); 542cabdff1aSopenharmony_ci av_free(sup_ext); 543cabdff1aSopenharmony_ci return 0; 544cabdff1aSopenharmony_ci 545cabdff1aSopenharmony_cifail: 546cabdff1aSopenharmony_ci RELEASE_PROPS(extension_names, extensions_found); 547cabdff1aSopenharmony_ci av_free(user_exts_str); 548cabdff1aSopenharmony_ci av_free(sup_ext); 549cabdff1aSopenharmony_ci return err; 550cabdff1aSopenharmony_ci} 551cabdff1aSopenharmony_ci 552cabdff1aSopenharmony_cistatic int check_validation_layers(AVHWDeviceContext *ctx, AVDictionary *opts, 553cabdff1aSopenharmony_ci const char * const **dst, uint32_t *num, 554cabdff1aSopenharmony_ci int *debug_mode) 555cabdff1aSopenharmony_ci{ 556cabdff1aSopenharmony_ci static const char default_layer[] = { "VK_LAYER_KHRONOS_validation" }; 557cabdff1aSopenharmony_ci 558cabdff1aSopenharmony_ci int found = 0, err = 0; 559cabdff1aSopenharmony_ci VulkanDevicePriv *priv = ctx->internal->priv; 560cabdff1aSopenharmony_ci FFVulkanFunctions *vk = &priv->vkfn; 561cabdff1aSopenharmony_ci 562cabdff1aSopenharmony_ci uint32_t sup_layer_count; 563cabdff1aSopenharmony_ci VkLayerProperties *sup_layers; 564cabdff1aSopenharmony_ci 565cabdff1aSopenharmony_ci AVDictionaryEntry *user_layers; 566cabdff1aSopenharmony_ci char *user_layers_str = NULL; 567cabdff1aSopenharmony_ci char *save, *token; 568cabdff1aSopenharmony_ci 569cabdff1aSopenharmony_ci const char **enabled_layers = NULL; 570cabdff1aSopenharmony_ci uint32_t enabled_layers_count = 0; 571cabdff1aSopenharmony_ci 572cabdff1aSopenharmony_ci AVDictionaryEntry *debug_opt = av_dict_get(opts, "debug", NULL, 0); 573cabdff1aSopenharmony_ci int debug = debug_opt && strtol(debug_opt->value, NULL, 10); 574cabdff1aSopenharmony_ci 575cabdff1aSopenharmony_ci /* If `debug=0`, enable no layers at all. */ 576cabdff1aSopenharmony_ci if (debug_opt && !debug) 577cabdff1aSopenharmony_ci return 0; 578cabdff1aSopenharmony_ci 579cabdff1aSopenharmony_ci vk->EnumerateInstanceLayerProperties(&sup_layer_count, NULL); 580cabdff1aSopenharmony_ci sup_layers = av_malloc_array(sup_layer_count, sizeof(VkLayerProperties)); 581cabdff1aSopenharmony_ci if (!sup_layers) 582cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 583cabdff1aSopenharmony_ci vk->EnumerateInstanceLayerProperties(&sup_layer_count, sup_layers); 584cabdff1aSopenharmony_ci 585cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_VERBOSE, "Supported validation layers:\n"); 586cabdff1aSopenharmony_ci for (int i = 0; i < sup_layer_count; i++) 587cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_VERBOSE, "\t%s\n", sup_layers[i].layerName); 588cabdff1aSopenharmony_ci 589cabdff1aSopenharmony_ci /* If `debug=1` is specified, enable the standard validation layer extension */ 590cabdff1aSopenharmony_ci if (debug) { 591cabdff1aSopenharmony_ci *debug_mode = debug; 592cabdff1aSopenharmony_ci for (int i = 0; i < sup_layer_count; i++) { 593cabdff1aSopenharmony_ci if (!strcmp(default_layer, sup_layers[i].layerName)) { 594cabdff1aSopenharmony_ci found = 1; 595cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_VERBOSE, "Default validation layer %s is enabled\n", 596cabdff1aSopenharmony_ci default_layer); 597cabdff1aSopenharmony_ci ADD_VAL_TO_LIST(enabled_layers, enabled_layers_count, default_layer); 598cabdff1aSopenharmony_ci break; 599cabdff1aSopenharmony_ci } 600cabdff1aSopenharmony_ci } 601cabdff1aSopenharmony_ci } 602cabdff1aSopenharmony_ci 603cabdff1aSopenharmony_ci user_layers = av_dict_get(opts, "validation_layers", NULL, 0); 604cabdff1aSopenharmony_ci if (!user_layers) 605cabdff1aSopenharmony_ci goto end; 606cabdff1aSopenharmony_ci 607cabdff1aSopenharmony_ci user_layers_str = av_strdup(user_layers->value); 608cabdff1aSopenharmony_ci if (!user_layers_str) { 609cabdff1aSopenharmony_ci err = AVERROR(ENOMEM); 610cabdff1aSopenharmony_ci goto fail; 611cabdff1aSopenharmony_ci } 612cabdff1aSopenharmony_ci 613cabdff1aSopenharmony_ci token = av_strtok(user_layers_str, "+", &save); 614cabdff1aSopenharmony_ci while (token) { 615cabdff1aSopenharmony_ci found = 0; 616cabdff1aSopenharmony_ci if (!strcmp(default_layer, token)) { 617cabdff1aSopenharmony_ci if (debug) { 618cabdff1aSopenharmony_ci /* if the `debug=1`, default_layer is enabled, skip here */ 619cabdff1aSopenharmony_ci token = av_strtok(NULL, "+", &save); 620cabdff1aSopenharmony_ci continue; 621cabdff1aSopenharmony_ci } else { 622cabdff1aSopenharmony_ci /* if the `debug=0`, enable debug mode to load its callback properly */ 623cabdff1aSopenharmony_ci *debug_mode = debug; 624cabdff1aSopenharmony_ci } 625cabdff1aSopenharmony_ci } 626cabdff1aSopenharmony_ci for (int j = 0; j < sup_layer_count; j++) { 627cabdff1aSopenharmony_ci if (!strcmp(token, sup_layers[j].layerName)) { 628cabdff1aSopenharmony_ci found = 1; 629cabdff1aSopenharmony_ci break; 630cabdff1aSopenharmony_ci } 631cabdff1aSopenharmony_ci } 632cabdff1aSopenharmony_ci if (found) { 633cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_VERBOSE, "Requested Validation Layer: %s\n", token); 634cabdff1aSopenharmony_ci ADD_VAL_TO_LIST(enabled_layers, enabled_layers_count, token); 635cabdff1aSopenharmony_ci } else { 636cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_ERROR, 637cabdff1aSopenharmony_ci "Validation Layer \"%s\" not support.\n", token); 638cabdff1aSopenharmony_ci err = AVERROR(EINVAL); 639cabdff1aSopenharmony_ci goto fail; 640cabdff1aSopenharmony_ci } 641cabdff1aSopenharmony_ci token = av_strtok(NULL, "+", &save); 642cabdff1aSopenharmony_ci } 643cabdff1aSopenharmony_ci 644cabdff1aSopenharmony_ci av_free(user_layers_str); 645cabdff1aSopenharmony_ci 646cabdff1aSopenharmony_ciend: 647cabdff1aSopenharmony_ci av_free(sup_layers); 648cabdff1aSopenharmony_ci 649cabdff1aSopenharmony_ci *dst = enabled_layers; 650cabdff1aSopenharmony_ci *num = enabled_layers_count; 651cabdff1aSopenharmony_ci 652cabdff1aSopenharmony_ci return 0; 653cabdff1aSopenharmony_ci 654cabdff1aSopenharmony_cifail: 655cabdff1aSopenharmony_ci RELEASE_PROPS(enabled_layers, enabled_layers_count); 656cabdff1aSopenharmony_ci av_free(sup_layers); 657cabdff1aSopenharmony_ci av_free(user_layers_str); 658cabdff1aSopenharmony_ci return err; 659cabdff1aSopenharmony_ci} 660cabdff1aSopenharmony_ci 661cabdff1aSopenharmony_ci/* Creates a VkInstance */ 662cabdff1aSopenharmony_cistatic int create_instance(AVHWDeviceContext *ctx, AVDictionary *opts) 663cabdff1aSopenharmony_ci{ 664cabdff1aSopenharmony_ci int err = 0, debug_mode = 0; 665cabdff1aSopenharmony_ci VkResult ret; 666cabdff1aSopenharmony_ci VulkanDevicePriv *p = ctx->internal->priv; 667cabdff1aSopenharmony_ci FFVulkanFunctions *vk = &p->vkfn; 668cabdff1aSopenharmony_ci AVVulkanDeviceContext *hwctx = ctx->hwctx; 669cabdff1aSopenharmony_ci VkApplicationInfo application_info = { 670cabdff1aSopenharmony_ci .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, 671cabdff1aSopenharmony_ci .pEngineName = "libavutil", 672cabdff1aSopenharmony_ci .apiVersion = VK_API_VERSION_1_2, 673cabdff1aSopenharmony_ci .engineVersion = VK_MAKE_VERSION(LIBAVUTIL_VERSION_MAJOR, 674cabdff1aSopenharmony_ci LIBAVUTIL_VERSION_MINOR, 675cabdff1aSopenharmony_ci LIBAVUTIL_VERSION_MICRO), 676cabdff1aSopenharmony_ci }; 677cabdff1aSopenharmony_ci VkInstanceCreateInfo inst_props = { 678cabdff1aSopenharmony_ci .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, 679cabdff1aSopenharmony_ci .pApplicationInfo = &application_info, 680cabdff1aSopenharmony_ci }; 681cabdff1aSopenharmony_ci 682cabdff1aSopenharmony_ci if (!hwctx->get_proc_addr) { 683cabdff1aSopenharmony_ci err = load_libvulkan(ctx); 684cabdff1aSopenharmony_ci if (err < 0) 685cabdff1aSopenharmony_ci return err; 686cabdff1aSopenharmony_ci } 687cabdff1aSopenharmony_ci 688cabdff1aSopenharmony_ci err = ff_vk_load_functions(ctx, vk, p->extensions, 0, 0); 689cabdff1aSopenharmony_ci if (err < 0) { 690cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_ERROR, "Unable to load instance enumeration functions!\n"); 691cabdff1aSopenharmony_ci return err; 692cabdff1aSopenharmony_ci } 693cabdff1aSopenharmony_ci 694cabdff1aSopenharmony_ci err = check_validation_layers(ctx, opts, &inst_props.ppEnabledLayerNames, 695cabdff1aSopenharmony_ci &inst_props.enabledLayerCount, &debug_mode); 696cabdff1aSopenharmony_ci if (err) 697cabdff1aSopenharmony_ci goto fail; 698cabdff1aSopenharmony_ci 699cabdff1aSopenharmony_ci /* Check for present/missing extensions */ 700cabdff1aSopenharmony_ci err = check_extensions(ctx, 0, opts, &inst_props.ppEnabledExtensionNames, 701cabdff1aSopenharmony_ci &inst_props.enabledExtensionCount, debug_mode); 702cabdff1aSopenharmony_ci hwctx->enabled_inst_extensions = inst_props.ppEnabledExtensionNames; 703cabdff1aSopenharmony_ci hwctx->nb_enabled_inst_extensions = inst_props.enabledExtensionCount; 704cabdff1aSopenharmony_ci if (err < 0) 705cabdff1aSopenharmony_ci goto fail; 706cabdff1aSopenharmony_ci 707cabdff1aSopenharmony_ci /* Try to create the instance */ 708cabdff1aSopenharmony_ci ret = vk->CreateInstance(&inst_props, hwctx->alloc, &hwctx->inst); 709cabdff1aSopenharmony_ci 710cabdff1aSopenharmony_ci /* Check for errors */ 711cabdff1aSopenharmony_ci if (ret != VK_SUCCESS) { 712cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_ERROR, "Instance creation failure: %s\n", 713cabdff1aSopenharmony_ci vk_ret2str(ret)); 714cabdff1aSopenharmony_ci err = AVERROR_EXTERNAL; 715cabdff1aSopenharmony_ci goto fail; 716cabdff1aSopenharmony_ci } 717cabdff1aSopenharmony_ci 718cabdff1aSopenharmony_ci err = ff_vk_load_functions(ctx, vk, p->extensions, 1, 0); 719cabdff1aSopenharmony_ci if (err < 0) { 720cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_ERROR, "Unable to load instance functions!\n"); 721cabdff1aSopenharmony_ci goto fail; 722cabdff1aSopenharmony_ci } 723cabdff1aSopenharmony_ci 724cabdff1aSopenharmony_ci if (debug_mode) { 725cabdff1aSopenharmony_ci VkDebugUtilsMessengerCreateInfoEXT dbg = { 726cabdff1aSopenharmony_ci .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, 727cabdff1aSopenharmony_ci .messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | 728cabdff1aSopenharmony_ci VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT | 729cabdff1aSopenharmony_ci VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | 730cabdff1aSopenharmony_ci VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT, 731cabdff1aSopenharmony_ci .messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | 732cabdff1aSopenharmony_ci VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | 733cabdff1aSopenharmony_ci VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT, 734cabdff1aSopenharmony_ci .pfnUserCallback = vk_dbg_callback, 735cabdff1aSopenharmony_ci .pUserData = ctx, 736cabdff1aSopenharmony_ci }; 737cabdff1aSopenharmony_ci 738cabdff1aSopenharmony_ci vk->CreateDebugUtilsMessengerEXT(hwctx->inst, &dbg, 739cabdff1aSopenharmony_ci hwctx->alloc, &p->debug_ctx); 740cabdff1aSopenharmony_ci } 741cabdff1aSopenharmony_ci 742cabdff1aSopenharmony_ci err = 0; 743cabdff1aSopenharmony_ci 744cabdff1aSopenharmony_cifail: 745cabdff1aSopenharmony_ci RELEASE_PROPS(inst_props.ppEnabledLayerNames, inst_props.enabledLayerCount); 746cabdff1aSopenharmony_ci return err; 747cabdff1aSopenharmony_ci} 748cabdff1aSopenharmony_ci 749cabdff1aSopenharmony_citypedef struct VulkanDeviceSelection { 750cabdff1aSopenharmony_ci uint8_t uuid[VK_UUID_SIZE]; /* Will use this first unless !has_uuid */ 751cabdff1aSopenharmony_ci int has_uuid; 752cabdff1aSopenharmony_ci const char *name; /* Will use this second unless NULL */ 753cabdff1aSopenharmony_ci uint32_t pci_device; /* Will use this third unless 0x0 */ 754cabdff1aSopenharmony_ci uint32_t vendor_id; /* Last resort to find something deterministic */ 755cabdff1aSopenharmony_ci int index; /* Finally fall back to index */ 756cabdff1aSopenharmony_ci} VulkanDeviceSelection; 757cabdff1aSopenharmony_ci 758cabdff1aSopenharmony_cistatic const char *vk_dev_type(enum VkPhysicalDeviceType type) 759cabdff1aSopenharmony_ci{ 760cabdff1aSopenharmony_ci switch (type) { 761cabdff1aSopenharmony_ci case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU: return "integrated"; 762cabdff1aSopenharmony_ci case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: return "discrete"; 763cabdff1aSopenharmony_ci case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU: return "virtual"; 764cabdff1aSopenharmony_ci case VK_PHYSICAL_DEVICE_TYPE_CPU: return "software"; 765cabdff1aSopenharmony_ci default: return "unknown"; 766cabdff1aSopenharmony_ci } 767cabdff1aSopenharmony_ci} 768cabdff1aSopenharmony_ci 769cabdff1aSopenharmony_ci/* Finds a device */ 770cabdff1aSopenharmony_cistatic int find_device(AVHWDeviceContext *ctx, VulkanDeviceSelection *select) 771cabdff1aSopenharmony_ci{ 772cabdff1aSopenharmony_ci int err = 0, choice = -1; 773cabdff1aSopenharmony_ci uint32_t num; 774cabdff1aSopenharmony_ci VkResult ret; 775cabdff1aSopenharmony_ci VulkanDevicePriv *p = ctx->internal->priv; 776cabdff1aSopenharmony_ci FFVulkanFunctions *vk = &p->vkfn; 777cabdff1aSopenharmony_ci VkPhysicalDevice *devices = NULL; 778cabdff1aSopenharmony_ci VkPhysicalDeviceIDProperties *idp = NULL; 779cabdff1aSopenharmony_ci VkPhysicalDeviceProperties2 *prop = NULL; 780cabdff1aSopenharmony_ci AVVulkanDeviceContext *hwctx = ctx->hwctx; 781cabdff1aSopenharmony_ci 782cabdff1aSopenharmony_ci ret = vk->EnumeratePhysicalDevices(hwctx->inst, &num, NULL); 783cabdff1aSopenharmony_ci if (ret != VK_SUCCESS || !num) { 784cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_ERROR, "No devices found: %s!\n", vk_ret2str(ret)); 785cabdff1aSopenharmony_ci return AVERROR(ENODEV); 786cabdff1aSopenharmony_ci } 787cabdff1aSopenharmony_ci 788cabdff1aSopenharmony_ci devices = av_malloc_array(num, sizeof(VkPhysicalDevice)); 789cabdff1aSopenharmony_ci if (!devices) 790cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 791cabdff1aSopenharmony_ci 792cabdff1aSopenharmony_ci ret = vk->EnumeratePhysicalDevices(hwctx->inst, &num, devices); 793cabdff1aSopenharmony_ci if (ret != VK_SUCCESS) { 794cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_ERROR, "Failed enumerating devices: %s\n", 795cabdff1aSopenharmony_ci vk_ret2str(ret)); 796cabdff1aSopenharmony_ci err = AVERROR(ENODEV); 797cabdff1aSopenharmony_ci goto end; 798cabdff1aSopenharmony_ci } 799cabdff1aSopenharmony_ci 800cabdff1aSopenharmony_ci prop = av_calloc(num, sizeof(*prop)); 801cabdff1aSopenharmony_ci if (!prop) { 802cabdff1aSopenharmony_ci err = AVERROR(ENOMEM); 803cabdff1aSopenharmony_ci goto end; 804cabdff1aSopenharmony_ci } 805cabdff1aSopenharmony_ci 806cabdff1aSopenharmony_ci idp = av_calloc(num, sizeof(*idp)); 807cabdff1aSopenharmony_ci if (!idp) { 808cabdff1aSopenharmony_ci err = AVERROR(ENOMEM); 809cabdff1aSopenharmony_ci goto end; 810cabdff1aSopenharmony_ci } 811cabdff1aSopenharmony_ci 812cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_VERBOSE, "GPU listing:\n"); 813cabdff1aSopenharmony_ci for (int i = 0; i < num; i++) { 814cabdff1aSopenharmony_ci idp[i].sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES; 815cabdff1aSopenharmony_ci prop[i].sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; 816cabdff1aSopenharmony_ci prop[i].pNext = &idp[i]; 817cabdff1aSopenharmony_ci 818cabdff1aSopenharmony_ci vk->GetPhysicalDeviceProperties2(devices[i], &prop[i]); 819cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_VERBOSE, " %d: %s (%s) (0x%x)\n", i, 820cabdff1aSopenharmony_ci prop[i].properties.deviceName, 821cabdff1aSopenharmony_ci vk_dev_type(prop[i].properties.deviceType), 822cabdff1aSopenharmony_ci prop[i].properties.deviceID); 823cabdff1aSopenharmony_ci } 824cabdff1aSopenharmony_ci 825cabdff1aSopenharmony_ci if (select->has_uuid) { 826cabdff1aSopenharmony_ci for (int i = 0; i < num; i++) { 827cabdff1aSopenharmony_ci if (!strncmp(idp[i].deviceUUID, select->uuid, VK_UUID_SIZE)) { 828cabdff1aSopenharmony_ci choice = i; 829cabdff1aSopenharmony_ci goto end; 830cabdff1aSopenharmony_ci } 831cabdff1aSopenharmony_ci } 832cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_ERROR, "Unable to find device by given UUID!\n"); 833cabdff1aSopenharmony_ci err = AVERROR(ENODEV); 834cabdff1aSopenharmony_ci goto end; 835cabdff1aSopenharmony_ci } else if (select->name) { 836cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_VERBOSE, "Requested device: %s\n", select->name); 837cabdff1aSopenharmony_ci for (int i = 0; i < num; i++) { 838cabdff1aSopenharmony_ci if (strstr(prop[i].properties.deviceName, select->name)) { 839cabdff1aSopenharmony_ci choice = i; 840cabdff1aSopenharmony_ci goto end; 841cabdff1aSopenharmony_ci } 842cabdff1aSopenharmony_ci } 843cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_ERROR, "Unable to find device \"%s\"!\n", 844cabdff1aSopenharmony_ci select->name); 845cabdff1aSopenharmony_ci err = AVERROR(ENODEV); 846cabdff1aSopenharmony_ci goto end; 847cabdff1aSopenharmony_ci } else if (select->pci_device) { 848cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_VERBOSE, "Requested device: 0x%x\n", select->pci_device); 849cabdff1aSopenharmony_ci for (int i = 0; i < num; i++) { 850cabdff1aSopenharmony_ci if (select->pci_device == prop[i].properties.deviceID) { 851cabdff1aSopenharmony_ci choice = i; 852cabdff1aSopenharmony_ci goto end; 853cabdff1aSopenharmony_ci } 854cabdff1aSopenharmony_ci } 855cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_ERROR, "Unable to find device with PCI ID 0x%x!\n", 856cabdff1aSopenharmony_ci select->pci_device); 857cabdff1aSopenharmony_ci err = AVERROR(EINVAL); 858cabdff1aSopenharmony_ci goto end; 859cabdff1aSopenharmony_ci } else if (select->vendor_id) { 860cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_VERBOSE, "Requested vendor: 0x%x\n", select->vendor_id); 861cabdff1aSopenharmony_ci for (int i = 0; i < num; i++) { 862cabdff1aSopenharmony_ci if (select->vendor_id == prop[i].properties.vendorID) { 863cabdff1aSopenharmony_ci choice = i; 864cabdff1aSopenharmony_ci goto end; 865cabdff1aSopenharmony_ci } 866cabdff1aSopenharmony_ci } 867cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_ERROR, "Unable to find device with Vendor ID 0x%x!\n", 868cabdff1aSopenharmony_ci select->vendor_id); 869cabdff1aSopenharmony_ci err = AVERROR(ENODEV); 870cabdff1aSopenharmony_ci goto end; 871cabdff1aSopenharmony_ci } else { 872cabdff1aSopenharmony_ci if (select->index < num) { 873cabdff1aSopenharmony_ci choice = select->index; 874cabdff1aSopenharmony_ci goto end; 875cabdff1aSopenharmony_ci } 876cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_ERROR, "Unable to find device with index %i!\n", 877cabdff1aSopenharmony_ci select->index); 878cabdff1aSopenharmony_ci err = AVERROR(ENODEV); 879cabdff1aSopenharmony_ci goto end; 880cabdff1aSopenharmony_ci } 881cabdff1aSopenharmony_ci 882cabdff1aSopenharmony_ciend: 883cabdff1aSopenharmony_ci if (choice > -1) { 884cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_VERBOSE, "Device %d selected: %s (%s) (0x%x)\n", 885cabdff1aSopenharmony_ci choice, prop[choice].properties.deviceName, 886cabdff1aSopenharmony_ci vk_dev_type(prop[choice].properties.deviceType), 887cabdff1aSopenharmony_ci prop[choice].properties.deviceID); 888cabdff1aSopenharmony_ci hwctx->phys_dev = devices[choice]; 889cabdff1aSopenharmony_ci } 890cabdff1aSopenharmony_ci 891cabdff1aSopenharmony_ci av_free(devices); 892cabdff1aSopenharmony_ci av_free(prop); 893cabdff1aSopenharmony_ci av_free(idp); 894cabdff1aSopenharmony_ci 895cabdff1aSopenharmony_ci return err; 896cabdff1aSopenharmony_ci} 897cabdff1aSopenharmony_ci 898cabdff1aSopenharmony_ci/* Picks the least used qf with the fewest unneeded flags, or -1 if none found */ 899cabdff1aSopenharmony_cistatic inline int pick_queue_family(VkQueueFamilyProperties *qf, uint32_t num_qf, 900cabdff1aSopenharmony_ci VkQueueFlagBits flags) 901cabdff1aSopenharmony_ci{ 902cabdff1aSopenharmony_ci int index = -1; 903cabdff1aSopenharmony_ci uint32_t min_score = UINT32_MAX; 904cabdff1aSopenharmony_ci 905cabdff1aSopenharmony_ci for (int i = 0; i < num_qf; i++) { 906cabdff1aSopenharmony_ci const VkQueueFlagBits qflags = qf[i].queueFlags; 907cabdff1aSopenharmony_ci if (qflags & flags) { 908cabdff1aSopenharmony_ci uint32_t score = av_popcount(qflags) + qf[i].timestampValidBits; 909cabdff1aSopenharmony_ci if (score < min_score) { 910cabdff1aSopenharmony_ci index = i; 911cabdff1aSopenharmony_ci min_score = score; 912cabdff1aSopenharmony_ci } 913cabdff1aSopenharmony_ci } 914cabdff1aSopenharmony_ci } 915cabdff1aSopenharmony_ci 916cabdff1aSopenharmony_ci if (index > -1) 917cabdff1aSopenharmony_ci qf[index].timestampValidBits++; 918cabdff1aSopenharmony_ci 919cabdff1aSopenharmony_ci return index; 920cabdff1aSopenharmony_ci} 921cabdff1aSopenharmony_ci 922cabdff1aSopenharmony_cistatic int setup_queue_families(AVHWDeviceContext *ctx, VkDeviceCreateInfo *cd) 923cabdff1aSopenharmony_ci{ 924cabdff1aSopenharmony_ci uint32_t num; 925cabdff1aSopenharmony_ci float *weights; 926cabdff1aSopenharmony_ci VkQueueFamilyProperties *qf = NULL; 927cabdff1aSopenharmony_ci VulkanDevicePriv *p = ctx->internal->priv; 928cabdff1aSopenharmony_ci FFVulkanFunctions *vk = &p->vkfn; 929cabdff1aSopenharmony_ci AVVulkanDeviceContext *hwctx = ctx->hwctx; 930cabdff1aSopenharmony_ci int graph_index, comp_index, tx_index, enc_index, dec_index; 931cabdff1aSopenharmony_ci 932cabdff1aSopenharmony_ci /* First get the number of queue families */ 933cabdff1aSopenharmony_ci vk->GetPhysicalDeviceQueueFamilyProperties(hwctx->phys_dev, &num, NULL); 934cabdff1aSopenharmony_ci if (!num) { 935cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_ERROR, "Failed to get queues!\n"); 936cabdff1aSopenharmony_ci return AVERROR_EXTERNAL; 937cabdff1aSopenharmony_ci } 938cabdff1aSopenharmony_ci 939cabdff1aSopenharmony_ci /* Then allocate memory */ 940cabdff1aSopenharmony_ci qf = av_malloc_array(num, sizeof(VkQueueFamilyProperties)); 941cabdff1aSopenharmony_ci if (!qf) 942cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 943cabdff1aSopenharmony_ci 944cabdff1aSopenharmony_ci /* Finally retrieve the queue families */ 945cabdff1aSopenharmony_ci vk->GetPhysicalDeviceQueueFamilyProperties(hwctx->phys_dev, &num, qf); 946cabdff1aSopenharmony_ci 947cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_VERBOSE, "Queue families:\n"); 948cabdff1aSopenharmony_ci for (int i = 0; i < num; i++) { 949cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_VERBOSE, " %i:%s%s%s%s%s%s%s (queues: %i)\n", i, 950cabdff1aSopenharmony_ci ((qf[i].queueFlags) & VK_QUEUE_GRAPHICS_BIT) ? " graphics" : "", 951cabdff1aSopenharmony_ci ((qf[i].queueFlags) & VK_QUEUE_COMPUTE_BIT) ? " compute" : "", 952cabdff1aSopenharmony_ci ((qf[i].queueFlags) & VK_QUEUE_TRANSFER_BIT) ? " transfer" : "", 953cabdff1aSopenharmony_ci ((qf[i].queueFlags) & VK_QUEUE_VIDEO_ENCODE_BIT_KHR) ? " encode" : "", 954cabdff1aSopenharmony_ci ((qf[i].queueFlags) & VK_QUEUE_VIDEO_DECODE_BIT_KHR) ? " decode" : "", 955cabdff1aSopenharmony_ci ((qf[i].queueFlags) & VK_QUEUE_SPARSE_BINDING_BIT) ? " sparse" : "", 956cabdff1aSopenharmony_ci ((qf[i].queueFlags) & VK_QUEUE_PROTECTED_BIT) ? " protected" : "", 957cabdff1aSopenharmony_ci qf[i].queueCount); 958cabdff1aSopenharmony_ci 959cabdff1aSopenharmony_ci /* We use this field to keep a score of how many times we've used that 960cabdff1aSopenharmony_ci * queue family in order to make better choices. */ 961cabdff1aSopenharmony_ci qf[i].timestampValidBits = 0; 962cabdff1aSopenharmony_ci } 963cabdff1aSopenharmony_ci 964cabdff1aSopenharmony_ci /* Pick each queue family to use */ 965cabdff1aSopenharmony_ci graph_index = pick_queue_family(qf, num, VK_QUEUE_GRAPHICS_BIT); 966cabdff1aSopenharmony_ci comp_index = pick_queue_family(qf, num, VK_QUEUE_COMPUTE_BIT); 967cabdff1aSopenharmony_ci tx_index = pick_queue_family(qf, num, VK_QUEUE_TRANSFER_BIT); 968cabdff1aSopenharmony_ci enc_index = pick_queue_family(qf, num, VK_QUEUE_VIDEO_ENCODE_BIT_KHR); 969cabdff1aSopenharmony_ci dec_index = pick_queue_family(qf, num, VK_QUEUE_VIDEO_DECODE_BIT_KHR); 970cabdff1aSopenharmony_ci 971cabdff1aSopenharmony_ci /* Signalling the transfer capabilities on a queue family is optional */ 972cabdff1aSopenharmony_ci if (tx_index < 0) { 973cabdff1aSopenharmony_ci tx_index = pick_queue_family(qf, num, VK_QUEUE_COMPUTE_BIT); 974cabdff1aSopenharmony_ci if (tx_index < 0) 975cabdff1aSopenharmony_ci tx_index = pick_queue_family(qf, num, VK_QUEUE_GRAPHICS_BIT); 976cabdff1aSopenharmony_ci } 977cabdff1aSopenharmony_ci 978cabdff1aSopenharmony_ci hwctx->queue_family_index = -1; 979cabdff1aSopenharmony_ci hwctx->queue_family_comp_index = -1; 980cabdff1aSopenharmony_ci hwctx->queue_family_tx_index = -1; 981cabdff1aSopenharmony_ci hwctx->queue_family_encode_index = -1; 982cabdff1aSopenharmony_ci hwctx->queue_family_decode_index = -1; 983cabdff1aSopenharmony_ci 984cabdff1aSopenharmony_ci#define SETUP_QUEUE(qf_idx) \ 985cabdff1aSopenharmony_ci if (qf_idx > -1) { \ 986cabdff1aSopenharmony_ci int fidx = qf_idx; \ 987cabdff1aSopenharmony_ci int qc = qf[fidx].queueCount; \ 988cabdff1aSopenharmony_ci VkDeviceQueueCreateInfo *pc; \ 989cabdff1aSopenharmony_ci \ 990cabdff1aSopenharmony_ci if (fidx == graph_index) { \ 991cabdff1aSopenharmony_ci hwctx->queue_family_index = fidx; \ 992cabdff1aSopenharmony_ci hwctx->nb_graphics_queues = qc; \ 993cabdff1aSopenharmony_ci graph_index = -1; \ 994cabdff1aSopenharmony_ci } \ 995cabdff1aSopenharmony_ci if (fidx == comp_index) { \ 996cabdff1aSopenharmony_ci hwctx->queue_family_comp_index = fidx; \ 997cabdff1aSopenharmony_ci hwctx->nb_comp_queues = qc; \ 998cabdff1aSopenharmony_ci comp_index = -1; \ 999cabdff1aSopenharmony_ci } \ 1000cabdff1aSopenharmony_ci if (fidx == tx_index) { \ 1001cabdff1aSopenharmony_ci hwctx->queue_family_tx_index = fidx; \ 1002cabdff1aSopenharmony_ci hwctx->nb_tx_queues = qc; \ 1003cabdff1aSopenharmony_ci tx_index = -1; \ 1004cabdff1aSopenharmony_ci } \ 1005cabdff1aSopenharmony_ci if (fidx == enc_index) { \ 1006cabdff1aSopenharmony_ci hwctx->queue_family_encode_index = fidx; \ 1007cabdff1aSopenharmony_ci hwctx->nb_encode_queues = qc; \ 1008cabdff1aSopenharmony_ci enc_index = -1; \ 1009cabdff1aSopenharmony_ci } \ 1010cabdff1aSopenharmony_ci if (fidx == dec_index) { \ 1011cabdff1aSopenharmony_ci hwctx->queue_family_decode_index = fidx; \ 1012cabdff1aSopenharmony_ci hwctx->nb_decode_queues = qc; \ 1013cabdff1aSopenharmony_ci dec_index = -1; \ 1014cabdff1aSopenharmony_ci } \ 1015cabdff1aSopenharmony_ci \ 1016cabdff1aSopenharmony_ci pc = av_realloc((void *)cd->pQueueCreateInfos, \ 1017cabdff1aSopenharmony_ci sizeof(*pc) * (cd->queueCreateInfoCount + 1)); \ 1018cabdff1aSopenharmony_ci if (!pc) { \ 1019cabdff1aSopenharmony_ci av_free(qf); \ 1020cabdff1aSopenharmony_ci return AVERROR(ENOMEM); \ 1021cabdff1aSopenharmony_ci } \ 1022cabdff1aSopenharmony_ci cd->pQueueCreateInfos = pc; \ 1023cabdff1aSopenharmony_ci pc = &pc[cd->queueCreateInfoCount]; \ 1024cabdff1aSopenharmony_ci \ 1025cabdff1aSopenharmony_ci weights = av_malloc(qc * sizeof(float)); \ 1026cabdff1aSopenharmony_ci if (!weights) { \ 1027cabdff1aSopenharmony_ci av_free(qf); \ 1028cabdff1aSopenharmony_ci return AVERROR(ENOMEM); \ 1029cabdff1aSopenharmony_ci } \ 1030cabdff1aSopenharmony_ci \ 1031cabdff1aSopenharmony_ci memset(pc, 0, sizeof(*pc)); \ 1032cabdff1aSopenharmony_ci pc->sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; \ 1033cabdff1aSopenharmony_ci pc->queueFamilyIndex = fidx; \ 1034cabdff1aSopenharmony_ci pc->queueCount = qc; \ 1035cabdff1aSopenharmony_ci pc->pQueuePriorities = weights; \ 1036cabdff1aSopenharmony_ci \ 1037cabdff1aSopenharmony_ci for (int i = 0; i < qc; i++) \ 1038cabdff1aSopenharmony_ci weights[i] = 1.0f / qc; \ 1039cabdff1aSopenharmony_ci \ 1040cabdff1aSopenharmony_ci cd->queueCreateInfoCount++; \ 1041cabdff1aSopenharmony_ci } 1042cabdff1aSopenharmony_ci 1043cabdff1aSopenharmony_ci SETUP_QUEUE(graph_index) 1044cabdff1aSopenharmony_ci SETUP_QUEUE(comp_index) 1045cabdff1aSopenharmony_ci SETUP_QUEUE(tx_index) 1046cabdff1aSopenharmony_ci SETUP_QUEUE(enc_index) 1047cabdff1aSopenharmony_ci SETUP_QUEUE(dec_index) 1048cabdff1aSopenharmony_ci 1049cabdff1aSopenharmony_ci#undef SETUP_QUEUE 1050cabdff1aSopenharmony_ci 1051cabdff1aSopenharmony_ci av_free(qf); 1052cabdff1aSopenharmony_ci 1053cabdff1aSopenharmony_ci return 0; 1054cabdff1aSopenharmony_ci} 1055cabdff1aSopenharmony_ci 1056cabdff1aSopenharmony_cistatic int create_exec_ctx(AVHWFramesContext *hwfc, VulkanExecCtx *cmd, 1057cabdff1aSopenharmony_ci int queue_family_index, int num_queues) 1058cabdff1aSopenharmony_ci{ 1059cabdff1aSopenharmony_ci VkResult ret; 1060cabdff1aSopenharmony_ci AVVulkanDeviceContext *hwctx = hwfc->device_ctx->hwctx; 1061cabdff1aSopenharmony_ci VulkanDevicePriv *p = hwfc->device_ctx->internal->priv; 1062cabdff1aSopenharmony_ci FFVulkanFunctions *vk = &p->vkfn; 1063cabdff1aSopenharmony_ci 1064cabdff1aSopenharmony_ci VkCommandPoolCreateInfo cqueue_create = { 1065cabdff1aSopenharmony_ci .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, 1066cabdff1aSopenharmony_ci .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, 1067cabdff1aSopenharmony_ci .queueFamilyIndex = queue_family_index, 1068cabdff1aSopenharmony_ci }; 1069cabdff1aSopenharmony_ci VkCommandBufferAllocateInfo cbuf_create = { 1070cabdff1aSopenharmony_ci .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, 1071cabdff1aSopenharmony_ci .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, 1072cabdff1aSopenharmony_ci .commandBufferCount = num_queues, 1073cabdff1aSopenharmony_ci }; 1074cabdff1aSopenharmony_ci 1075cabdff1aSopenharmony_ci cmd->nb_queues = num_queues; 1076cabdff1aSopenharmony_ci 1077cabdff1aSopenharmony_ci /* Create command pool */ 1078cabdff1aSopenharmony_ci ret = vk->CreateCommandPool(hwctx->act_dev, &cqueue_create, 1079cabdff1aSopenharmony_ci hwctx->alloc, &cmd->pool); 1080cabdff1aSopenharmony_ci if (ret != VK_SUCCESS) { 1081cabdff1aSopenharmony_ci av_log(hwfc, AV_LOG_ERROR, "Command pool creation failure: %s\n", 1082cabdff1aSopenharmony_ci vk_ret2str(ret)); 1083cabdff1aSopenharmony_ci return AVERROR_EXTERNAL; 1084cabdff1aSopenharmony_ci } 1085cabdff1aSopenharmony_ci 1086cabdff1aSopenharmony_ci cmd->bufs = av_mallocz(num_queues * sizeof(*cmd->bufs)); 1087cabdff1aSopenharmony_ci if (!cmd->bufs) 1088cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 1089cabdff1aSopenharmony_ci 1090cabdff1aSopenharmony_ci cbuf_create.commandPool = cmd->pool; 1091cabdff1aSopenharmony_ci 1092cabdff1aSopenharmony_ci /* Allocate command buffer */ 1093cabdff1aSopenharmony_ci ret = vk->AllocateCommandBuffers(hwctx->act_dev, &cbuf_create, cmd->bufs); 1094cabdff1aSopenharmony_ci if (ret != VK_SUCCESS) { 1095cabdff1aSopenharmony_ci av_log(hwfc, AV_LOG_ERROR, "Command buffer alloc failure: %s\n", 1096cabdff1aSopenharmony_ci vk_ret2str(ret)); 1097cabdff1aSopenharmony_ci av_freep(&cmd->bufs); 1098cabdff1aSopenharmony_ci return AVERROR_EXTERNAL; 1099cabdff1aSopenharmony_ci } 1100cabdff1aSopenharmony_ci 1101cabdff1aSopenharmony_ci cmd->queues = av_mallocz(num_queues * sizeof(*cmd->queues)); 1102cabdff1aSopenharmony_ci if (!cmd->queues) 1103cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 1104cabdff1aSopenharmony_ci 1105cabdff1aSopenharmony_ci for (int i = 0; i < num_queues; i++) { 1106cabdff1aSopenharmony_ci VulkanQueueCtx *q = &cmd->queues[i]; 1107cabdff1aSopenharmony_ci vk->GetDeviceQueue(hwctx->act_dev, queue_family_index, i, &q->queue); 1108cabdff1aSopenharmony_ci q->was_synchronous = 1; 1109cabdff1aSopenharmony_ci } 1110cabdff1aSopenharmony_ci 1111cabdff1aSopenharmony_ci return 0; 1112cabdff1aSopenharmony_ci} 1113cabdff1aSopenharmony_ci 1114cabdff1aSopenharmony_cistatic void free_exec_ctx(AVHWFramesContext *hwfc, VulkanExecCtx *cmd) 1115cabdff1aSopenharmony_ci{ 1116cabdff1aSopenharmony_ci AVVulkanDeviceContext *hwctx = hwfc->device_ctx->hwctx; 1117cabdff1aSopenharmony_ci VulkanDevicePriv *p = hwfc->device_ctx->internal->priv; 1118cabdff1aSopenharmony_ci FFVulkanFunctions *vk = &p->vkfn; 1119cabdff1aSopenharmony_ci 1120cabdff1aSopenharmony_ci if (cmd->queues) { 1121cabdff1aSopenharmony_ci for (int i = 0; i < cmd->nb_queues; i++) { 1122cabdff1aSopenharmony_ci VulkanQueueCtx *q = &cmd->queues[i]; 1123cabdff1aSopenharmony_ci 1124cabdff1aSopenharmony_ci /* Make sure all queues have finished executing */ 1125cabdff1aSopenharmony_ci if (q->fence && !q->was_synchronous) { 1126cabdff1aSopenharmony_ci vk->WaitForFences(hwctx->act_dev, 1, &q->fence, VK_TRUE, UINT64_MAX); 1127cabdff1aSopenharmony_ci vk->ResetFences(hwctx->act_dev, 1, &q->fence); 1128cabdff1aSopenharmony_ci } 1129cabdff1aSopenharmony_ci 1130cabdff1aSopenharmony_ci /* Free the fence */ 1131cabdff1aSopenharmony_ci if (q->fence) 1132cabdff1aSopenharmony_ci vk->DestroyFence(hwctx->act_dev, q->fence, hwctx->alloc); 1133cabdff1aSopenharmony_ci 1134cabdff1aSopenharmony_ci /* Free buffer dependencies */ 1135cabdff1aSopenharmony_ci for (int j = 0; j < q->nb_buf_deps; j++) 1136cabdff1aSopenharmony_ci av_buffer_unref(&q->buf_deps[j]); 1137cabdff1aSopenharmony_ci av_free(q->buf_deps); 1138cabdff1aSopenharmony_ci } 1139cabdff1aSopenharmony_ci } 1140cabdff1aSopenharmony_ci 1141cabdff1aSopenharmony_ci if (cmd->bufs) 1142cabdff1aSopenharmony_ci vk->FreeCommandBuffers(hwctx->act_dev, cmd->pool, cmd->nb_queues, cmd->bufs); 1143cabdff1aSopenharmony_ci if (cmd->pool) 1144cabdff1aSopenharmony_ci vk->DestroyCommandPool(hwctx->act_dev, cmd->pool, hwctx->alloc); 1145cabdff1aSopenharmony_ci 1146cabdff1aSopenharmony_ci av_freep(&cmd->queues); 1147cabdff1aSopenharmony_ci av_freep(&cmd->bufs); 1148cabdff1aSopenharmony_ci cmd->pool = VK_NULL_HANDLE; 1149cabdff1aSopenharmony_ci} 1150cabdff1aSopenharmony_ci 1151cabdff1aSopenharmony_cistatic VkCommandBuffer get_buf_exec_ctx(AVHWFramesContext *hwfc, VulkanExecCtx *cmd) 1152cabdff1aSopenharmony_ci{ 1153cabdff1aSopenharmony_ci return cmd->bufs[cmd->cur_queue_idx]; 1154cabdff1aSopenharmony_ci} 1155cabdff1aSopenharmony_ci 1156cabdff1aSopenharmony_cistatic void unref_exec_ctx_deps(AVHWFramesContext *hwfc, VulkanExecCtx *cmd) 1157cabdff1aSopenharmony_ci{ 1158cabdff1aSopenharmony_ci VulkanQueueCtx *q = &cmd->queues[cmd->cur_queue_idx]; 1159cabdff1aSopenharmony_ci 1160cabdff1aSopenharmony_ci for (int j = 0; j < q->nb_buf_deps; j++) 1161cabdff1aSopenharmony_ci av_buffer_unref(&q->buf_deps[j]); 1162cabdff1aSopenharmony_ci q->nb_buf_deps = 0; 1163cabdff1aSopenharmony_ci} 1164cabdff1aSopenharmony_ci 1165cabdff1aSopenharmony_cistatic int wait_start_exec_ctx(AVHWFramesContext *hwfc, VulkanExecCtx *cmd) 1166cabdff1aSopenharmony_ci{ 1167cabdff1aSopenharmony_ci VkResult ret; 1168cabdff1aSopenharmony_ci AVVulkanDeviceContext *hwctx = hwfc->device_ctx->hwctx; 1169cabdff1aSopenharmony_ci VulkanQueueCtx *q = &cmd->queues[cmd->cur_queue_idx]; 1170cabdff1aSopenharmony_ci VulkanDevicePriv *p = hwfc->device_ctx->internal->priv; 1171cabdff1aSopenharmony_ci FFVulkanFunctions *vk = &p->vkfn; 1172cabdff1aSopenharmony_ci 1173cabdff1aSopenharmony_ci VkCommandBufferBeginInfo cmd_start = { 1174cabdff1aSopenharmony_ci .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, 1175cabdff1aSopenharmony_ci .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, 1176cabdff1aSopenharmony_ci }; 1177cabdff1aSopenharmony_ci 1178cabdff1aSopenharmony_ci /* Create the fence and don't wait for it initially */ 1179cabdff1aSopenharmony_ci if (!q->fence) { 1180cabdff1aSopenharmony_ci VkFenceCreateInfo fence_spawn = { 1181cabdff1aSopenharmony_ci .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, 1182cabdff1aSopenharmony_ci }; 1183cabdff1aSopenharmony_ci ret = vk->CreateFence(hwctx->act_dev, &fence_spawn, hwctx->alloc, 1184cabdff1aSopenharmony_ci &q->fence); 1185cabdff1aSopenharmony_ci if (ret != VK_SUCCESS) { 1186cabdff1aSopenharmony_ci av_log(hwfc, AV_LOG_ERROR, "Failed to queue frame fence: %s\n", 1187cabdff1aSopenharmony_ci vk_ret2str(ret)); 1188cabdff1aSopenharmony_ci return AVERROR_EXTERNAL; 1189cabdff1aSopenharmony_ci } 1190cabdff1aSopenharmony_ci } else if (!q->was_synchronous) { 1191cabdff1aSopenharmony_ci vk->WaitForFences(hwctx->act_dev, 1, &q->fence, VK_TRUE, UINT64_MAX); 1192cabdff1aSopenharmony_ci vk->ResetFences(hwctx->act_dev, 1, &q->fence); 1193cabdff1aSopenharmony_ci } 1194cabdff1aSopenharmony_ci 1195cabdff1aSopenharmony_ci /* Discard queue dependencies */ 1196cabdff1aSopenharmony_ci unref_exec_ctx_deps(hwfc, cmd); 1197cabdff1aSopenharmony_ci 1198cabdff1aSopenharmony_ci ret = vk->BeginCommandBuffer(cmd->bufs[cmd->cur_queue_idx], &cmd_start); 1199cabdff1aSopenharmony_ci if (ret != VK_SUCCESS) { 1200cabdff1aSopenharmony_ci av_log(hwfc, AV_LOG_ERROR, "Unable to init command buffer: %s\n", 1201cabdff1aSopenharmony_ci vk_ret2str(ret)); 1202cabdff1aSopenharmony_ci return AVERROR_EXTERNAL; 1203cabdff1aSopenharmony_ci } 1204cabdff1aSopenharmony_ci 1205cabdff1aSopenharmony_ci return 0; 1206cabdff1aSopenharmony_ci} 1207cabdff1aSopenharmony_ci 1208cabdff1aSopenharmony_cistatic int add_buf_dep_exec_ctx(AVHWFramesContext *hwfc, VulkanExecCtx *cmd, 1209cabdff1aSopenharmony_ci AVBufferRef * const *deps, int nb_deps) 1210cabdff1aSopenharmony_ci{ 1211cabdff1aSopenharmony_ci AVBufferRef **dst; 1212cabdff1aSopenharmony_ci VulkanQueueCtx *q = &cmd->queues[cmd->cur_queue_idx]; 1213cabdff1aSopenharmony_ci 1214cabdff1aSopenharmony_ci if (!deps || !nb_deps) 1215cabdff1aSopenharmony_ci return 0; 1216cabdff1aSopenharmony_ci 1217cabdff1aSopenharmony_ci dst = av_fast_realloc(q->buf_deps, &q->buf_deps_alloc_size, 1218cabdff1aSopenharmony_ci (q->nb_buf_deps + nb_deps) * sizeof(*dst)); 1219cabdff1aSopenharmony_ci if (!dst) 1220cabdff1aSopenharmony_ci goto err; 1221cabdff1aSopenharmony_ci 1222cabdff1aSopenharmony_ci q->buf_deps = dst; 1223cabdff1aSopenharmony_ci 1224cabdff1aSopenharmony_ci for (int i = 0; i < nb_deps; i++) { 1225cabdff1aSopenharmony_ci q->buf_deps[q->nb_buf_deps] = av_buffer_ref(deps[i]); 1226cabdff1aSopenharmony_ci if (!q->buf_deps[q->nb_buf_deps]) 1227cabdff1aSopenharmony_ci goto err; 1228cabdff1aSopenharmony_ci q->nb_buf_deps++; 1229cabdff1aSopenharmony_ci } 1230cabdff1aSopenharmony_ci 1231cabdff1aSopenharmony_ci return 0; 1232cabdff1aSopenharmony_ci 1233cabdff1aSopenharmony_cierr: 1234cabdff1aSopenharmony_ci unref_exec_ctx_deps(hwfc, cmd); 1235cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 1236cabdff1aSopenharmony_ci} 1237cabdff1aSopenharmony_ci 1238cabdff1aSopenharmony_cistatic int submit_exec_ctx(AVHWFramesContext *hwfc, VulkanExecCtx *cmd, 1239cabdff1aSopenharmony_ci VkSubmitInfo *s_info, AVVkFrame *f, int synchronous) 1240cabdff1aSopenharmony_ci{ 1241cabdff1aSopenharmony_ci VkResult ret; 1242cabdff1aSopenharmony_ci VulkanQueueCtx *q = &cmd->queues[cmd->cur_queue_idx]; 1243cabdff1aSopenharmony_ci VulkanDevicePriv *p = hwfc->device_ctx->internal->priv; 1244cabdff1aSopenharmony_ci FFVulkanFunctions *vk = &p->vkfn; 1245cabdff1aSopenharmony_ci 1246cabdff1aSopenharmony_ci ret = vk->EndCommandBuffer(cmd->bufs[cmd->cur_queue_idx]); 1247cabdff1aSopenharmony_ci if (ret != VK_SUCCESS) { 1248cabdff1aSopenharmony_ci av_log(hwfc, AV_LOG_ERROR, "Unable to finish command buffer: %s\n", 1249cabdff1aSopenharmony_ci vk_ret2str(ret)); 1250cabdff1aSopenharmony_ci unref_exec_ctx_deps(hwfc, cmd); 1251cabdff1aSopenharmony_ci return AVERROR_EXTERNAL; 1252cabdff1aSopenharmony_ci } 1253cabdff1aSopenharmony_ci 1254cabdff1aSopenharmony_ci s_info->pCommandBuffers = &cmd->bufs[cmd->cur_queue_idx]; 1255cabdff1aSopenharmony_ci s_info->commandBufferCount = 1; 1256cabdff1aSopenharmony_ci 1257cabdff1aSopenharmony_ci ret = vk->QueueSubmit(q->queue, 1, s_info, q->fence); 1258cabdff1aSopenharmony_ci if (ret != VK_SUCCESS) { 1259cabdff1aSopenharmony_ci av_log(hwfc, AV_LOG_ERROR, "Queue submission failure: %s\n", 1260cabdff1aSopenharmony_ci vk_ret2str(ret)); 1261cabdff1aSopenharmony_ci unref_exec_ctx_deps(hwfc, cmd); 1262cabdff1aSopenharmony_ci return AVERROR_EXTERNAL; 1263cabdff1aSopenharmony_ci } 1264cabdff1aSopenharmony_ci 1265cabdff1aSopenharmony_ci if (f) 1266cabdff1aSopenharmony_ci for (int i = 0; i < s_info->signalSemaphoreCount; i++) 1267cabdff1aSopenharmony_ci f->sem_value[i]++; 1268cabdff1aSopenharmony_ci 1269cabdff1aSopenharmony_ci q->was_synchronous = synchronous; 1270cabdff1aSopenharmony_ci 1271cabdff1aSopenharmony_ci if (synchronous) { 1272cabdff1aSopenharmony_ci AVVulkanDeviceContext *hwctx = hwfc->device_ctx->hwctx; 1273cabdff1aSopenharmony_ci vk->WaitForFences(hwctx->act_dev, 1, &q->fence, VK_TRUE, UINT64_MAX); 1274cabdff1aSopenharmony_ci vk->ResetFences(hwctx->act_dev, 1, &q->fence); 1275cabdff1aSopenharmony_ci unref_exec_ctx_deps(hwfc, cmd); 1276cabdff1aSopenharmony_ci } else { /* Rotate queues */ 1277cabdff1aSopenharmony_ci cmd->cur_queue_idx = (cmd->cur_queue_idx + 1) % cmd->nb_queues; 1278cabdff1aSopenharmony_ci } 1279cabdff1aSopenharmony_ci 1280cabdff1aSopenharmony_ci return 0; 1281cabdff1aSopenharmony_ci} 1282cabdff1aSopenharmony_ci 1283cabdff1aSopenharmony_cistatic void vulkan_device_free(AVHWDeviceContext *ctx) 1284cabdff1aSopenharmony_ci{ 1285cabdff1aSopenharmony_ci VulkanDevicePriv *p = ctx->internal->priv; 1286cabdff1aSopenharmony_ci FFVulkanFunctions *vk = &p->vkfn; 1287cabdff1aSopenharmony_ci AVVulkanDeviceContext *hwctx = ctx->hwctx; 1288cabdff1aSopenharmony_ci 1289cabdff1aSopenharmony_ci if (hwctx->act_dev) 1290cabdff1aSopenharmony_ci vk->DestroyDevice(hwctx->act_dev, hwctx->alloc); 1291cabdff1aSopenharmony_ci 1292cabdff1aSopenharmony_ci if (p->debug_ctx) 1293cabdff1aSopenharmony_ci vk->DestroyDebugUtilsMessengerEXT(hwctx->inst, p->debug_ctx, 1294cabdff1aSopenharmony_ci hwctx->alloc); 1295cabdff1aSopenharmony_ci 1296cabdff1aSopenharmony_ci if (hwctx->inst) 1297cabdff1aSopenharmony_ci vk->DestroyInstance(hwctx->inst, hwctx->alloc); 1298cabdff1aSopenharmony_ci 1299cabdff1aSopenharmony_ci if (p->libvulkan) 1300cabdff1aSopenharmony_ci dlclose(p->libvulkan); 1301cabdff1aSopenharmony_ci 1302cabdff1aSopenharmony_ci RELEASE_PROPS(hwctx->enabled_inst_extensions, hwctx->nb_enabled_inst_extensions); 1303cabdff1aSopenharmony_ci RELEASE_PROPS(hwctx->enabled_dev_extensions, hwctx->nb_enabled_dev_extensions); 1304cabdff1aSopenharmony_ci} 1305cabdff1aSopenharmony_ci 1306cabdff1aSopenharmony_cistatic int vulkan_device_create_internal(AVHWDeviceContext *ctx, 1307cabdff1aSopenharmony_ci VulkanDeviceSelection *dev_select, 1308cabdff1aSopenharmony_ci AVDictionary *opts, int flags) 1309cabdff1aSopenharmony_ci{ 1310cabdff1aSopenharmony_ci int err = 0; 1311cabdff1aSopenharmony_ci VkResult ret; 1312cabdff1aSopenharmony_ci AVDictionaryEntry *opt_d; 1313cabdff1aSopenharmony_ci VulkanDevicePriv *p = ctx->internal->priv; 1314cabdff1aSopenharmony_ci FFVulkanFunctions *vk = &p->vkfn; 1315cabdff1aSopenharmony_ci AVVulkanDeviceContext *hwctx = ctx->hwctx; 1316cabdff1aSopenharmony_ci 1317cabdff1aSopenharmony_ci /* 1318cabdff1aSopenharmony_ci * VkPhysicalDeviceVulkan12Features has a timelineSemaphore field, but 1319cabdff1aSopenharmony_ci * MoltenVK doesn't implement VkPhysicalDeviceVulkan12Features yet, so we 1320cabdff1aSopenharmony_ci * use VkPhysicalDeviceTimelineSemaphoreFeatures directly. 1321cabdff1aSopenharmony_ci */ 1322cabdff1aSopenharmony_ci VkPhysicalDeviceTimelineSemaphoreFeatures timeline_features = { 1323cabdff1aSopenharmony_ci .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES, 1324cabdff1aSopenharmony_ci }; 1325cabdff1aSopenharmony_ci VkPhysicalDeviceVulkan12Features dev_features_1_2 = { 1326cabdff1aSopenharmony_ci .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES, 1327cabdff1aSopenharmony_ci .pNext = &timeline_features, 1328cabdff1aSopenharmony_ci }; 1329cabdff1aSopenharmony_ci VkPhysicalDeviceVulkan11Features dev_features_1_1 = { 1330cabdff1aSopenharmony_ci .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES, 1331cabdff1aSopenharmony_ci .pNext = &dev_features_1_2, 1332cabdff1aSopenharmony_ci }; 1333cabdff1aSopenharmony_ci VkPhysicalDeviceFeatures2 dev_features = { 1334cabdff1aSopenharmony_ci .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2, 1335cabdff1aSopenharmony_ci .pNext = &dev_features_1_1, 1336cabdff1aSopenharmony_ci }; 1337cabdff1aSopenharmony_ci 1338cabdff1aSopenharmony_ci VkDeviceCreateInfo dev_info = { 1339cabdff1aSopenharmony_ci .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, 1340cabdff1aSopenharmony_ci .pNext = &hwctx->device_features, 1341cabdff1aSopenharmony_ci }; 1342cabdff1aSopenharmony_ci 1343cabdff1aSopenharmony_ci hwctx->device_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; 1344cabdff1aSopenharmony_ci hwctx->device_features.pNext = &p->device_features_1_1; 1345cabdff1aSopenharmony_ci p->device_features_1_1.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES; 1346cabdff1aSopenharmony_ci p->device_features_1_1.pNext = &p->device_features_1_2; 1347cabdff1aSopenharmony_ci p->device_features_1_2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES; 1348cabdff1aSopenharmony_ci ctx->free = vulkan_device_free; 1349cabdff1aSopenharmony_ci 1350cabdff1aSopenharmony_ci /* Create an instance if not given one */ 1351cabdff1aSopenharmony_ci if ((err = create_instance(ctx, opts))) 1352cabdff1aSopenharmony_ci goto end; 1353cabdff1aSopenharmony_ci 1354cabdff1aSopenharmony_ci /* Find a device (if not given one) */ 1355cabdff1aSopenharmony_ci if ((err = find_device(ctx, dev_select))) 1356cabdff1aSopenharmony_ci goto end; 1357cabdff1aSopenharmony_ci 1358cabdff1aSopenharmony_ci vk->GetPhysicalDeviceFeatures2(hwctx->phys_dev, &dev_features); 1359cabdff1aSopenharmony_ci 1360cabdff1aSopenharmony_ci /* Try to keep in sync with libplacebo */ 1361cabdff1aSopenharmony_ci#define COPY_FEATURE(DST, NAME) (DST).features.NAME = dev_features.features.NAME; 1362cabdff1aSopenharmony_ci COPY_FEATURE(hwctx->device_features, shaderImageGatherExtended) 1363cabdff1aSopenharmony_ci COPY_FEATURE(hwctx->device_features, shaderStorageImageReadWithoutFormat) 1364cabdff1aSopenharmony_ci COPY_FEATURE(hwctx->device_features, shaderStorageImageWriteWithoutFormat) 1365cabdff1aSopenharmony_ci COPY_FEATURE(hwctx->device_features, fragmentStoresAndAtomics) 1366cabdff1aSopenharmony_ci COPY_FEATURE(hwctx->device_features, vertexPipelineStoresAndAtomics) 1367cabdff1aSopenharmony_ci COPY_FEATURE(hwctx->device_features, shaderInt64) 1368cabdff1aSopenharmony_ci#undef COPY_FEATURE 1369cabdff1aSopenharmony_ci 1370cabdff1aSopenharmony_ci /* We require timeline semaphores */ 1371cabdff1aSopenharmony_ci if (!timeline_features.timelineSemaphore) { 1372cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_ERROR, "Device does not support timeline semaphores!\n"); 1373cabdff1aSopenharmony_ci err = AVERROR(ENOSYS); 1374cabdff1aSopenharmony_ci goto end; 1375cabdff1aSopenharmony_ci } 1376cabdff1aSopenharmony_ci p->device_features_1_2.timelineSemaphore = 1; 1377cabdff1aSopenharmony_ci 1378cabdff1aSopenharmony_ci /* Setup queue family */ 1379cabdff1aSopenharmony_ci if ((err = setup_queue_families(ctx, &dev_info))) 1380cabdff1aSopenharmony_ci goto end; 1381cabdff1aSopenharmony_ci 1382cabdff1aSopenharmony_ci if ((err = check_extensions(ctx, 1, opts, &dev_info.ppEnabledExtensionNames, 1383cabdff1aSopenharmony_ci &dev_info.enabledExtensionCount, 0))) { 1384cabdff1aSopenharmony_ci for (int i = 0; i < dev_info.queueCreateInfoCount; i++) 1385cabdff1aSopenharmony_ci av_free((void *)dev_info.pQueueCreateInfos[i].pQueuePriorities); 1386cabdff1aSopenharmony_ci av_free((void *)dev_info.pQueueCreateInfos); 1387cabdff1aSopenharmony_ci goto end; 1388cabdff1aSopenharmony_ci } 1389cabdff1aSopenharmony_ci 1390cabdff1aSopenharmony_ci ret = vk->CreateDevice(hwctx->phys_dev, &dev_info, hwctx->alloc, 1391cabdff1aSopenharmony_ci &hwctx->act_dev); 1392cabdff1aSopenharmony_ci 1393cabdff1aSopenharmony_ci for (int i = 0; i < dev_info.queueCreateInfoCount; i++) 1394cabdff1aSopenharmony_ci av_free((void *)dev_info.pQueueCreateInfos[i].pQueuePriorities); 1395cabdff1aSopenharmony_ci av_free((void *)dev_info.pQueueCreateInfos); 1396cabdff1aSopenharmony_ci 1397cabdff1aSopenharmony_ci if (ret != VK_SUCCESS) { 1398cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_ERROR, "Device creation failure: %s\n", 1399cabdff1aSopenharmony_ci vk_ret2str(ret)); 1400cabdff1aSopenharmony_ci for (int i = 0; i < dev_info.enabledExtensionCount; i++) 1401cabdff1aSopenharmony_ci av_free((void *)dev_info.ppEnabledExtensionNames[i]); 1402cabdff1aSopenharmony_ci av_free((void *)dev_info.ppEnabledExtensionNames); 1403cabdff1aSopenharmony_ci err = AVERROR_EXTERNAL; 1404cabdff1aSopenharmony_ci goto end; 1405cabdff1aSopenharmony_ci } 1406cabdff1aSopenharmony_ci 1407cabdff1aSopenharmony_ci /* Tiled images setting, use them by default */ 1408cabdff1aSopenharmony_ci opt_d = av_dict_get(opts, "linear_images", NULL, 0); 1409cabdff1aSopenharmony_ci if (opt_d) 1410cabdff1aSopenharmony_ci p->use_linear_images = strtol(opt_d->value, NULL, 10); 1411cabdff1aSopenharmony_ci 1412cabdff1aSopenharmony_ci opt_d = av_dict_get(opts, "contiguous_planes", NULL, 0); 1413cabdff1aSopenharmony_ci if (opt_d) 1414cabdff1aSopenharmony_ci p->contiguous_planes = strtol(opt_d->value, NULL, 10); 1415cabdff1aSopenharmony_ci else 1416cabdff1aSopenharmony_ci p->contiguous_planes = -1; 1417cabdff1aSopenharmony_ci 1418cabdff1aSopenharmony_ci hwctx->enabled_dev_extensions = dev_info.ppEnabledExtensionNames; 1419cabdff1aSopenharmony_ci hwctx->nb_enabled_dev_extensions = dev_info.enabledExtensionCount; 1420cabdff1aSopenharmony_ci 1421cabdff1aSopenharmony_ciend: 1422cabdff1aSopenharmony_ci return err; 1423cabdff1aSopenharmony_ci} 1424cabdff1aSopenharmony_ci 1425cabdff1aSopenharmony_cistatic int vulkan_device_init(AVHWDeviceContext *ctx) 1426cabdff1aSopenharmony_ci{ 1427cabdff1aSopenharmony_ci int err; 1428cabdff1aSopenharmony_ci uint32_t queue_num; 1429cabdff1aSopenharmony_ci AVVulkanDeviceContext *hwctx = ctx->hwctx; 1430cabdff1aSopenharmony_ci VulkanDevicePriv *p = ctx->internal->priv; 1431cabdff1aSopenharmony_ci FFVulkanFunctions *vk = &p->vkfn; 1432cabdff1aSopenharmony_ci int graph_index, comp_index, tx_index, enc_index, dec_index; 1433cabdff1aSopenharmony_ci 1434cabdff1aSopenharmony_ci /* Set device extension flags */ 1435cabdff1aSopenharmony_ci for (int i = 0; i < hwctx->nb_enabled_dev_extensions; i++) { 1436cabdff1aSopenharmony_ci for (int j = 0; j < FF_ARRAY_ELEMS(optional_device_exts); j++) { 1437cabdff1aSopenharmony_ci if (!strcmp(hwctx->enabled_dev_extensions[i], 1438cabdff1aSopenharmony_ci optional_device_exts[j].name)) { 1439cabdff1aSopenharmony_ci p->extensions |= optional_device_exts[j].flag; 1440cabdff1aSopenharmony_ci break; 1441cabdff1aSopenharmony_ci } 1442cabdff1aSopenharmony_ci } 1443cabdff1aSopenharmony_ci } 1444cabdff1aSopenharmony_ci 1445cabdff1aSopenharmony_ci err = ff_vk_load_functions(ctx, vk, p->extensions, 1, 1); 1446cabdff1aSopenharmony_ci if (err < 0) { 1447cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_ERROR, "Unable to load functions!\n"); 1448cabdff1aSopenharmony_ci return err; 1449cabdff1aSopenharmony_ci } 1450cabdff1aSopenharmony_ci 1451cabdff1aSopenharmony_ci p->props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; 1452cabdff1aSopenharmony_ci p->props.pNext = &p->hprops; 1453cabdff1aSopenharmony_ci p->hprops.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT; 1454cabdff1aSopenharmony_ci 1455cabdff1aSopenharmony_ci vk->GetPhysicalDeviceProperties2(hwctx->phys_dev, &p->props); 1456cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_VERBOSE, "Using device: %s\n", 1457cabdff1aSopenharmony_ci p->props.properties.deviceName); 1458cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_VERBOSE, "Alignments:\n"); 1459cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_VERBOSE, " optimalBufferCopyRowPitchAlignment: %"PRIu64"\n", 1460cabdff1aSopenharmony_ci p->props.properties.limits.optimalBufferCopyRowPitchAlignment); 1461cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_VERBOSE, " minMemoryMapAlignment: %"SIZE_SPECIFIER"\n", 1462cabdff1aSopenharmony_ci p->props.properties.limits.minMemoryMapAlignment); 1463cabdff1aSopenharmony_ci if (p->extensions & FF_VK_EXT_EXTERNAL_HOST_MEMORY) 1464cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_VERBOSE, " minImportedHostPointerAlignment: %"PRIu64"\n", 1465cabdff1aSopenharmony_ci p->hprops.minImportedHostPointerAlignment); 1466cabdff1aSopenharmony_ci 1467cabdff1aSopenharmony_ci p->dev_is_nvidia = (p->props.properties.vendorID == 0x10de); 1468cabdff1aSopenharmony_ci p->dev_is_intel = (p->props.properties.vendorID == 0x8086); 1469cabdff1aSopenharmony_ci 1470cabdff1aSopenharmony_ci vk->GetPhysicalDeviceQueueFamilyProperties(hwctx->phys_dev, &queue_num, NULL); 1471cabdff1aSopenharmony_ci if (!queue_num) { 1472cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_ERROR, "Failed to get queues!\n"); 1473cabdff1aSopenharmony_ci return AVERROR_EXTERNAL; 1474cabdff1aSopenharmony_ci } 1475cabdff1aSopenharmony_ci 1476cabdff1aSopenharmony_ci graph_index = hwctx->queue_family_index; 1477cabdff1aSopenharmony_ci comp_index = hwctx->queue_family_comp_index; 1478cabdff1aSopenharmony_ci tx_index = hwctx->queue_family_tx_index; 1479cabdff1aSopenharmony_ci enc_index = hwctx->queue_family_encode_index; 1480cabdff1aSopenharmony_ci dec_index = hwctx->queue_family_decode_index; 1481cabdff1aSopenharmony_ci 1482cabdff1aSopenharmony_ci#define CHECK_QUEUE(type, required, fidx, ctx_qf, qc) \ 1483cabdff1aSopenharmony_ci do { \ 1484cabdff1aSopenharmony_ci if (ctx_qf < 0 && required) { \ 1485cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_ERROR, "%s queue family is required, but marked as missing" \ 1486cabdff1aSopenharmony_ci " in the context!\n", type); \ 1487cabdff1aSopenharmony_ci return AVERROR(EINVAL); \ 1488cabdff1aSopenharmony_ci } else if (fidx < 0 || ctx_qf < 0) { \ 1489cabdff1aSopenharmony_ci break; \ 1490cabdff1aSopenharmony_ci } else if (ctx_qf >= queue_num) { \ 1491cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_ERROR, "Invalid %s family index %i (device has %i families)!\n", \ 1492cabdff1aSopenharmony_ci type, ctx_qf, queue_num); \ 1493cabdff1aSopenharmony_ci return AVERROR(EINVAL); \ 1494cabdff1aSopenharmony_ci } \ 1495cabdff1aSopenharmony_ci \ 1496cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_VERBOSE, "Using queue family %i (queues: %i)" \ 1497cabdff1aSopenharmony_ci " for%s%s%s%s%s\n", \ 1498cabdff1aSopenharmony_ci ctx_qf, qc, \ 1499cabdff1aSopenharmony_ci ctx_qf == graph_index ? " graphics" : "", \ 1500cabdff1aSopenharmony_ci ctx_qf == comp_index ? " compute" : "", \ 1501cabdff1aSopenharmony_ci ctx_qf == tx_index ? " transfers" : "", \ 1502cabdff1aSopenharmony_ci ctx_qf == enc_index ? " encode" : "", \ 1503cabdff1aSopenharmony_ci ctx_qf == dec_index ? " decode" : ""); \ 1504cabdff1aSopenharmony_ci graph_index = (ctx_qf == graph_index) ? -1 : graph_index; \ 1505cabdff1aSopenharmony_ci comp_index = (ctx_qf == comp_index) ? -1 : comp_index; \ 1506cabdff1aSopenharmony_ci tx_index = (ctx_qf == tx_index) ? -1 : tx_index; \ 1507cabdff1aSopenharmony_ci enc_index = (ctx_qf == enc_index) ? -1 : enc_index; \ 1508cabdff1aSopenharmony_ci dec_index = (ctx_qf == dec_index) ? -1 : dec_index; \ 1509cabdff1aSopenharmony_ci p->qfs[p->num_qfs++] = ctx_qf; \ 1510cabdff1aSopenharmony_ci } while (0) 1511cabdff1aSopenharmony_ci 1512cabdff1aSopenharmony_ci CHECK_QUEUE("graphics", 0, graph_index, hwctx->queue_family_index, hwctx->nb_graphics_queues); 1513cabdff1aSopenharmony_ci CHECK_QUEUE("upload", 1, tx_index, hwctx->queue_family_tx_index, hwctx->nb_tx_queues); 1514cabdff1aSopenharmony_ci CHECK_QUEUE("compute", 1, comp_index, hwctx->queue_family_comp_index, hwctx->nb_comp_queues); 1515cabdff1aSopenharmony_ci CHECK_QUEUE("encode", 0, enc_index, hwctx->queue_family_encode_index, hwctx->nb_encode_queues); 1516cabdff1aSopenharmony_ci CHECK_QUEUE("decode", 0, dec_index, hwctx->queue_family_decode_index, hwctx->nb_decode_queues); 1517cabdff1aSopenharmony_ci 1518cabdff1aSopenharmony_ci#undef CHECK_QUEUE 1519cabdff1aSopenharmony_ci 1520cabdff1aSopenharmony_ci /* Get device capabilities */ 1521cabdff1aSopenharmony_ci vk->GetPhysicalDeviceMemoryProperties(hwctx->phys_dev, &p->mprops); 1522cabdff1aSopenharmony_ci 1523cabdff1aSopenharmony_ci return 0; 1524cabdff1aSopenharmony_ci} 1525cabdff1aSopenharmony_ci 1526cabdff1aSopenharmony_cistatic int vulkan_device_create(AVHWDeviceContext *ctx, const char *device, 1527cabdff1aSopenharmony_ci AVDictionary *opts, int flags) 1528cabdff1aSopenharmony_ci{ 1529cabdff1aSopenharmony_ci VulkanDeviceSelection dev_select = { 0 }; 1530cabdff1aSopenharmony_ci if (device && device[0]) { 1531cabdff1aSopenharmony_ci char *end = NULL; 1532cabdff1aSopenharmony_ci dev_select.index = strtol(device, &end, 10); 1533cabdff1aSopenharmony_ci if (end == device) { 1534cabdff1aSopenharmony_ci dev_select.index = 0; 1535cabdff1aSopenharmony_ci dev_select.name = device; 1536cabdff1aSopenharmony_ci } 1537cabdff1aSopenharmony_ci } 1538cabdff1aSopenharmony_ci 1539cabdff1aSopenharmony_ci return vulkan_device_create_internal(ctx, &dev_select, opts, flags); 1540cabdff1aSopenharmony_ci} 1541cabdff1aSopenharmony_ci 1542cabdff1aSopenharmony_cistatic int vulkan_device_derive(AVHWDeviceContext *ctx, 1543cabdff1aSopenharmony_ci AVHWDeviceContext *src_ctx, 1544cabdff1aSopenharmony_ci AVDictionary *opts, int flags) 1545cabdff1aSopenharmony_ci{ 1546cabdff1aSopenharmony_ci av_unused VulkanDeviceSelection dev_select = { 0 }; 1547cabdff1aSopenharmony_ci 1548cabdff1aSopenharmony_ci /* If there's only one device on the system, then even if its not covered 1549cabdff1aSopenharmony_ci * by the following checks (e.g. non-PCIe ARM GPU), having an empty 1550cabdff1aSopenharmony_ci * dev_select will mean it'll get picked. */ 1551cabdff1aSopenharmony_ci switch(src_ctx->type) { 1552cabdff1aSopenharmony_ci#if CONFIG_LIBDRM 1553cabdff1aSopenharmony_ci#if CONFIG_VAAPI 1554cabdff1aSopenharmony_ci case AV_HWDEVICE_TYPE_VAAPI: { 1555cabdff1aSopenharmony_ci AVVAAPIDeviceContext *src_hwctx = src_ctx->hwctx; 1556cabdff1aSopenharmony_ci 1557cabdff1aSopenharmony_ci const char *vendor = vaQueryVendorString(src_hwctx->display); 1558cabdff1aSopenharmony_ci if (!vendor) { 1559cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_ERROR, "Unable to get device info from VAAPI!\n"); 1560cabdff1aSopenharmony_ci return AVERROR_EXTERNAL; 1561cabdff1aSopenharmony_ci } 1562cabdff1aSopenharmony_ci 1563cabdff1aSopenharmony_ci if (strstr(vendor, "Intel")) 1564cabdff1aSopenharmony_ci dev_select.vendor_id = 0x8086; 1565cabdff1aSopenharmony_ci if (strstr(vendor, "AMD")) 1566cabdff1aSopenharmony_ci dev_select.vendor_id = 0x1002; 1567cabdff1aSopenharmony_ci 1568cabdff1aSopenharmony_ci return vulkan_device_create_internal(ctx, &dev_select, opts, flags); 1569cabdff1aSopenharmony_ci } 1570cabdff1aSopenharmony_ci#endif 1571cabdff1aSopenharmony_ci case AV_HWDEVICE_TYPE_DRM: { 1572cabdff1aSopenharmony_ci AVDRMDeviceContext *src_hwctx = src_ctx->hwctx; 1573cabdff1aSopenharmony_ci 1574cabdff1aSopenharmony_ci drmDevice *drm_dev_info; 1575cabdff1aSopenharmony_ci int err = drmGetDevice(src_hwctx->fd, &drm_dev_info); 1576cabdff1aSopenharmony_ci if (err) { 1577cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_ERROR, "Unable to get device info from DRM fd!\n"); 1578cabdff1aSopenharmony_ci return AVERROR_EXTERNAL; 1579cabdff1aSopenharmony_ci } 1580cabdff1aSopenharmony_ci 1581cabdff1aSopenharmony_ci if (drm_dev_info->bustype == DRM_BUS_PCI) 1582cabdff1aSopenharmony_ci dev_select.pci_device = drm_dev_info->deviceinfo.pci->device_id; 1583cabdff1aSopenharmony_ci 1584cabdff1aSopenharmony_ci drmFreeDevice(&drm_dev_info); 1585cabdff1aSopenharmony_ci 1586cabdff1aSopenharmony_ci return vulkan_device_create_internal(ctx, &dev_select, opts, flags); 1587cabdff1aSopenharmony_ci } 1588cabdff1aSopenharmony_ci#endif 1589cabdff1aSopenharmony_ci#if CONFIG_CUDA 1590cabdff1aSopenharmony_ci case AV_HWDEVICE_TYPE_CUDA: { 1591cabdff1aSopenharmony_ci AVHWDeviceContext *cuda_cu = src_ctx; 1592cabdff1aSopenharmony_ci AVCUDADeviceContext *src_hwctx = src_ctx->hwctx; 1593cabdff1aSopenharmony_ci AVCUDADeviceContextInternal *cu_internal = src_hwctx->internal; 1594cabdff1aSopenharmony_ci CudaFunctions *cu = cu_internal->cuda_dl; 1595cabdff1aSopenharmony_ci 1596cabdff1aSopenharmony_ci int ret = CHECK_CU(cu->cuDeviceGetUuid((CUuuid *)&dev_select.uuid, 1597cabdff1aSopenharmony_ci cu_internal->cuda_device)); 1598cabdff1aSopenharmony_ci if (ret < 0) { 1599cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_ERROR, "Unable to get UUID from CUDA!\n"); 1600cabdff1aSopenharmony_ci return AVERROR_EXTERNAL; 1601cabdff1aSopenharmony_ci } 1602cabdff1aSopenharmony_ci 1603cabdff1aSopenharmony_ci dev_select.has_uuid = 1; 1604cabdff1aSopenharmony_ci 1605cabdff1aSopenharmony_ci return vulkan_device_create_internal(ctx, &dev_select, opts, flags); 1606cabdff1aSopenharmony_ci } 1607cabdff1aSopenharmony_ci#endif 1608cabdff1aSopenharmony_ci default: 1609cabdff1aSopenharmony_ci return AVERROR(ENOSYS); 1610cabdff1aSopenharmony_ci } 1611cabdff1aSopenharmony_ci} 1612cabdff1aSopenharmony_ci 1613cabdff1aSopenharmony_cistatic int vulkan_frames_get_constraints(AVHWDeviceContext *ctx, 1614cabdff1aSopenharmony_ci const void *hwconfig, 1615cabdff1aSopenharmony_ci AVHWFramesConstraints *constraints) 1616cabdff1aSopenharmony_ci{ 1617cabdff1aSopenharmony_ci int count = 0; 1618cabdff1aSopenharmony_ci VulkanDevicePriv *p = ctx->internal->priv; 1619cabdff1aSopenharmony_ci 1620cabdff1aSopenharmony_ci for (enum AVPixelFormat i = 0; i < AV_PIX_FMT_NB; i++) 1621cabdff1aSopenharmony_ci count += pixfmt_is_supported(ctx, i, p->use_linear_images); 1622cabdff1aSopenharmony_ci 1623cabdff1aSopenharmony_ci#if CONFIG_CUDA 1624cabdff1aSopenharmony_ci if (p->dev_is_nvidia) 1625cabdff1aSopenharmony_ci count++; 1626cabdff1aSopenharmony_ci#endif 1627cabdff1aSopenharmony_ci 1628cabdff1aSopenharmony_ci constraints->valid_sw_formats = av_malloc_array(count + 1, 1629cabdff1aSopenharmony_ci sizeof(enum AVPixelFormat)); 1630cabdff1aSopenharmony_ci if (!constraints->valid_sw_formats) 1631cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 1632cabdff1aSopenharmony_ci 1633cabdff1aSopenharmony_ci count = 0; 1634cabdff1aSopenharmony_ci for (enum AVPixelFormat i = 0; i < AV_PIX_FMT_NB; i++) 1635cabdff1aSopenharmony_ci if (pixfmt_is_supported(ctx, i, p->use_linear_images)) 1636cabdff1aSopenharmony_ci constraints->valid_sw_formats[count++] = i; 1637cabdff1aSopenharmony_ci 1638cabdff1aSopenharmony_ci#if CONFIG_CUDA 1639cabdff1aSopenharmony_ci if (p->dev_is_nvidia) 1640cabdff1aSopenharmony_ci constraints->valid_sw_formats[count++] = AV_PIX_FMT_CUDA; 1641cabdff1aSopenharmony_ci#endif 1642cabdff1aSopenharmony_ci constraints->valid_sw_formats[count++] = AV_PIX_FMT_NONE; 1643cabdff1aSopenharmony_ci 1644cabdff1aSopenharmony_ci constraints->min_width = 0; 1645cabdff1aSopenharmony_ci constraints->min_height = 0; 1646cabdff1aSopenharmony_ci constraints->max_width = p->props.properties.limits.maxImageDimension2D; 1647cabdff1aSopenharmony_ci constraints->max_height = p->props.properties.limits.maxImageDimension2D; 1648cabdff1aSopenharmony_ci 1649cabdff1aSopenharmony_ci constraints->valid_hw_formats = av_malloc_array(2, sizeof(enum AVPixelFormat)); 1650cabdff1aSopenharmony_ci if (!constraints->valid_hw_formats) 1651cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 1652cabdff1aSopenharmony_ci 1653cabdff1aSopenharmony_ci constraints->valid_hw_formats[0] = AV_PIX_FMT_VULKAN; 1654cabdff1aSopenharmony_ci constraints->valid_hw_formats[1] = AV_PIX_FMT_NONE; 1655cabdff1aSopenharmony_ci 1656cabdff1aSopenharmony_ci return 0; 1657cabdff1aSopenharmony_ci} 1658cabdff1aSopenharmony_ci 1659cabdff1aSopenharmony_cistatic int alloc_mem(AVHWDeviceContext *ctx, VkMemoryRequirements *req, 1660cabdff1aSopenharmony_ci VkMemoryPropertyFlagBits req_flags, const void *alloc_extension, 1661cabdff1aSopenharmony_ci VkMemoryPropertyFlagBits *mem_flags, VkDeviceMemory *mem) 1662cabdff1aSopenharmony_ci{ 1663cabdff1aSopenharmony_ci VkResult ret; 1664cabdff1aSopenharmony_ci int index = -1; 1665cabdff1aSopenharmony_ci VulkanDevicePriv *p = ctx->internal->priv; 1666cabdff1aSopenharmony_ci FFVulkanFunctions *vk = &p->vkfn; 1667cabdff1aSopenharmony_ci AVVulkanDeviceContext *dev_hwctx = ctx->hwctx; 1668cabdff1aSopenharmony_ci VkMemoryAllocateInfo alloc_info = { 1669cabdff1aSopenharmony_ci .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, 1670cabdff1aSopenharmony_ci .pNext = alloc_extension, 1671cabdff1aSopenharmony_ci .allocationSize = req->size, 1672cabdff1aSopenharmony_ci }; 1673cabdff1aSopenharmony_ci 1674cabdff1aSopenharmony_ci /* The vulkan spec requires memory types to be sorted in the "optimal" 1675cabdff1aSopenharmony_ci * order, so the first matching type we find will be the best/fastest one */ 1676cabdff1aSopenharmony_ci for (int i = 0; i < p->mprops.memoryTypeCount; i++) { 1677cabdff1aSopenharmony_ci const VkMemoryType *type = &p->mprops.memoryTypes[i]; 1678cabdff1aSopenharmony_ci 1679cabdff1aSopenharmony_ci /* The memory type must be supported by the requirements (bitfield) */ 1680cabdff1aSopenharmony_ci if (!(req->memoryTypeBits & (1 << i))) 1681cabdff1aSopenharmony_ci continue; 1682cabdff1aSopenharmony_ci 1683cabdff1aSopenharmony_ci /* The memory type flags must include our properties */ 1684cabdff1aSopenharmony_ci if ((type->propertyFlags & req_flags) != req_flags) 1685cabdff1aSopenharmony_ci continue; 1686cabdff1aSopenharmony_ci 1687cabdff1aSopenharmony_ci /* The memory type must be large enough */ 1688cabdff1aSopenharmony_ci if (req->size > p->mprops.memoryHeaps[type->heapIndex].size) 1689cabdff1aSopenharmony_ci continue; 1690cabdff1aSopenharmony_ci 1691cabdff1aSopenharmony_ci /* Found a suitable memory type */ 1692cabdff1aSopenharmony_ci index = i; 1693cabdff1aSopenharmony_ci break; 1694cabdff1aSopenharmony_ci } 1695cabdff1aSopenharmony_ci 1696cabdff1aSopenharmony_ci if (index < 0) { 1697cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_ERROR, "No memory type found for flags 0x%x\n", 1698cabdff1aSopenharmony_ci req_flags); 1699cabdff1aSopenharmony_ci return AVERROR(EINVAL); 1700cabdff1aSopenharmony_ci } 1701cabdff1aSopenharmony_ci 1702cabdff1aSopenharmony_ci alloc_info.memoryTypeIndex = index; 1703cabdff1aSopenharmony_ci 1704cabdff1aSopenharmony_ci ret = vk->AllocateMemory(dev_hwctx->act_dev, &alloc_info, 1705cabdff1aSopenharmony_ci dev_hwctx->alloc, mem); 1706cabdff1aSopenharmony_ci if (ret != VK_SUCCESS) { 1707cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_ERROR, "Failed to allocate memory: %s\n", 1708cabdff1aSopenharmony_ci vk_ret2str(ret)); 1709cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 1710cabdff1aSopenharmony_ci } 1711cabdff1aSopenharmony_ci 1712cabdff1aSopenharmony_ci *mem_flags |= p->mprops.memoryTypes[index].propertyFlags; 1713cabdff1aSopenharmony_ci 1714cabdff1aSopenharmony_ci return 0; 1715cabdff1aSopenharmony_ci} 1716cabdff1aSopenharmony_ci 1717cabdff1aSopenharmony_cistatic void vulkan_free_internal(AVVkFrame *f) 1718cabdff1aSopenharmony_ci{ 1719cabdff1aSopenharmony_ci AVVkFrameInternal *internal = f->internal; 1720cabdff1aSopenharmony_ci 1721cabdff1aSopenharmony_ci if (!internal) 1722cabdff1aSopenharmony_ci return; 1723cabdff1aSopenharmony_ci 1724cabdff1aSopenharmony_ci#if CONFIG_CUDA 1725cabdff1aSopenharmony_ci if (internal->cuda_fc_ref) { 1726cabdff1aSopenharmony_ci AVHWFramesContext *cuda_fc = (AVHWFramesContext *)internal->cuda_fc_ref->data; 1727cabdff1aSopenharmony_ci int planes = av_pix_fmt_count_planes(cuda_fc->sw_format); 1728cabdff1aSopenharmony_ci AVHWDeviceContext *cuda_cu = cuda_fc->device_ctx; 1729cabdff1aSopenharmony_ci AVCUDADeviceContext *cuda_dev = cuda_cu->hwctx; 1730cabdff1aSopenharmony_ci AVCUDADeviceContextInternal *cu_internal = cuda_dev->internal; 1731cabdff1aSopenharmony_ci CudaFunctions *cu = cu_internal->cuda_dl; 1732cabdff1aSopenharmony_ci 1733cabdff1aSopenharmony_ci for (int i = 0; i < planes; i++) { 1734cabdff1aSopenharmony_ci if (internal->cu_sem[i]) 1735cabdff1aSopenharmony_ci CHECK_CU(cu->cuDestroyExternalSemaphore(internal->cu_sem[i])); 1736cabdff1aSopenharmony_ci if (internal->cu_mma[i]) 1737cabdff1aSopenharmony_ci CHECK_CU(cu->cuMipmappedArrayDestroy(internal->cu_mma[i])); 1738cabdff1aSopenharmony_ci if (internal->ext_mem[i]) 1739cabdff1aSopenharmony_ci CHECK_CU(cu->cuDestroyExternalMemory(internal->ext_mem[i])); 1740cabdff1aSopenharmony_ci#ifdef _WIN32 1741cabdff1aSopenharmony_ci if (internal->ext_sem_handle[i]) 1742cabdff1aSopenharmony_ci CloseHandle(internal->ext_sem_handle[i]); 1743cabdff1aSopenharmony_ci if (internal->ext_mem_handle[i]) 1744cabdff1aSopenharmony_ci CloseHandle(internal->ext_mem_handle[i]); 1745cabdff1aSopenharmony_ci#endif 1746cabdff1aSopenharmony_ci } 1747cabdff1aSopenharmony_ci 1748cabdff1aSopenharmony_ci av_buffer_unref(&internal->cuda_fc_ref); 1749cabdff1aSopenharmony_ci } 1750cabdff1aSopenharmony_ci#endif 1751cabdff1aSopenharmony_ci 1752cabdff1aSopenharmony_ci av_freep(&f->internal); 1753cabdff1aSopenharmony_ci} 1754cabdff1aSopenharmony_ci 1755cabdff1aSopenharmony_cistatic void vulkan_frame_free(void *opaque, uint8_t *data) 1756cabdff1aSopenharmony_ci{ 1757cabdff1aSopenharmony_ci AVVkFrame *f = (AVVkFrame *)data; 1758cabdff1aSopenharmony_ci AVHWFramesContext *hwfc = opaque; 1759cabdff1aSopenharmony_ci AVVulkanDeviceContext *hwctx = hwfc->device_ctx->hwctx; 1760cabdff1aSopenharmony_ci VulkanDevicePriv *p = hwfc->device_ctx->internal->priv; 1761cabdff1aSopenharmony_ci FFVulkanFunctions *vk = &p->vkfn; 1762cabdff1aSopenharmony_ci int planes = av_pix_fmt_count_planes(hwfc->sw_format); 1763cabdff1aSopenharmony_ci 1764cabdff1aSopenharmony_ci /* We could use vkWaitSemaphores, but the validation layer seems to have 1765cabdff1aSopenharmony_ci * issues tracking command buffer execution state on uninit. */ 1766cabdff1aSopenharmony_ci vk->DeviceWaitIdle(hwctx->act_dev); 1767cabdff1aSopenharmony_ci 1768cabdff1aSopenharmony_ci vulkan_free_internal(f); 1769cabdff1aSopenharmony_ci 1770cabdff1aSopenharmony_ci for (int i = 0; i < planes; i++) { 1771cabdff1aSopenharmony_ci vk->DestroyImage(hwctx->act_dev, f->img[i], hwctx->alloc); 1772cabdff1aSopenharmony_ci vk->FreeMemory(hwctx->act_dev, f->mem[i], hwctx->alloc); 1773cabdff1aSopenharmony_ci vk->DestroySemaphore(hwctx->act_dev, f->sem[i], hwctx->alloc); 1774cabdff1aSopenharmony_ci } 1775cabdff1aSopenharmony_ci 1776cabdff1aSopenharmony_ci av_free(f); 1777cabdff1aSopenharmony_ci} 1778cabdff1aSopenharmony_ci 1779cabdff1aSopenharmony_cistatic int alloc_bind_mem(AVHWFramesContext *hwfc, AVVkFrame *f, 1780cabdff1aSopenharmony_ci void *alloc_pnext, size_t alloc_pnext_stride) 1781cabdff1aSopenharmony_ci{ 1782cabdff1aSopenharmony_ci int err; 1783cabdff1aSopenharmony_ci VkResult ret; 1784cabdff1aSopenharmony_ci AVHWDeviceContext *ctx = hwfc->device_ctx; 1785cabdff1aSopenharmony_ci VulkanDevicePriv *p = ctx->internal->priv; 1786cabdff1aSopenharmony_ci FFVulkanFunctions *vk = &p->vkfn; 1787cabdff1aSopenharmony_ci AVVulkanFramesContext *hwfctx = hwfc->hwctx; 1788cabdff1aSopenharmony_ci const int planes = av_pix_fmt_count_planes(hwfc->sw_format); 1789cabdff1aSopenharmony_ci VkBindImageMemoryInfo bind_info[AV_NUM_DATA_POINTERS] = { { 0 } }; 1790cabdff1aSopenharmony_ci 1791cabdff1aSopenharmony_ci VkMemoryRequirements cont_memory_requirements = { 0 }; 1792cabdff1aSopenharmony_ci int cont_mem_size_list[AV_NUM_DATA_POINTERS] = { 0 }; 1793cabdff1aSopenharmony_ci int cont_mem_size = 0; 1794cabdff1aSopenharmony_ci 1795cabdff1aSopenharmony_ci AVVulkanDeviceContext *hwctx = ctx->hwctx; 1796cabdff1aSopenharmony_ci 1797cabdff1aSopenharmony_ci for (int i = 0; i < planes; i++) { 1798cabdff1aSopenharmony_ci int use_ded_mem; 1799cabdff1aSopenharmony_ci VkImageMemoryRequirementsInfo2 req_desc = { 1800cabdff1aSopenharmony_ci .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2, 1801cabdff1aSopenharmony_ci .image = f->img[i], 1802cabdff1aSopenharmony_ci }; 1803cabdff1aSopenharmony_ci VkMemoryDedicatedAllocateInfo ded_alloc = { 1804cabdff1aSopenharmony_ci .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO, 1805cabdff1aSopenharmony_ci .pNext = (void *)(((uint8_t *)alloc_pnext) + i*alloc_pnext_stride), 1806cabdff1aSopenharmony_ci }; 1807cabdff1aSopenharmony_ci VkMemoryDedicatedRequirements ded_req = { 1808cabdff1aSopenharmony_ci .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS, 1809cabdff1aSopenharmony_ci }; 1810cabdff1aSopenharmony_ci VkMemoryRequirements2 req = { 1811cabdff1aSopenharmony_ci .sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2, 1812cabdff1aSopenharmony_ci .pNext = &ded_req, 1813cabdff1aSopenharmony_ci }; 1814cabdff1aSopenharmony_ci 1815cabdff1aSopenharmony_ci vk->GetImageMemoryRequirements2(hwctx->act_dev, &req_desc, &req); 1816cabdff1aSopenharmony_ci 1817cabdff1aSopenharmony_ci if (f->tiling == VK_IMAGE_TILING_LINEAR) 1818cabdff1aSopenharmony_ci req.memoryRequirements.size = FFALIGN(req.memoryRequirements.size, 1819cabdff1aSopenharmony_ci p->props.properties.limits.minMemoryMapAlignment); 1820cabdff1aSopenharmony_ci 1821cabdff1aSopenharmony_ci if (hwfctx->flags & AV_VK_FRAME_FLAG_CONTIGUOUS_MEMORY) { 1822cabdff1aSopenharmony_ci if (ded_req.requiresDedicatedAllocation) { 1823cabdff1aSopenharmony_ci av_log(hwfc, AV_LOG_ERROR, "Cannot allocate all planes in a single allocation, " 1824cabdff1aSopenharmony_ci "device requires dedicated image allocation!\n"); 1825cabdff1aSopenharmony_ci return AVERROR(EINVAL); 1826cabdff1aSopenharmony_ci } else if (!i) { 1827cabdff1aSopenharmony_ci cont_memory_requirements = req.memoryRequirements; 1828cabdff1aSopenharmony_ci } else if (cont_memory_requirements.memoryTypeBits != 1829cabdff1aSopenharmony_ci req.memoryRequirements.memoryTypeBits) { 1830cabdff1aSopenharmony_ci av_log(hwfc, AV_LOG_ERROR, "The memory requirements differ between plane 0 " 1831cabdff1aSopenharmony_ci "and %i, cannot allocate in a single region!\n", 1832cabdff1aSopenharmony_ci i); 1833cabdff1aSopenharmony_ci return AVERROR(EINVAL); 1834cabdff1aSopenharmony_ci } 1835cabdff1aSopenharmony_ci 1836cabdff1aSopenharmony_ci cont_mem_size_list[i] = FFALIGN(req.memoryRequirements.size, 1837cabdff1aSopenharmony_ci req.memoryRequirements.alignment); 1838cabdff1aSopenharmony_ci cont_mem_size += cont_mem_size_list[i]; 1839cabdff1aSopenharmony_ci continue; 1840cabdff1aSopenharmony_ci } 1841cabdff1aSopenharmony_ci 1842cabdff1aSopenharmony_ci /* In case the implementation prefers/requires dedicated allocation */ 1843cabdff1aSopenharmony_ci use_ded_mem = ded_req.prefersDedicatedAllocation | 1844cabdff1aSopenharmony_ci ded_req.requiresDedicatedAllocation; 1845cabdff1aSopenharmony_ci if (use_ded_mem) 1846cabdff1aSopenharmony_ci ded_alloc.image = f->img[i]; 1847cabdff1aSopenharmony_ci 1848cabdff1aSopenharmony_ci /* Allocate memory */ 1849cabdff1aSopenharmony_ci if ((err = alloc_mem(ctx, &req.memoryRequirements, 1850cabdff1aSopenharmony_ci f->tiling == VK_IMAGE_TILING_LINEAR ? 1851cabdff1aSopenharmony_ci VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT : 1852cabdff1aSopenharmony_ci VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, 1853cabdff1aSopenharmony_ci use_ded_mem ? &ded_alloc : (void *)ded_alloc.pNext, 1854cabdff1aSopenharmony_ci &f->flags, &f->mem[i]))) 1855cabdff1aSopenharmony_ci return err; 1856cabdff1aSopenharmony_ci 1857cabdff1aSopenharmony_ci f->size[i] = req.memoryRequirements.size; 1858cabdff1aSopenharmony_ci bind_info[i].sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO; 1859cabdff1aSopenharmony_ci bind_info[i].image = f->img[i]; 1860cabdff1aSopenharmony_ci bind_info[i].memory = f->mem[i]; 1861cabdff1aSopenharmony_ci } 1862cabdff1aSopenharmony_ci 1863cabdff1aSopenharmony_ci if (hwfctx->flags & AV_VK_FRAME_FLAG_CONTIGUOUS_MEMORY) { 1864cabdff1aSopenharmony_ci cont_memory_requirements.size = cont_mem_size; 1865cabdff1aSopenharmony_ci 1866cabdff1aSopenharmony_ci /* Allocate memory */ 1867cabdff1aSopenharmony_ci if ((err = alloc_mem(ctx, &cont_memory_requirements, 1868cabdff1aSopenharmony_ci f->tiling == VK_IMAGE_TILING_LINEAR ? 1869cabdff1aSopenharmony_ci VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT : 1870cabdff1aSopenharmony_ci VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, 1871cabdff1aSopenharmony_ci (void *)(((uint8_t *)alloc_pnext)), 1872cabdff1aSopenharmony_ci &f->flags, &f->mem[0]))) 1873cabdff1aSopenharmony_ci return err; 1874cabdff1aSopenharmony_ci 1875cabdff1aSopenharmony_ci f->size[0] = cont_memory_requirements.size; 1876cabdff1aSopenharmony_ci 1877cabdff1aSopenharmony_ci for (int i = 0, offset = 0; i < planes; i++) { 1878cabdff1aSopenharmony_ci bind_info[i].sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO; 1879cabdff1aSopenharmony_ci bind_info[i].image = f->img[i]; 1880cabdff1aSopenharmony_ci bind_info[i].memory = f->mem[0]; 1881cabdff1aSopenharmony_ci bind_info[i].memoryOffset = offset; 1882cabdff1aSopenharmony_ci 1883cabdff1aSopenharmony_ci f->offset[i] = bind_info[i].memoryOffset; 1884cabdff1aSopenharmony_ci offset += cont_mem_size_list[i]; 1885cabdff1aSopenharmony_ci } 1886cabdff1aSopenharmony_ci } 1887cabdff1aSopenharmony_ci 1888cabdff1aSopenharmony_ci /* Bind the allocated memory to the images */ 1889cabdff1aSopenharmony_ci ret = vk->BindImageMemory2(hwctx->act_dev, planes, bind_info); 1890cabdff1aSopenharmony_ci if (ret != VK_SUCCESS) { 1891cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_ERROR, "Failed to bind memory: %s\n", 1892cabdff1aSopenharmony_ci vk_ret2str(ret)); 1893cabdff1aSopenharmony_ci return AVERROR_EXTERNAL; 1894cabdff1aSopenharmony_ci } 1895cabdff1aSopenharmony_ci 1896cabdff1aSopenharmony_ci return 0; 1897cabdff1aSopenharmony_ci} 1898cabdff1aSopenharmony_ci 1899cabdff1aSopenharmony_cienum PrepMode { 1900cabdff1aSopenharmony_ci PREP_MODE_WRITE, 1901cabdff1aSopenharmony_ci PREP_MODE_EXTERNAL_EXPORT, 1902cabdff1aSopenharmony_ci PREP_MODE_EXTERNAL_IMPORT 1903cabdff1aSopenharmony_ci}; 1904cabdff1aSopenharmony_ci 1905cabdff1aSopenharmony_cistatic int prepare_frame(AVHWFramesContext *hwfc, VulkanExecCtx *ectx, 1906cabdff1aSopenharmony_ci AVVkFrame *frame, enum PrepMode pmode) 1907cabdff1aSopenharmony_ci{ 1908cabdff1aSopenharmony_ci int err; 1909cabdff1aSopenharmony_ci uint32_t src_qf, dst_qf; 1910cabdff1aSopenharmony_ci VkImageLayout new_layout; 1911cabdff1aSopenharmony_ci VkAccessFlags new_access; 1912cabdff1aSopenharmony_ci const int planes = av_pix_fmt_count_planes(hwfc->sw_format); 1913cabdff1aSopenharmony_ci VulkanDevicePriv *p = hwfc->device_ctx->internal->priv; 1914cabdff1aSopenharmony_ci FFVulkanFunctions *vk = &p->vkfn; 1915cabdff1aSopenharmony_ci uint64_t sem_sig_val[AV_NUM_DATA_POINTERS]; 1916cabdff1aSopenharmony_ci 1917cabdff1aSopenharmony_ci VkImageMemoryBarrier img_bar[AV_NUM_DATA_POINTERS] = { 0 }; 1918cabdff1aSopenharmony_ci 1919cabdff1aSopenharmony_ci VkTimelineSemaphoreSubmitInfo s_timeline_sem_info = { 1920cabdff1aSopenharmony_ci .sType = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO, 1921cabdff1aSopenharmony_ci .pSignalSemaphoreValues = sem_sig_val, 1922cabdff1aSopenharmony_ci .signalSemaphoreValueCount = planes, 1923cabdff1aSopenharmony_ci }; 1924cabdff1aSopenharmony_ci 1925cabdff1aSopenharmony_ci VkSubmitInfo s_info = { 1926cabdff1aSopenharmony_ci .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, 1927cabdff1aSopenharmony_ci .pNext = &s_timeline_sem_info, 1928cabdff1aSopenharmony_ci .pSignalSemaphores = frame->sem, 1929cabdff1aSopenharmony_ci .signalSemaphoreCount = planes, 1930cabdff1aSopenharmony_ci }; 1931cabdff1aSopenharmony_ci 1932cabdff1aSopenharmony_ci VkPipelineStageFlagBits wait_st[AV_NUM_DATA_POINTERS]; 1933cabdff1aSopenharmony_ci for (int i = 0; i < planes; i++) { 1934cabdff1aSopenharmony_ci wait_st[i] = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; 1935cabdff1aSopenharmony_ci sem_sig_val[i] = frame->sem_value[i] + 1; 1936cabdff1aSopenharmony_ci } 1937cabdff1aSopenharmony_ci 1938cabdff1aSopenharmony_ci switch (pmode) { 1939cabdff1aSopenharmony_ci case PREP_MODE_WRITE: 1940cabdff1aSopenharmony_ci new_layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; 1941cabdff1aSopenharmony_ci new_access = VK_ACCESS_TRANSFER_WRITE_BIT; 1942cabdff1aSopenharmony_ci src_qf = VK_QUEUE_FAMILY_IGNORED; 1943cabdff1aSopenharmony_ci dst_qf = VK_QUEUE_FAMILY_IGNORED; 1944cabdff1aSopenharmony_ci break; 1945cabdff1aSopenharmony_ci case PREP_MODE_EXTERNAL_IMPORT: 1946cabdff1aSopenharmony_ci new_layout = VK_IMAGE_LAYOUT_GENERAL; 1947cabdff1aSopenharmony_ci new_access = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT; 1948cabdff1aSopenharmony_ci src_qf = VK_QUEUE_FAMILY_EXTERNAL_KHR; 1949cabdff1aSopenharmony_ci dst_qf = VK_QUEUE_FAMILY_IGNORED; 1950cabdff1aSopenharmony_ci s_timeline_sem_info.pWaitSemaphoreValues = frame->sem_value; 1951cabdff1aSopenharmony_ci s_timeline_sem_info.waitSemaphoreValueCount = planes; 1952cabdff1aSopenharmony_ci s_info.pWaitSemaphores = frame->sem; 1953cabdff1aSopenharmony_ci s_info.pWaitDstStageMask = wait_st; 1954cabdff1aSopenharmony_ci s_info.waitSemaphoreCount = planes; 1955cabdff1aSopenharmony_ci break; 1956cabdff1aSopenharmony_ci case PREP_MODE_EXTERNAL_EXPORT: 1957cabdff1aSopenharmony_ci new_layout = VK_IMAGE_LAYOUT_GENERAL; 1958cabdff1aSopenharmony_ci new_access = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT; 1959cabdff1aSopenharmony_ci src_qf = VK_QUEUE_FAMILY_IGNORED; 1960cabdff1aSopenharmony_ci dst_qf = VK_QUEUE_FAMILY_EXTERNAL_KHR; 1961cabdff1aSopenharmony_ci s_timeline_sem_info.pWaitSemaphoreValues = frame->sem_value; 1962cabdff1aSopenharmony_ci s_timeline_sem_info.waitSemaphoreValueCount = planes; 1963cabdff1aSopenharmony_ci s_info.pWaitSemaphores = frame->sem; 1964cabdff1aSopenharmony_ci s_info.pWaitDstStageMask = wait_st; 1965cabdff1aSopenharmony_ci s_info.waitSemaphoreCount = planes; 1966cabdff1aSopenharmony_ci break; 1967cabdff1aSopenharmony_ci } 1968cabdff1aSopenharmony_ci 1969cabdff1aSopenharmony_ci if ((err = wait_start_exec_ctx(hwfc, ectx))) 1970cabdff1aSopenharmony_ci return err; 1971cabdff1aSopenharmony_ci 1972cabdff1aSopenharmony_ci /* Change the image layout to something more optimal for writes. 1973cabdff1aSopenharmony_ci * This also signals the newly created semaphore, making it usable 1974cabdff1aSopenharmony_ci * for synchronization */ 1975cabdff1aSopenharmony_ci for (int i = 0; i < planes; i++) { 1976cabdff1aSopenharmony_ci img_bar[i].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; 1977cabdff1aSopenharmony_ci img_bar[i].srcAccessMask = 0x0; 1978cabdff1aSopenharmony_ci img_bar[i].dstAccessMask = new_access; 1979cabdff1aSopenharmony_ci img_bar[i].oldLayout = frame->layout[i]; 1980cabdff1aSopenharmony_ci img_bar[i].newLayout = new_layout; 1981cabdff1aSopenharmony_ci img_bar[i].srcQueueFamilyIndex = src_qf; 1982cabdff1aSopenharmony_ci img_bar[i].dstQueueFamilyIndex = dst_qf; 1983cabdff1aSopenharmony_ci img_bar[i].image = frame->img[i]; 1984cabdff1aSopenharmony_ci img_bar[i].subresourceRange.levelCount = 1; 1985cabdff1aSopenharmony_ci img_bar[i].subresourceRange.layerCount = 1; 1986cabdff1aSopenharmony_ci img_bar[i].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; 1987cabdff1aSopenharmony_ci 1988cabdff1aSopenharmony_ci frame->layout[i] = img_bar[i].newLayout; 1989cabdff1aSopenharmony_ci frame->access[i] = img_bar[i].dstAccessMask; 1990cabdff1aSopenharmony_ci } 1991cabdff1aSopenharmony_ci 1992cabdff1aSopenharmony_ci vk->CmdPipelineBarrier(get_buf_exec_ctx(hwfc, ectx), 1993cabdff1aSopenharmony_ci VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 1994cabdff1aSopenharmony_ci VK_PIPELINE_STAGE_TRANSFER_BIT, 1995cabdff1aSopenharmony_ci 0, 0, NULL, 0, NULL, planes, img_bar); 1996cabdff1aSopenharmony_ci 1997cabdff1aSopenharmony_ci return submit_exec_ctx(hwfc, ectx, &s_info, frame, 0); 1998cabdff1aSopenharmony_ci} 1999cabdff1aSopenharmony_ci 2000cabdff1aSopenharmony_cistatic inline void get_plane_wh(int *w, int *h, enum AVPixelFormat format, 2001cabdff1aSopenharmony_ci int frame_w, int frame_h, int plane) 2002cabdff1aSopenharmony_ci{ 2003cabdff1aSopenharmony_ci const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(format); 2004cabdff1aSopenharmony_ci 2005cabdff1aSopenharmony_ci /* Currently always true unless gray + alpha support is added */ 2006cabdff1aSopenharmony_ci if (!plane || (plane == 3) || desc->flags & AV_PIX_FMT_FLAG_RGB || 2007cabdff1aSopenharmony_ci !(desc->flags & AV_PIX_FMT_FLAG_PLANAR)) { 2008cabdff1aSopenharmony_ci *w = frame_w; 2009cabdff1aSopenharmony_ci *h = frame_h; 2010cabdff1aSopenharmony_ci return; 2011cabdff1aSopenharmony_ci } 2012cabdff1aSopenharmony_ci 2013cabdff1aSopenharmony_ci *w = AV_CEIL_RSHIFT(frame_w, desc->log2_chroma_w); 2014cabdff1aSopenharmony_ci *h = AV_CEIL_RSHIFT(frame_h, desc->log2_chroma_h); 2015cabdff1aSopenharmony_ci} 2016cabdff1aSopenharmony_ci 2017cabdff1aSopenharmony_cistatic int create_frame(AVHWFramesContext *hwfc, AVVkFrame **frame, 2018cabdff1aSopenharmony_ci VkImageTiling tiling, VkImageUsageFlagBits usage, 2019cabdff1aSopenharmony_ci void *create_pnext) 2020cabdff1aSopenharmony_ci{ 2021cabdff1aSopenharmony_ci int err; 2022cabdff1aSopenharmony_ci VkResult ret; 2023cabdff1aSopenharmony_ci AVHWDeviceContext *ctx = hwfc->device_ctx; 2024cabdff1aSopenharmony_ci VulkanDevicePriv *p = ctx->internal->priv; 2025cabdff1aSopenharmony_ci FFVulkanFunctions *vk = &p->vkfn; 2026cabdff1aSopenharmony_ci AVVulkanDeviceContext *hwctx = ctx->hwctx; 2027cabdff1aSopenharmony_ci enum AVPixelFormat format = hwfc->sw_format; 2028cabdff1aSopenharmony_ci const VkFormat *img_fmts = av_vkfmt_from_pixfmt(format); 2029cabdff1aSopenharmony_ci const int planes = av_pix_fmt_count_planes(format); 2030cabdff1aSopenharmony_ci 2031cabdff1aSopenharmony_ci VkExportSemaphoreCreateInfo ext_sem_info = { 2032cabdff1aSopenharmony_ci .sType = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO, 2033cabdff1aSopenharmony_ci#ifdef _WIN32 2034cabdff1aSopenharmony_ci .handleTypes = IsWindows8OrGreater() 2035cabdff1aSopenharmony_ci ? VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT 2036cabdff1aSopenharmony_ci : VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT, 2037cabdff1aSopenharmony_ci#else 2038cabdff1aSopenharmony_ci .handleTypes = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT, 2039cabdff1aSopenharmony_ci#endif 2040cabdff1aSopenharmony_ci }; 2041cabdff1aSopenharmony_ci 2042cabdff1aSopenharmony_ci VkSemaphoreTypeCreateInfo sem_type_info = { 2043cabdff1aSopenharmony_ci .sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO, 2044cabdff1aSopenharmony_ci#ifdef _WIN32 2045cabdff1aSopenharmony_ci .pNext = p->extensions & FF_VK_EXT_EXTERNAL_WIN32_SEM ? &ext_sem_info : NULL, 2046cabdff1aSopenharmony_ci#else 2047cabdff1aSopenharmony_ci .pNext = p->extensions & FF_VK_EXT_EXTERNAL_FD_SEM ? &ext_sem_info : NULL, 2048cabdff1aSopenharmony_ci#endif 2049cabdff1aSopenharmony_ci .semaphoreType = VK_SEMAPHORE_TYPE_TIMELINE, 2050cabdff1aSopenharmony_ci .initialValue = 0, 2051cabdff1aSopenharmony_ci }; 2052cabdff1aSopenharmony_ci 2053cabdff1aSopenharmony_ci VkSemaphoreCreateInfo sem_spawn = { 2054cabdff1aSopenharmony_ci .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, 2055cabdff1aSopenharmony_ci .pNext = &sem_type_info, 2056cabdff1aSopenharmony_ci }; 2057cabdff1aSopenharmony_ci 2058cabdff1aSopenharmony_ci AVVkFrame *f = av_vk_frame_alloc(); 2059cabdff1aSopenharmony_ci if (!f) { 2060cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_ERROR, "Unable to allocate memory for AVVkFrame!\n"); 2061cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 2062cabdff1aSopenharmony_ci } 2063cabdff1aSopenharmony_ci 2064cabdff1aSopenharmony_ci /* Create the images */ 2065cabdff1aSopenharmony_ci for (int i = 0; i < planes; i++) { 2066cabdff1aSopenharmony_ci VkImageCreateInfo create_info = { 2067cabdff1aSopenharmony_ci .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, 2068cabdff1aSopenharmony_ci .pNext = create_pnext, 2069cabdff1aSopenharmony_ci .imageType = VK_IMAGE_TYPE_2D, 2070cabdff1aSopenharmony_ci .format = img_fmts[i], 2071cabdff1aSopenharmony_ci .extent.depth = 1, 2072cabdff1aSopenharmony_ci .mipLevels = 1, 2073cabdff1aSopenharmony_ci .arrayLayers = 1, 2074cabdff1aSopenharmony_ci .flags = VK_IMAGE_CREATE_ALIAS_BIT, 2075cabdff1aSopenharmony_ci .tiling = tiling, 2076cabdff1aSopenharmony_ci .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, 2077cabdff1aSopenharmony_ci .usage = usage, 2078cabdff1aSopenharmony_ci .samples = VK_SAMPLE_COUNT_1_BIT, 2079cabdff1aSopenharmony_ci .pQueueFamilyIndices = p->qfs, 2080cabdff1aSopenharmony_ci .queueFamilyIndexCount = p->num_qfs, 2081cabdff1aSopenharmony_ci .sharingMode = p->num_qfs > 1 ? VK_SHARING_MODE_CONCURRENT : 2082cabdff1aSopenharmony_ci VK_SHARING_MODE_EXCLUSIVE, 2083cabdff1aSopenharmony_ci }; 2084cabdff1aSopenharmony_ci 2085cabdff1aSopenharmony_ci get_plane_wh(&create_info.extent.width, &create_info.extent.height, 2086cabdff1aSopenharmony_ci format, hwfc->width, hwfc->height, i); 2087cabdff1aSopenharmony_ci 2088cabdff1aSopenharmony_ci ret = vk->CreateImage(hwctx->act_dev, &create_info, 2089cabdff1aSopenharmony_ci hwctx->alloc, &f->img[i]); 2090cabdff1aSopenharmony_ci if (ret != VK_SUCCESS) { 2091cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_ERROR, "Image creation failure: %s\n", 2092cabdff1aSopenharmony_ci vk_ret2str(ret)); 2093cabdff1aSopenharmony_ci err = AVERROR(EINVAL); 2094cabdff1aSopenharmony_ci goto fail; 2095cabdff1aSopenharmony_ci } 2096cabdff1aSopenharmony_ci 2097cabdff1aSopenharmony_ci /* Create semaphore */ 2098cabdff1aSopenharmony_ci ret = vk->CreateSemaphore(hwctx->act_dev, &sem_spawn, 2099cabdff1aSopenharmony_ci hwctx->alloc, &f->sem[i]); 2100cabdff1aSopenharmony_ci if (ret != VK_SUCCESS) { 2101cabdff1aSopenharmony_ci av_log(hwctx, AV_LOG_ERROR, "Failed to create semaphore: %s\n", 2102cabdff1aSopenharmony_ci vk_ret2str(ret)); 2103cabdff1aSopenharmony_ci return AVERROR_EXTERNAL; 2104cabdff1aSopenharmony_ci } 2105cabdff1aSopenharmony_ci 2106cabdff1aSopenharmony_ci f->layout[i] = create_info.initialLayout; 2107cabdff1aSopenharmony_ci f->access[i] = 0x0; 2108cabdff1aSopenharmony_ci f->sem_value[i] = 0; 2109cabdff1aSopenharmony_ci } 2110cabdff1aSopenharmony_ci 2111cabdff1aSopenharmony_ci f->flags = 0x0; 2112cabdff1aSopenharmony_ci f->tiling = tiling; 2113cabdff1aSopenharmony_ci 2114cabdff1aSopenharmony_ci *frame = f; 2115cabdff1aSopenharmony_ci return 0; 2116cabdff1aSopenharmony_ci 2117cabdff1aSopenharmony_cifail: 2118cabdff1aSopenharmony_ci vulkan_frame_free(hwfc, (uint8_t *)f); 2119cabdff1aSopenharmony_ci return err; 2120cabdff1aSopenharmony_ci} 2121cabdff1aSopenharmony_ci 2122cabdff1aSopenharmony_ci/* Checks if an export flag is enabled, and if it is ORs it with *iexp */ 2123cabdff1aSopenharmony_cistatic void try_export_flags(AVHWFramesContext *hwfc, 2124cabdff1aSopenharmony_ci VkExternalMemoryHandleTypeFlags *comp_handle_types, 2125cabdff1aSopenharmony_ci VkExternalMemoryHandleTypeFlagBits *iexp, 2126cabdff1aSopenharmony_ci VkExternalMemoryHandleTypeFlagBits exp) 2127cabdff1aSopenharmony_ci{ 2128cabdff1aSopenharmony_ci VkResult ret; 2129cabdff1aSopenharmony_ci AVVulkanFramesContext *hwctx = hwfc->hwctx; 2130cabdff1aSopenharmony_ci AVVulkanDeviceContext *dev_hwctx = hwfc->device_ctx->hwctx; 2131cabdff1aSopenharmony_ci VulkanDevicePriv *p = hwfc->device_ctx->internal->priv; 2132cabdff1aSopenharmony_ci FFVulkanFunctions *vk = &p->vkfn; 2133cabdff1aSopenharmony_ci 2134cabdff1aSopenharmony_ci const VkImageDrmFormatModifierListCreateInfoEXT *drm_mod_info = 2135cabdff1aSopenharmony_ci vk_find_struct(hwctx->create_pnext, 2136cabdff1aSopenharmony_ci VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT); 2137cabdff1aSopenharmony_ci int has_mods = hwctx->tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT && drm_mod_info; 2138cabdff1aSopenharmony_ci int nb_mods; 2139cabdff1aSopenharmony_ci 2140cabdff1aSopenharmony_ci VkExternalImageFormatProperties eprops = { 2141cabdff1aSopenharmony_ci .sType = VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES_KHR, 2142cabdff1aSopenharmony_ci }; 2143cabdff1aSopenharmony_ci VkImageFormatProperties2 props = { 2144cabdff1aSopenharmony_ci .sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2, 2145cabdff1aSopenharmony_ci .pNext = &eprops, 2146cabdff1aSopenharmony_ci }; 2147cabdff1aSopenharmony_ci VkPhysicalDeviceImageDrmFormatModifierInfoEXT phy_dev_mod_info = { 2148cabdff1aSopenharmony_ci .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT, 2149cabdff1aSopenharmony_ci .pNext = NULL, 2150cabdff1aSopenharmony_ci .pQueueFamilyIndices = p->qfs, 2151cabdff1aSopenharmony_ci .queueFamilyIndexCount = p->num_qfs, 2152cabdff1aSopenharmony_ci .sharingMode = p->num_qfs > 1 ? VK_SHARING_MODE_CONCURRENT : 2153cabdff1aSopenharmony_ci VK_SHARING_MODE_EXCLUSIVE, 2154cabdff1aSopenharmony_ci }; 2155cabdff1aSopenharmony_ci VkPhysicalDeviceExternalImageFormatInfo enext = { 2156cabdff1aSopenharmony_ci .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO, 2157cabdff1aSopenharmony_ci .handleType = exp, 2158cabdff1aSopenharmony_ci .pNext = has_mods ? &phy_dev_mod_info : NULL, 2159cabdff1aSopenharmony_ci }; 2160cabdff1aSopenharmony_ci VkPhysicalDeviceImageFormatInfo2 pinfo = { 2161cabdff1aSopenharmony_ci .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2, 2162cabdff1aSopenharmony_ci .pNext = !exp ? NULL : &enext, 2163cabdff1aSopenharmony_ci .format = av_vkfmt_from_pixfmt(hwfc->sw_format)[0], 2164cabdff1aSopenharmony_ci .type = VK_IMAGE_TYPE_2D, 2165cabdff1aSopenharmony_ci .tiling = hwctx->tiling, 2166cabdff1aSopenharmony_ci .usage = hwctx->usage, 2167cabdff1aSopenharmony_ci .flags = VK_IMAGE_CREATE_ALIAS_BIT, 2168cabdff1aSopenharmony_ci }; 2169cabdff1aSopenharmony_ci 2170cabdff1aSopenharmony_ci nb_mods = has_mods ? drm_mod_info->drmFormatModifierCount : 1; 2171cabdff1aSopenharmony_ci for (int i = 0; i < nb_mods; i++) { 2172cabdff1aSopenharmony_ci if (has_mods) 2173cabdff1aSopenharmony_ci phy_dev_mod_info.drmFormatModifier = drm_mod_info->pDrmFormatModifiers[i]; 2174cabdff1aSopenharmony_ci 2175cabdff1aSopenharmony_ci ret = vk->GetPhysicalDeviceImageFormatProperties2(dev_hwctx->phys_dev, 2176cabdff1aSopenharmony_ci &pinfo, &props); 2177cabdff1aSopenharmony_ci 2178cabdff1aSopenharmony_ci if (ret == VK_SUCCESS) { 2179cabdff1aSopenharmony_ci *iexp |= exp; 2180cabdff1aSopenharmony_ci *comp_handle_types |= eprops.externalMemoryProperties.compatibleHandleTypes; 2181cabdff1aSopenharmony_ci } 2182cabdff1aSopenharmony_ci } 2183cabdff1aSopenharmony_ci} 2184cabdff1aSopenharmony_ci 2185cabdff1aSopenharmony_cistatic AVBufferRef *vulkan_pool_alloc(void *opaque, size_t size) 2186cabdff1aSopenharmony_ci{ 2187cabdff1aSopenharmony_ci int err; 2188cabdff1aSopenharmony_ci AVVkFrame *f; 2189cabdff1aSopenharmony_ci AVBufferRef *avbuf = NULL; 2190cabdff1aSopenharmony_ci AVHWFramesContext *hwfc = opaque; 2191cabdff1aSopenharmony_ci AVVulkanFramesContext *hwctx = hwfc->hwctx; 2192cabdff1aSopenharmony_ci VulkanDevicePriv *p = hwfc->device_ctx->internal->priv; 2193cabdff1aSopenharmony_ci VulkanFramesPriv *fp = hwfc->internal->priv; 2194cabdff1aSopenharmony_ci VkExportMemoryAllocateInfo eminfo[AV_NUM_DATA_POINTERS]; 2195cabdff1aSopenharmony_ci VkExternalMemoryHandleTypeFlags e = 0x0; 2196cabdff1aSopenharmony_ci 2197cabdff1aSopenharmony_ci VkExternalMemoryImageCreateInfo eiinfo = { 2198cabdff1aSopenharmony_ci .sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO, 2199cabdff1aSopenharmony_ci .pNext = hwctx->create_pnext, 2200cabdff1aSopenharmony_ci }; 2201cabdff1aSopenharmony_ci 2202cabdff1aSopenharmony_ci#ifdef _WIN32 2203cabdff1aSopenharmony_ci if (p->extensions & FF_VK_EXT_EXTERNAL_WIN32_MEMORY) 2204cabdff1aSopenharmony_ci try_export_flags(hwfc, &eiinfo.handleTypes, &e, IsWindows8OrGreater() 2205cabdff1aSopenharmony_ci ? VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT 2206cabdff1aSopenharmony_ci : VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT); 2207cabdff1aSopenharmony_ci#else 2208cabdff1aSopenharmony_ci if (p->extensions & FF_VK_EXT_EXTERNAL_FD_MEMORY) 2209cabdff1aSopenharmony_ci try_export_flags(hwfc, &eiinfo.handleTypes, &e, 2210cabdff1aSopenharmony_ci VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT); 2211cabdff1aSopenharmony_ci 2212cabdff1aSopenharmony_ci if (p->extensions & (FF_VK_EXT_EXTERNAL_DMABUF_MEMORY | FF_VK_EXT_DRM_MODIFIER_FLAGS)) 2213cabdff1aSopenharmony_ci try_export_flags(hwfc, &eiinfo.handleTypes, &e, 2214cabdff1aSopenharmony_ci VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT); 2215cabdff1aSopenharmony_ci#endif 2216cabdff1aSopenharmony_ci 2217cabdff1aSopenharmony_ci for (int i = 0; i < av_pix_fmt_count_planes(hwfc->sw_format); i++) { 2218cabdff1aSopenharmony_ci eminfo[i].sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO; 2219cabdff1aSopenharmony_ci eminfo[i].pNext = hwctx->alloc_pnext[i]; 2220cabdff1aSopenharmony_ci eminfo[i].handleTypes = e; 2221cabdff1aSopenharmony_ci } 2222cabdff1aSopenharmony_ci 2223cabdff1aSopenharmony_ci err = create_frame(hwfc, &f, hwctx->tiling, hwctx->usage, 2224cabdff1aSopenharmony_ci eiinfo.handleTypes ? &eiinfo : NULL); 2225cabdff1aSopenharmony_ci if (err) 2226cabdff1aSopenharmony_ci return NULL; 2227cabdff1aSopenharmony_ci 2228cabdff1aSopenharmony_ci err = alloc_bind_mem(hwfc, f, eminfo, sizeof(*eminfo)); 2229cabdff1aSopenharmony_ci if (err) 2230cabdff1aSopenharmony_ci goto fail; 2231cabdff1aSopenharmony_ci 2232cabdff1aSopenharmony_ci err = prepare_frame(hwfc, &fp->conv_ctx, f, PREP_MODE_WRITE); 2233cabdff1aSopenharmony_ci if (err) 2234cabdff1aSopenharmony_ci goto fail; 2235cabdff1aSopenharmony_ci 2236cabdff1aSopenharmony_ci avbuf = av_buffer_create((uint8_t *)f, sizeof(AVVkFrame), 2237cabdff1aSopenharmony_ci vulkan_frame_free, hwfc, 0); 2238cabdff1aSopenharmony_ci if (!avbuf) 2239cabdff1aSopenharmony_ci goto fail; 2240cabdff1aSopenharmony_ci 2241cabdff1aSopenharmony_ci return avbuf; 2242cabdff1aSopenharmony_ci 2243cabdff1aSopenharmony_cifail: 2244cabdff1aSopenharmony_ci vulkan_frame_free(hwfc, (uint8_t *)f); 2245cabdff1aSopenharmony_ci return NULL; 2246cabdff1aSopenharmony_ci} 2247cabdff1aSopenharmony_ci 2248cabdff1aSopenharmony_cistatic void vulkan_frames_uninit(AVHWFramesContext *hwfc) 2249cabdff1aSopenharmony_ci{ 2250cabdff1aSopenharmony_ci VulkanFramesPriv *fp = hwfc->internal->priv; 2251cabdff1aSopenharmony_ci 2252cabdff1aSopenharmony_ci if (fp->modifier_info) { 2253cabdff1aSopenharmony_ci if (fp->modifier_info->pDrmFormatModifiers) 2254cabdff1aSopenharmony_ci av_freep(&fp->modifier_info->pDrmFormatModifiers); 2255cabdff1aSopenharmony_ci av_freep(&fp->modifier_info); 2256cabdff1aSopenharmony_ci } 2257cabdff1aSopenharmony_ci 2258cabdff1aSopenharmony_ci free_exec_ctx(hwfc, &fp->conv_ctx); 2259cabdff1aSopenharmony_ci free_exec_ctx(hwfc, &fp->upload_ctx); 2260cabdff1aSopenharmony_ci free_exec_ctx(hwfc, &fp->download_ctx); 2261cabdff1aSopenharmony_ci} 2262cabdff1aSopenharmony_ci 2263cabdff1aSopenharmony_cistatic int vulkan_frames_init(AVHWFramesContext *hwfc) 2264cabdff1aSopenharmony_ci{ 2265cabdff1aSopenharmony_ci int err; 2266cabdff1aSopenharmony_ci AVVkFrame *f; 2267cabdff1aSopenharmony_ci AVVulkanFramesContext *hwctx = hwfc->hwctx; 2268cabdff1aSopenharmony_ci VulkanFramesPriv *fp = hwfc->internal->priv; 2269cabdff1aSopenharmony_ci AVVulkanDeviceContext *dev_hwctx = hwfc->device_ctx->hwctx; 2270cabdff1aSopenharmony_ci VulkanDevicePriv *p = hwfc->device_ctx->internal->priv; 2271cabdff1aSopenharmony_ci const VkImageDrmFormatModifierListCreateInfoEXT *modifier_info; 2272cabdff1aSopenharmony_ci const int has_modifiers = !!(p->extensions & FF_VK_EXT_DRM_MODIFIER_FLAGS); 2273cabdff1aSopenharmony_ci 2274cabdff1aSopenharmony_ci /* Default tiling flags */ 2275cabdff1aSopenharmony_ci hwctx->tiling = hwctx->tiling ? hwctx->tiling : 2276cabdff1aSopenharmony_ci has_modifiers ? VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT : 2277cabdff1aSopenharmony_ci p->use_linear_images ? VK_IMAGE_TILING_LINEAR : 2278cabdff1aSopenharmony_ci VK_IMAGE_TILING_OPTIMAL; 2279cabdff1aSopenharmony_ci 2280cabdff1aSopenharmony_ci if (!hwctx->usage) 2281cabdff1aSopenharmony_ci hwctx->usage = FF_VK_DEFAULT_USAGE_FLAGS; 2282cabdff1aSopenharmony_ci 2283cabdff1aSopenharmony_ci if (!(hwctx->flags & AV_VK_FRAME_FLAG_NONE)) { 2284cabdff1aSopenharmony_ci if (p->contiguous_planes == 1 || 2285cabdff1aSopenharmony_ci ((p->contiguous_planes == -1) && p->dev_is_intel)) 2286cabdff1aSopenharmony_ci hwctx->flags |= AV_VK_FRAME_FLAG_CONTIGUOUS_MEMORY; 2287cabdff1aSopenharmony_ci } 2288cabdff1aSopenharmony_ci 2289cabdff1aSopenharmony_ci modifier_info = vk_find_struct(hwctx->create_pnext, 2290cabdff1aSopenharmony_ci VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT); 2291cabdff1aSopenharmony_ci 2292cabdff1aSopenharmony_ci /* Get the supported modifiers if the user has not given any. */ 2293cabdff1aSopenharmony_ci if (has_modifiers && !modifier_info) { 2294cabdff1aSopenharmony_ci const VkFormat *fmt = av_vkfmt_from_pixfmt(hwfc->sw_format); 2295cabdff1aSopenharmony_ci VkImageDrmFormatModifierListCreateInfoEXT *modifier_info; 2296cabdff1aSopenharmony_ci FFVulkanFunctions *vk = &p->vkfn; 2297cabdff1aSopenharmony_ci VkDrmFormatModifierPropertiesEXT *mod_props; 2298cabdff1aSopenharmony_ci uint64_t *modifiers; 2299cabdff1aSopenharmony_ci int modifier_count = 0; 2300cabdff1aSopenharmony_ci 2301cabdff1aSopenharmony_ci VkDrmFormatModifierPropertiesListEXT mod_props_list = { 2302cabdff1aSopenharmony_ci .sType = VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT, 2303cabdff1aSopenharmony_ci .pNext = NULL, 2304cabdff1aSopenharmony_ci .drmFormatModifierCount = 0, 2305cabdff1aSopenharmony_ci .pDrmFormatModifierProperties = NULL, 2306cabdff1aSopenharmony_ci }; 2307cabdff1aSopenharmony_ci VkFormatProperties2 prop = { 2308cabdff1aSopenharmony_ci .sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2, 2309cabdff1aSopenharmony_ci .pNext = &mod_props_list, 2310cabdff1aSopenharmony_ci }; 2311cabdff1aSopenharmony_ci 2312cabdff1aSopenharmony_ci /* Get all supported modifiers */ 2313cabdff1aSopenharmony_ci vk->GetPhysicalDeviceFormatProperties2(dev_hwctx->phys_dev, fmt[0], &prop); 2314cabdff1aSopenharmony_ci 2315cabdff1aSopenharmony_ci if (!mod_props_list.drmFormatModifierCount) { 2316cabdff1aSopenharmony_ci av_log(hwfc, AV_LOG_ERROR, "There are no supported modifiers for the given sw_format\n"); 2317cabdff1aSopenharmony_ci return AVERROR(EINVAL); 2318cabdff1aSopenharmony_ci } 2319cabdff1aSopenharmony_ci 2320cabdff1aSopenharmony_ci /* Createa structure to hold the modifier list info */ 2321cabdff1aSopenharmony_ci modifier_info = av_mallocz(sizeof(*modifier_info)); 2322cabdff1aSopenharmony_ci if (!modifier_info) 2323cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 2324cabdff1aSopenharmony_ci 2325cabdff1aSopenharmony_ci modifier_info->pNext = NULL; 2326cabdff1aSopenharmony_ci modifier_info->sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT; 2327cabdff1aSopenharmony_ci 2328cabdff1aSopenharmony_ci /* Add structure to the image creation pNext chain */ 2329cabdff1aSopenharmony_ci if (!hwctx->create_pnext) 2330cabdff1aSopenharmony_ci hwctx->create_pnext = modifier_info; 2331cabdff1aSopenharmony_ci else 2332cabdff1aSopenharmony_ci vk_link_struct(hwctx->create_pnext, (void *)modifier_info); 2333cabdff1aSopenharmony_ci 2334cabdff1aSopenharmony_ci /* Backup the allocated struct to be freed later */ 2335cabdff1aSopenharmony_ci fp->modifier_info = modifier_info; 2336cabdff1aSopenharmony_ci 2337cabdff1aSopenharmony_ci /* Allocate list of modifiers */ 2338cabdff1aSopenharmony_ci modifiers = av_mallocz(mod_props_list.drmFormatModifierCount * 2339cabdff1aSopenharmony_ci sizeof(*modifiers)); 2340cabdff1aSopenharmony_ci if (!modifiers) 2341cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 2342cabdff1aSopenharmony_ci 2343cabdff1aSopenharmony_ci modifier_info->pDrmFormatModifiers = modifiers; 2344cabdff1aSopenharmony_ci 2345cabdff1aSopenharmony_ci /* Allocate a temporary list to hold all modifiers supported */ 2346cabdff1aSopenharmony_ci mod_props = av_mallocz(mod_props_list.drmFormatModifierCount * 2347cabdff1aSopenharmony_ci sizeof(*mod_props)); 2348cabdff1aSopenharmony_ci if (!mod_props) 2349cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 2350cabdff1aSopenharmony_ci 2351cabdff1aSopenharmony_ci mod_props_list.pDrmFormatModifierProperties = mod_props; 2352cabdff1aSopenharmony_ci 2353cabdff1aSopenharmony_ci /* Finally get all modifiers from the device */ 2354cabdff1aSopenharmony_ci vk->GetPhysicalDeviceFormatProperties2(dev_hwctx->phys_dev, fmt[0], &prop); 2355cabdff1aSopenharmony_ci 2356cabdff1aSopenharmony_ci /* Reject any modifiers that don't match our requirements */ 2357cabdff1aSopenharmony_ci for (int i = 0; i < mod_props_list.drmFormatModifierCount; i++) { 2358cabdff1aSopenharmony_ci if (!(mod_props[i].drmFormatModifierTilingFeatures & hwctx->usage)) 2359cabdff1aSopenharmony_ci continue; 2360cabdff1aSopenharmony_ci 2361cabdff1aSopenharmony_ci modifiers[modifier_count++] = mod_props[i].drmFormatModifier; 2362cabdff1aSopenharmony_ci } 2363cabdff1aSopenharmony_ci 2364cabdff1aSopenharmony_ci if (!modifier_count) { 2365cabdff1aSopenharmony_ci av_log(hwfc, AV_LOG_ERROR, "None of the given modifiers supports" 2366cabdff1aSopenharmony_ci " the usage flags!\n"); 2367cabdff1aSopenharmony_ci av_freep(&mod_props); 2368cabdff1aSopenharmony_ci return AVERROR(EINVAL); 2369cabdff1aSopenharmony_ci } 2370cabdff1aSopenharmony_ci 2371cabdff1aSopenharmony_ci modifier_info->drmFormatModifierCount = modifier_count; 2372cabdff1aSopenharmony_ci av_freep(&mod_props); 2373cabdff1aSopenharmony_ci } 2374cabdff1aSopenharmony_ci 2375cabdff1aSopenharmony_ci err = create_exec_ctx(hwfc, &fp->conv_ctx, 2376cabdff1aSopenharmony_ci dev_hwctx->queue_family_comp_index, 2377cabdff1aSopenharmony_ci dev_hwctx->nb_comp_queues); 2378cabdff1aSopenharmony_ci if (err) 2379cabdff1aSopenharmony_ci return err; 2380cabdff1aSopenharmony_ci 2381cabdff1aSopenharmony_ci err = create_exec_ctx(hwfc, &fp->upload_ctx, 2382cabdff1aSopenharmony_ci dev_hwctx->queue_family_tx_index, 2383cabdff1aSopenharmony_ci dev_hwctx->nb_tx_queues); 2384cabdff1aSopenharmony_ci if (err) 2385cabdff1aSopenharmony_ci return err; 2386cabdff1aSopenharmony_ci 2387cabdff1aSopenharmony_ci err = create_exec_ctx(hwfc, &fp->download_ctx, 2388cabdff1aSopenharmony_ci dev_hwctx->queue_family_tx_index, 1); 2389cabdff1aSopenharmony_ci if (err) 2390cabdff1aSopenharmony_ci return err; 2391cabdff1aSopenharmony_ci 2392cabdff1aSopenharmony_ci /* Test to see if allocation will fail */ 2393cabdff1aSopenharmony_ci err = create_frame(hwfc, &f, hwctx->tiling, hwctx->usage, 2394cabdff1aSopenharmony_ci hwctx->create_pnext); 2395cabdff1aSopenharmony_ci if (err) 2396cabdff1aSopenharmony_ci return err; 2397cabdff1aSopenharmony_ci 2398cabdff1aSopenharmony_ci vulkan_frame_free(hwfc, (uint8_t *)f); 2399cabdff1aSopenharmony_ci 2400cabdff1aSopenharmony_ci /* If user did not specify a pool, hwfc->pool will be set to the internal one 2401cabdff1aSopenharmony_ci * in hwcontext.c just after this gets called */ 2402cabdff1aSopenharmony_ci if (!hwfc->pool) { 2403cabdff1aSopenharmony_ci hwfc->internal->pool_internal = av_buffer_pool_init2(sizeof(AVVkFrame), 2404cabdff1aSopenharmony_ci hwfc, vulkan_pool_alloc, 2405cabdff1aSopenharmony_ci NULL); 2406cabdff1aSopenharmony_ci if (!hwfc->internal->pool_internal) 2407cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 2408cabdff1aSopenharmony_ci } 2409cabdff1aSopenharmony_ci 2410cabdff1aSopenharmony_ci return 0; 2411cabdff1aSopenharmony_ci} 2412cabdff1aSopenharmony_ci 2413cabdff1aSopenharmony_cistatic int vulkan_get_buffer(AVHWFramesContext *hwfc, AVFrame *frame) 2414cabdff1aSopenharmony_ci{ 2415cabdff1aSopenharmony_ci frame->buf[0] = av_buffer_pool_get(hwfc->pool); 2416cabdff1aSopenharmony_ci if (!frame->buf[0]) 2417cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 2418cabdff1aSopenharmony_ci 2419cabdff1aSopenharmony_ci frame->data[0] = frame->buf[0]->data; 2420cabdff1aSopenharmony_ci frame->format = AV_PIX_FMT_VULKAN; 2421cabdff1aSopenharmony_ci frame->width = hwfc->width; 2422cabdff1aSopenharmony_ci frame->height = hwfc->height; 2423cabdff1aSopenharmony_ci 2424cabdff1aSopenharmony_ci return 0; 2425cabdff1aSopenharmony_ci} 2426cabdff1aSopenharmony_ci 2427cabdff1aSopenharmony_cistatic int vulkan_transfer_get_formats(AVHWFramesContext *hwfc, 2428cabdff1aSopenharmony_ci enum AVHWFrameTransferDirection dir, 2429cabdff1aSopenharmony_ci enum AVPixelFormat **formats) 2430cabdff1aSopenharmony_ci{ 2431cabdff1aSopenharmony_ci enum AVPixelFormat *fmts = av_malloc_array(2, sizeof(*fmts)); 2432cabdff1aSopenharmony_ci if (!fmts) 2433cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 2434cabdff1aSopenharmony_ci 2435cabdff1aSopenharmony_ci fmts[0] = hwfc->sw_format; 2436cabdff1aSopenharmony_ci fmts[1] = AV_PIX_FMT_NONE; 2437cabdff1aSopenharmony_ci 2438cabdff1aSopenharmony_ci *formats = fmts; 2439cabdff1aSopenharmony_ci return 0; 2440cabdff1aSopenharmony_ci} 2441cabdff1aSopenharmony_ci 2442cabdff1aSopenharmony_citypedef struct VulkanMapping { 2443cabdff1aSopenharmony_ci AVVkFrame *frame; 2444cabdff1aSopenharmony_ci int flags; 2445cabdff1aSopenharmony_ci} VulkanMapping; 2446cabdff1aSopenharmony_ci 2447cabdff1aSopenharmony_cistatic void vulkan_unmap_frame(AVHWFramesContext *hwfc, HWMapDescriptor *hwmap) 2448cabdff1aSopenharmony_ci{ 2449cabdff1aSopenharmony_ci VulkanMapping *map = hwmap->priv; 2450cabdff1aSopenharmony_ci AVVulkanDeviceContext *hwctx = hwfc->device_ctx->hwctx; 2451cabdff1aSopenharmony_ci const int planes = av_pix_fmt_count_planes(hwfc->sw_format); 2452cabdff1aSopenharmony_ci VulkanDevicePriv *p = hwfc->device_ctx->internal->priv; 2453cabdff1aSopenharmony_ci FFVulkanFunctions *vk = &p->vkfn; 2454cabdff1aSopenharmony_ci 2455cabdff1aSopenharmony_ci /* Check if buffer needs flushing */ 2456cabdff1aSopenharmony_ci if ((map->flags & AV_HWFRAME_MAP_WRITE) && 2457cabdff1aSopenharmony_ci !(map->frame->flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) { 2458cabdff1aSopenharmony_ci VkResult ret; 2459cabdff1aSopenharmony_ci VkMappedMemoryRange flush_ranges[AV_NUM_DATA_POINTERS] = { { 0 } }; 2460cabdff1aSopenharmony_ci 2461cabdff1aSopenharmony_ci for (int i = 0; i < planes; i++) { 2462cabdff1aSopenharmony_ci flush_ranges[i].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; 2463cabdff1aSopenharmony_ci flush_ranges[i].memory = map->frame->mem[i]; 2464cabdff1aSopenharmony_ci flush_ranges[i].size = VK_WHOLE_SIZE; 2465cabdff1aSopenharmony_ci } 2466cabdff1aSopenharmony_ci 2467cabdff1aSopenharmony_ci ret = vk->FlushMappedMemoryRanges(hwctx->act_dev, planes, 2468cabdff1aSopenharmony_ci flush_ranges); 2469cabdff1aSopenharmony_ci if (ret != VK_SUCCESS) { 2470cabdff1aSopenharmony_ci av_log(hwfc, AV_LOG_ERROR, "Failed to flush memory: %s\n", 2471cabdff1aSopenharmony_ci vk_ret2str(ret)); 2472cabdff1aSopenharmony_ci } 2473cabdff1aSopenharmony_ci } 2474cabdff1aSopenharmony_ci 2475cabdff1aSopenharmony_ci for (int i = 0; i < planes; i++) 2476cabdff1aSopenharmony_ci vk->UnmapMemory(hwctx->act_dev, map->frame->mem[i]); 2477cabdff1aSopenharmony_ci 2478cabdff1aSopenharmony_ci av_free(map); 2479cabdff1aSopenharmony_ci} 2480cabdff1aSopenharmony_ci 2481cabdff1aSopenharmony_cistatic int vulkan_map_frame_to_mem(AVHWFramesContext *hwfc, AVFrame *dst, 2482cabdff1aSopenharmony_ci const AVFrame *src, int flags) 2483cabdff1aSopenharmony_ci{ 2484cabdff1aSopenharmony_ci VkResult ret; 2485cabdff1aSopenharmony_ci int err, mapped_mem_count = 0, mem_planes = 0; 2486cabdff1aSopenharmony_ci AVVkFrame *f = (AVVkFrame *)src->data[0]; 2487cabdff1aSopenharmony_ci AVVulkanDeviceContext *hwctx = hwfc->device_ctx->hwctx; 2488cabdff1aSopenharmony_ci AVVulkanFramesContext *hwfctx = hwfc->hwctx; 2489cabdff1aSopenharmony_ci const int planes = av_pix_fmt_count_planes(hwfc->sw_format); 2490cabdff1aSopenharmony_ci VulkanDevicePriv *p = hwfc->device_ctx->internal->priv; 2491cabdff1aSopenharmony_ci FFVulkanFunctions *vk = &p->vkfn; 2492cabdff1aSopenharmony_ci 2493cabdff1aSopenharmony_ci VulkanMapping *map = av_mallocz(sizeof(VulkanMapping)); 2494cabdff1aSopenharmony_ci if (!map) 2495cabdff1aSopenharmony_ci return AVERROR(EINVAL); 2496cabdff1aSopenharmony_ci 2497cabdff1aSopenharmony_ci if (src->format != AV_PIX_FMT_VULKAN) { 2498cabdff1aSopenharmony_ci av_log(hwfc, AV_LOG_ERROR, "Cannot map from pixel format %s!\n", 2499cabdff1aSopenharmony_ci av_get_pix_fmt_name(src->format)); 2500cabdff1aSopenharmony_ci err = AVERROR(EINVAL); 2501cabdff1aSopenharmony_ci goto fail; 2502cabdff1aSopenharmony_ci } 2503cabdff1aSopenharmony_ci 2504cabdff1aSopenharmony_ci if (!(f->flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) || 2505cabdff1aSopenharmony_ci !(f->tiling == VK_IMAGE_TILING_LINEAR)) { 2506cabdff1aSopenharmony_ci av_log(hwfc, AV_LOG_ERROR, "Unable to map frame, not host visible " 2507cabdff1aSopenharmony_ci "and linear!\n"); 2508cabdff1aSopenharmony_ci err = AVERROR(EINVAL); 2509cabdff1aSopenharmony_ci goto fail; 2510cabdff1aSopenharmony_ci } 2511cabdff1aSopenharmony_ci 2512cabdff1aSopenharmony_ci dst->width = src->width; 2513cabdff1aSopenharmony_ci dst->height = src->height; 2514cabdff1aSopenharmony_ci 2515cabdff1aSopenharmony_ci mem_planes = hwfctx->flags & AV_VK_FRAME_FLAG_CONTIGUOUS_MEMORY ? 1 : planes; 2516cabdff1aSopenharmony_ci for (int i = 0; i < mem_planes; i++) { 2517cabdff1aSopenharmony_ci ret = vk->MapMemory(hwctx->act_dev, f->mem[i], 0, 2518cabdff1aSopenharmony_ci VK_WHOLE_SIZE, 0, (void **)&dst->data[i]); 2519cabdff1aSopenharmony_ci if (ret != VK_SUCCESS) { 2520cabdff1aSopenharmony_ci av_log(hwfc, AV_LOG_ERROR, "Failed to map image memory: %s\n", 2521cabdff1aSopenharmony_ci vk_ret2str(ret)); 2522cabdff1aSopenharmony_ci err = AVERROR_EXTERNAL; 2523cabdff1aSopenharmony_ci goto fail; 2524cabdff1aSopenharmony_ci } 2525cabdff1aSopenharmony_ci mapped_mem_count++; 2526cabdff1aSopenharmony_ci } 2527cabdff1aSopenharmony_ci 2528cabdff1aSopenharmony_ci if (hwfctx->flags & AV_VK_FRAME_FLAG_CONTIGUOUS_MEMORY) { 2529cabdff1aSopenharmony_ci for (int i = 0; i < planes; i++) 2530cabdff1aSopenharmony_ci dst->data[i] = dst->data[0] + f->offset[i]; 2531cabdff1aSopenharmony_ci } 2532cabdff1aSopenharmony_ci 2533cabdff1aSopenharmony_ci /* Check if the memory contents matter */ 2534cabdff1aSopenharmony_ci if (((flags & AV_HWFRAME_MAP_READ) || !(flags & AV_HWFRAME_MAP_OVERWRITE)) && 2535cabdff1aSopenharmony_ci !(f->flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) { 2536cabdff1aSopenharmony_ci VkMappedMemoryRange map_mem_ranges[AV_NUM_DATA_POINTERS] = { { 0 } }; 2537cabdff1aSopenharmony_ci for (int i = 0; i < planes; i++) { 2538cabdff1aSopenharmony_ci map_mem_ranges[i].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; 2539cabdff1aSopenharmony_ci map_mem_ranges[i].size = VK_WHOLE_SIZE; 2540cabdff1aSopenharmony_ci map_mem_ranges[i].memory = f->mem[i]; 2541cabdff1aSopenharmony_ci } 2542cabdff1aSopenharmony_ci 2543cabdff1aSopenharmony_ci ret = vk->InvalidateMappedMemoryRanges(hwctx->act_dev, planes, 2544cabdff1aSopenharmony_ci map_mem_ranges); 2545cabdff1aSopenharmony_ci if (ret != VK_SUCCESS) { 2546cabdff1aSopenharmony_ci av_log(hwfc, AV_LOG_ERROR, "Failed to invalidate memory: %s\n", 2547cabdff1aSopenharmony_ci vk_ret2str(ret)); 2548cabdff1aSopenharmony_ci err = AVERROR_EXTERNAL; 2549cabdff1aSopenharmony_ci goto fail; 2550cabdff1aSopenharmony_ci } 2551cabdff1aSopenharmony_ci } 2552cabdff1aSopenharmony_ci 2553cabdff1aSopenharmony_ci for (int i = 0; i < planes; i++) { 2554cabdff1aSopenharmony_ci VkImageSubresource sub = { 2555cabdff1aSopenharmony_ci .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, 2556cabdff1aSopenharmony_ci }; 2557cabdff1aSopenharmony_ci VkSubresourceLayout layout; 2558cabdff1aSopenharmony_ci vk->GetImageSubresourceLayout(hwctx->act_dev, f->img[i], &sub, &layout); 2559cabdff1aSopenharmony_ci dst->linesize[i] = layout.rowPitch; 2560cabdff1aSopenharmony_ci } 2561cabdff1aSopenharmony_ci 2562cabdff1aSopenharmony_ci map->frame = f; 2563cabdff1aSopenharmony_ci map->flags = flags; 2564cabdff1aSopenharmony_ci 2565cabdff1aSopenharmony_ci err = ff_hwframe_map_create(src->hw_frames_ctx, dst, src, 2566cabdff1aSopenharmony_ci &vulkan_unmap_frame, map); 2567cabdff1aSopenharmony_ci if (err < 0) 2568cabdff1aSopenharmony_ci goto fail; 2569cabdff1aSopenharmony_ci 2570cabdff1aSopenharmony_ci return 0; 2571cabdff1aSopenharmony_ci 2572cabdff1aSopenharmony_cifail: 2573cabdff1aSopenharmony_ci for (int i = 0; i < mapped_mem_count; i++) 2574cabdff1aSopenharmony_ci vk->UnmapMemory(hwctx->act_dev, f->mem[i]); 2575cabdff1aSopenharmony_ci 2576cabdff1aSopenharmony_ci av_free(map); 2577cabdff1aSopenharmony_ci return err; 2578cabdff1aSopenharmony_ci} 2579cabdff1aSopenharmony_ci 2580cabdff1aSopenharmony_ci#if CONFIG_LIBDRM 2581cabdff1aSopenharmony_cistatic void vulkan_unmap_from_drm(AVHWFramesContext *hwfc, HWMapDescriptor *hwmap) 2582cabdff1aSopenharmony_ci{ 2583cabdff1aSopenharmony_ci AVVkFrame *f = hwmap->priv; 2584cabdff1aSopenharmony_ci AVVulkanDeviceContext *hwctx = hwfc->device_ctx->hwctx; 2585cabdff1aSopenharmony_ci const int planes = av_pix_fmt_count_planes(hwfc->sw_format); 2586cabdff1aSopenharmony_ci VulkanDevicePriv *p = hwfc->device_ctx->internal->priv; 2587cabdff1aSopenharmony_ci FFVulkanFunctions *vk = &p->vkfn; 2588cabdff1aSopenharmony_ci 2589cabdff1aSopenharmony_ci VkSemaphoreWaitInfo wait_info = { 2590cabdff1aSopenharmony_ci .sType = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO, 2591cabdff1aSopenharmony_ci .flags = 0x0, 2592cabdff1aSopenharmony_ci .pSemaphores = f->sem, 2593cabdff1aSopenharmony_ci .pValues = f->sem_value, 2594cabdff1aSopenharmony_ci .semaphoreCount = planes, 2595cabdff1aSopenharmony_ci }; 2596cabdff1aSopenharmony_ci 2597cabdff1aSopenharmony_ci vk->WaitSemaphores(hwctx->act_dev, &wait_info, UINT64_MAX); 2598cabdff1aSopenharmony_ci 2599cabdff1aSopenharmony_ci vulkan_free_internal(f); 2600cabdff1aSopenharmony_ci 2601cabdff1aSopenharmony_ci for (int i = 0; i < planes; i++) { 2602cabdff1aSopenharmony_ci vk->DestroyImage(hwctx->act_dev, f->img[i], hwctx->alloc); 2603cabdff1aSopenharmony_ci vk->FreeMemory(hwctx->act_dev, f->mem[i], hwctx->alloc); 2604cabdff1aSopenharmony_ci vk->DestroySemaphore(hwctx->act_dev, f->sem[i], hwctx->alloc); 2605cabdff1aSopenharmony_ci } 2606cabdff1aSopenharmony_ci 2607cabdff1aSopenharmony_ci av_free(f); 2608cabdff1aSopenharmony_ci} 2609cabdff1aSopenharmony_ci 2610cabdff1aSopenharmony_cistatic const struct { 2611cabdff1aSopenharmony_ci uint32_t drm_fourcc; 2612cabdff1aSopenharmony_ci VkFormat vk_format; 2613cabdff1aSopenharmony_ci} vulkan_drm_format_map[] = { 2614cabdff1aSopenharmony_ci { DRM_FORMAT_R8, VK_FORMAT_R8_UNORM }, 2615cabdff1aSopenharmony_ci { DRM_FORMAT_R16, VK_FORMAT_R16_UNORM }, 2616cabdff1aSopenharmony_ci { DRM_FORMAT_GR88, VK_FORMAT_R8G8_UNORM }, 2617cabdff1aSopenharmony_ci { DRM_FORMAT_RG88, VK_FORMAT_R8G8_UNORM }, 2618cabdff1aSopenharmony_ci { DRM_FORMAT_GR1616, VK_FORMAT_R16G16_UNORM }, 2619cabdff1aSopenharmony_ci { DRM_FORMAT_RG1616, VK_FORMAT_R16G16_UNORM }, 2620cabdff1aSopenharmony_ci { DRM_FORMAT_ARGB8888, VK_FORMAT_B8G8R8A8_UNORM }, 2621cabdff1aSopenharmony_ci { DRM_FORMAT_XRGB8888, VK_FORMAT_B8G8R8A8_UNORM }, 2622cabdff1aSopenharmony_ci { DRM_FORMAT_ABGR8888, VK_FORMAT_R8G8B8A8_UNORM }, 2623cabdff1aSopenharmony_ci { DRM_FORMAT_XBGR8888, VK_FORMAT_R8G8B8A8_UNORM }, 2624cabdff1aSopenharmony_ci}; 2625cabdff1aSopenharmony_ci 2626cabdff1aSopenharmony_cistatic inline VkFormat drm_to_vulkan_fmt(uint32_t drm_fourcc) 2627cabdff1aSopenharmony_ci{ 2628cabdff1aSopenharmony_ci for (int i = 0; i < FF_ARRAY_ELEMS(vulkan_drm_format_map); i++) 2629cabdff1aSopenharmony_ci if (vulkan_drm_format_map[i].drm_fourcc == drm_fourcc) 2630cabdff1aSopenharmony_ci return vulkan_drm_format_map[i].vk_format; 2631cabdff1aSopenharmony_ci return VK_FORMAT_UNDEFINED; 2632cabdff1aSopenharmony_ci} 2633cabdff1aSopenharmony_ci 2634cabdff1aSopenharmony_cistatic int vulkan_map_from_drm_frame_desc(AVHWFramesContext *hwfc, AVVkFrame **frame, 2635cabdff1aSopenharmony_ci const AVFrame *src) 2636cabdff1aSopenharmony_ci{ 2637cabdff1aSopenharmony_ci int err = 0; 2638cabdff1aSopenharmony_ci VkResult ret; 2639cabdff1aSopenharmony_ci AVVkFrame *f; 2640cabdff1aSopenharmony_ci int bind_counts = 0; 2641cabdff1aSopenharmony_ci AVHWDeviceContext *ctx = hwfc->device_ctx; 2642cabdff1aSopenharmony_ci AVVulkanDeviceContext *hwctx = ctx->hwctx; 2643cabdff1aSopenharmony_ci VulkanDevicePriv *p = ctx->internal->priv; 2644cabdff1aSopenharmony_ci FFVulkanFunctions *vk = &p->vkfn; 2645cabdff1aSopenharmony_ci VulkanFramesPriv *fp = hwfc->internal->priv; 2646cabdff1aSopenharmony_ci const AVDRMFrameDescriptor *desc = (AVDRMFrameDescriptor *)src->data[0]; 2647cabdff1aSopenharmony_ci VkBindImageMemoryInfo bind_info[AV_DRM_MAX_PLANES]; 2648cabdff1aSopenharmony_ci VkBindImagePlaneMemoryInfo plane_info[AV_DRM_MAX_PLANES]; 2649cabdff1aSopenharmony_ci 2650cabdff1aSopenharmony_ci for (int i = 0; i < desc->nb_layers; i++) { 2651cabdff1aSopenharmony_ci if (drm_to_vulkan_fmt(desc->layers[i].format) == VK_FORMAT_UNDEFINED) { 2652cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_ERROR, "Unsupported DMABUF layer format %#08x!\n", 2653cabdff1aSopenharmony_ci desc->layers[i].format); 2654cabdff1aSopenharmony_ci return AVERROR(EINVAL); 2655cabdff1aSopenharmony_ci } 2656cabdff1aSopenharmony_ci } 2657cabdff1aSopenharmony_ci 2658cabdff1aSopenharmony_ci if (!(f = av_vk_frame_alloc())) { 2659cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_ERROR, "Unable to allocate memory for AVVkFrame!\n"); 2660cabdff1aSopenharmony_ci err = AVERROR(ENOMEM); 2661cabdff1aSopenharmony_ci goto fail; 2662cabdff1aSopenharmony_ci } 2663cabdff1aSopenharmony_ci 2664cabdff1aSopenharmony_ci f->tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT; 2665cabdff1aSopenharmony_ci 2666cabdff1aSopenharmony_ci for (int i = 0; i < desc->nb_layers; i++) { 2667cabdff1aSopenharmony_ci const int planes = desc->layers[i].nb_planes; 2668cabdff1aSopenharmony_ci 2669cabdff1aSopenharmony_ci /* Semaphore */ 2670cabdff1aSopenharmony_ci VkSemaphoreTypeCreateInfo sem_type_info = { 2671cabdff1aSopenharmony_ci .sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO, 2672cabdff1aSopenharmony_ci .semaphoreType = VK_SEMAPHORE_TYPE_TIMELINE, 2673cabdff1aSopenharmony_ci .initialValue = 0, 2674cabdff1aSopenharmony_ci }; 2675cabdff1aSopenharmony_ci VkSemaphoreCreateInfo sem_spawn = { 2676cabdff1aSopenharmony_ci .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, 2677cabdff1aSopenharmony_ci .pNext = &sem_type_info, 2678cabdff1aSopenharmony_ci }; 2679cabdff1aSopenharmony_ci 2680cabdff1aSopenharmony_ci /* Image creation */ 2681cabdff1aSopenharmony_ci VkSubresourceLayout ext_img_layouts[AV_DRM_MAX_PLANES]; 2682cabdff1aSopenharmony_ci VkImageDrmFormatModifierExplicitCreateInfoEXT ext_img_mod_spec = { 2683cabdff1aSopenharmony_ci .sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT, 2684cabdff1aSopenharmony_ci .drmFormatModifier = desc->objects[0].format_modifier, 2685cabdff1aSopenharmony_ci .drmFormatModifierPlaneCount = planes, 2686cabdff1aSopenharmony_ci .pPlaneLayouts = (const VkSubresourceLayout *)&ext_img_layouts, 2687cabdff1aSopenharmony_ci }; 2688cabdff1aSopenharmony_ci VkExternalMemoryImageCreateInfo ext_img_spec = { 2689cabdff1aSopenharmony_ci .sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO, 2690cabdff1aSopenharmony_ci .pNext = &ext_img_mod_spec, 2691cabdff1aSopenharmony_ci .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT, 2692cabdff1aSopenharmony_ci }; 2693cabdff1aSopenharmony_ci VkImageCreateInfo create_info = { 2694cabdff1aSopenharmony_ci .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, 2695cabdff1aSopenharmony_ci .pNext = &ext_img_spec, 2696cabdff1aSopenharmony_ci .imageType = VK_IMAGE_TYPE_2D, 2697cabdff1aSopenharmony_ci .format = drm_to_vulkan_fmt(desc->layers[i].format), 2698cabdff1aSopenharmony_ci .extent.depth = 1, 2699cabdff1aSopenharmony_ci .mipLevels = 1, 2700cabdff1aSopenharmony_ci .arrayLayers = 1, 2701cabdff1aSopenharmony_ci .flags = 0x0, /* ALIAS flag is implicit for imported images */ 2702cabdff1aSopenharmony_ci .tiling = f->tiling, 2703cabdff1aSopenharmony_ci .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, /* specs say so */ 2704cabdff1aSopenharmony_ci .usage = VK_IMAGE_USAGE_SAMPLED_BIT | 2705cabdff1aSopenharmony_ci VK_IMAGE_USAGE_TRANSFER_SRC_BIT, 2706cabdff1aSopenharmony_ci .samples = VK_SAMPLE_COUNT_1_BIT, 2707cabdff1aSopenharmony_ci .pQueueFamilyIndices = p->qfs, 2708cabdff1aSopenharmony_ci .queueFamilyIndexCount = p->num_qfs, 2709cabdff1aSopenharmony_ci .sharingMode = p->num_qfs > 1 ? VK_SHARING_MODE_CONCURRENT : 2710cabdff1aSopenharmony_ci VK_SHARING_MODE_EXCLUSIVE, 2711cabdff1aSopenharmony_ci }; 2712cabdff1aSopenharmony_ci 2713cabdff1aSopenharmony_ci /* Image format verification */ 2714cabdff1aSopenharmony_ci VkExternalImageFormatProperties ext_props = { 2715cabdff1aSopenharmony_ci .sType = VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES_KHR, 2716cabdff1aSopenharmony_ci }; 2717cabdff1aSopenharmony_ci VkImageFormatProperties2 props_ret = { 2718cabdff1aSopenharmony_ci .sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2, 2719cabdff1aSopenharmony_ci .pNext = &ext_props, 2720cabdff1aSopenharmony_ci }; 2721cabdff1aSopenharmony_ci VkPhysicalDeviceImageDrmFormatModifierInfoEXT props_drm_mod = { 2722cabdff1aSopenharmony_ci .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT, 2723cabdff1aSopenharmony_ci .drmFormatModifier = ext_img_mod_spec.drmFormatModifier, 2724cabdff1aSopenharmony_ci .pQueueFamilyIndices = create_info.pQueueFamilyIndices, 2725cabdff1aSopenharmony_ci .queueFamilyIndexCount = create_info.queueFamilyIndexCount, 2726cabdff1aSopenharmony_ci .sharingMode = create_info.sharingMode, 2727cabdff1aSopenharmony_ci }; 2728cabdff1aSopenharmony_ci VkPhysicalDeviceExternalImageFormatInfo props_ext = { 2729cabdff1aSopenharmony_ci .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO, 2730cabdff1aSopenharmony_ci .pNext = &props_drm_mod, 2731cabdff1aSopenharmony_ci .handleType = ext_img_spec.handleTypes, 2732cabdff1aSopenharmony_ci }; 2733cabdff1aSopenharmony_ci VkPhysicalDeviceImageFormatInfo2 fmt_props = { 2734cabdff1aSopenharmony_ci .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2, 2735cabdff1aSopenharmony_ci .pNext = &props_ext, 2736cabdff1aSopenharmony_ci .format = create_info.format, 2737cabdff1aSopenharmony_ci .type = create_info.imageType, 2738cabdff1aSopenharmony_ci .tiling = create_info.tiling, 2739cabdff1aSopenharmony_ci .usage = create_info.usage, 2740cabdff1aSopenharmony_ci .flags = create_info.flags, 2741cabdff1aSopenharmony_ci }; 2742cabdff1aSopenharmony_ci 2743cabdff1aSopenharmony_ci /* Check if importing is possible for this combination of parameters */ 2744cabdff1aSopenharmony_ci ret = vk->GetPhysicalDeviceImageFormatProperties2(hwctx->phys_dev, 2745cabdff1aSopenharmony_ci &fmt_props, &props_ret); 2746cabdff1aSopenharmony_ci if (ret != VK_SUCCESS) { 2747cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_ERROR, "Cannot map DRM frame to Vulkan: %s\n", 2748cabdff1aSopenharmony_ci vk_ret2str(ret)); 2749cabdff1aSopenharmony_ci err = AVERROR_EXTERNAL; 2750cabdff1aSopenharmony_ci goto fail; 2751cabdff1aSopenharmony_ci } 2752cabdff1aSopenharmony_ci 2753cabdff1aSopenharmony_ci /* Set the image width/height */ 2754cabdff1aSopenharmony_ci get_plane_wh(&create_info.extent.width, &create_info.extent.height, 2755cabdff1aSopenharmony_ci hwfc->sw_format, src->width, src->height, i); 2756cabdff1aSopenharmony_ci 2757cabdff1aSopenharmony_ci /* Set the subresource layout based on the layer properties */ 2758cabdff1aSopenharmony_ci for (int j = 0; j < planes; j++) { 2759cabdff1aSopenharmony_ci ext_img_layouts[j].offset = desc->layers[i].planes[j].offset; 2760cabdff1aSopenharmony_ci ext_img_layouts[j].rowPitch = desc->layers[i].planes[j].pitch; 2761cabdff1aSopenharmony_ci ext_img_layouts[j].size = 0; /* The specs say so for all 3 */ 2762cabdff1aSopenharmony_ci ext_img_layouts[j].arrayPitch = 0; 2763cabdff1aSopenharmony_ci ext_img_layouts[j].depthPitch = 0; 2764cabdff1aSopenharmony_ci } 2765cabdff1aSopenharmony_ci 2766cabdff1aSopenharmony_ci /* Create image */ 2767cabdff1aSopenharmony_ci ret = vk->CreateImage(hwctx->act_dev, &create_info, 2768cabdff1aSopenharmony_ci hwctx->alloc, &f->img[i]); 2769cabdff1aSopenharmony_ci if (ret != VK_SUCCESS) { 2770cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_ERROR, "Image creation failure: %s\n", 2771cabdff1aSopenharmony_ci vk_ret2str(ret)); 2772cabdff1aSopenharmony_ci err = AVERROR(EINVAL); 2773cabdff1aSopenharmony_ci goto fail; 2774cabdff1aSopenharmony_ci } 2775cabdff1aSopenharmony_ci 2776cabdff1aSopenharmony_ci ret = vk->CreateSemaphore(hwctx->act_dev, &sem_spawn, 2777cabdff1aSopenharmony_ci hwctx->alloc, &f->sem[i]); 2778cabdff1aSopenharmony_ci if (ret != VK_SUCCESS) { 2779cabdff1aSopenharmony_ci av_log(hwctx, AV_LOG_ERROR, "Failed to create semaphore: %s\n", 2780cabdff1aSopenharmony_ci vk_ret2str(ret)); 2781cabdff1aSopenharmony_ci return AVERROR_EXTERNAL; 2782cabdff1aSopenharmony_ci } 2783cabdff1aSopenharmony_ci 2784cabdff1aSopenharmony_ci /* We'd import a semaphore onto the one we created using 2785cabdff1aSopenharmony_ci * vkImportSemaphoreFdKHR but unfortunately neither DRM nor VAAPI 2786cabdff1aSopenharmony_ci * offer us anything we could import and sync with, so instead 2787cabdff1aSopenharmony_ci * just signal the semaphore we created. */ 2788cabdff1aSopenharmony_ci 2789cabdff1aSopenharmony_ci f->layout[i] = create_info.initialLayout; 2790cabdff1aSopenharmony_ci f->access[i] = 0x0; 2791cabdff1aSopenharmony_ci f->sem_value[i] = 0; 2792cabdff1aSopenharmony_ci } 2793cabdff1aSopenharmony_ci 2794cabdff1aSopenharmony_ci for (int i = 0; i < desc->nb_objects; i++) { 2795cabdff1aSopenharmony_ci /* Memory requirements */ 2796cabdff1aSopenharmony_ci VkImageMemoryRequirementsInfo2 req_desc = { 2797cabdff1aSopenharmony_ci .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2, 2798cabdff1aSopenharmony_ci .image = f->img[i], 2799cabdff1aSopenharmony_ci }; 2800cabdff1aSopenharmony_ci VkMemoryDedicatedRequirements ded_req = { 2801cabdff1aSopenharmony_ci .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS, 2802cabdff1aSopenharmony_ci }; 2803cabdff1aSopenharmony_ci VkMemoryRequirements2 req2 = { 2804cabdff1aSopenharmony_ci .sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2, 2805cabdff1aSopenharmony_ci .pNext = &ded_req, 2806cabdff1aSopenharmony_ci }; 2807cabdff1aSopenharmony_ci 2808cabdff1aSopenharmony_ci /* Allocation/importing */ 2809cabdff1aSopenharmony_ci VkMemoryFdPropertiesKHR fdmp = { 2810cabdff1aSopenharmony_ci .sType = VK_STRUCTURE_TYPE_MEMORY_FD_PROPERTIES_KHR, 2811cabdff1aSopenharmony_ci }; 2812cabdff1aSopenharmony_ci VkImportMemoryFdInfoKHR idesc = { 2813cabdff1aSopenharmony_ci .sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR, 2814cabdff1aSopenharmony_ci .fd = dup(desc->objects[i].fd), 2815cabdff1aSopenharmony_ci .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT, 2816cabdff1aSopenharmony_ci }; 2817cabdff1aSopenharmony_ci VkMemoryDedicatedAllocateInfo ded_alloc = { 2818cabdff1aSopenharmony_ci .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO, 2819cabdff1aSopenharmony_ci .pNext = &idesc, 2820cabdff1aSopenharmony_ci .image = req_desc.image, 2821cabdff1aSopenharmony_ci }; 2822cabdff1aSopenharmony_ci 2823cabdff1aSopenharmony_ci /* Get object properties */ 2824cabdff1aSopenharmony_ci ret = vk->GetMemoryFdPropertiesKHR(hwctx->act_dev, 2825cabdff1aSopenharmony_ci VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT, 2826cabdff1aSopenharmony_ci idesc.fd, &fdmp); 2827cabdff1aSopenharmony_ci if (ret != VK_SUCCESS) { 2828cabdff1aSopenharmony_ci av_log(hwfc, AV_LOG_ERROR, "Failed to get FD properties: %s\n", 2829cabdff1aSopenharmony_ci vk_ret2str(ret)); 2830cabdff1aSopenharmony_ci err = AVERROR_EXTERNAL; 2831cabdff1aSopenharmony_ci close(idesc.fd); 2832cabdff1aSopenharmony_ci goto fail; 2833cabdff1aSopenharmony_ci } 2834cabdff1aSopenharmony_ci 2835cabdff1aSopenharmony_ci vk->GetImageMemoryRequirements2(hwctx->act_dev, &req_desc, &req2); 2836cabdff1aSopenharmony_ci 2837cabdff1aSopenharmony_ci /* Only a single bit must be set, not a range, and it must match */ 2838cabdff1aSopenharmony_ci req2.memoryRequirements.memoryTypeBits = fdmp.memoryTypeBits; 2839cabdff1aSopenharmony_ci 2840cabdff1aSopenharmony_ci err = alloc_mem(ctx, &req2.memoryRequirements, 2841cabdff1aSopenharmony_ci VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, 2842cabdff1aSopenharmony_ci (ded_req.prefersDedicatedAllocation || 2843cabdff1aSopenharmony_ci ded_req.requiresDedicatedAllocation) ? 2844cabdff1aSopenharmony_ci &ded_alloc : ded_alloc.pNext, 2845cabdff1aSopenharmony_ci &f->flags, &f->mem[i]); 2846cabdff1aSopenharmony_ci if (err) { 2847cabdff1aSopenharmony_ci close(idesc.fd); 2848cabdff1aSopenharmony_ci return err; 2849cabdff1aSopenharmony_ci } 2850cabdff1aSopenharmony_ci 2851cabdff1aSopenharmony_ci f->size[i] = req2.memoryRequirements.size; 2852cabdff1aSopenharmony_ci } 2853cabdff1aSopenharmony_ci 2854cabdff1aSopenharmony_ci for (int i = 0; i < desc->nb_layers; i++) { 2855cabdff1aSopenharmony_ci const int planes = desc->layers[i].nb_planes; 2856cabdff1aSopenharmony_ci for (int j = 0; j < planes; j++) { 2857cabdff1aSopenharmony_ci VkImageAspectFlagBits aspect = j == 0 ? VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT : 2858cabdff1aSopenharmony_ci j == 1 ? VK_IMAGE_ASPECT_MEMORY_PLANE_1_BIT_EXT : 2859cabdff1aSopenharmony_ci VK_IMAGE_ASPECT_MEMORY_PLANE_2_BIT_EXT; 2860cabdff1aSopenharmony_ci 2861cabdff1aSopenharmony_ci plane_info[bind_counts].sType = VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO; 2862cabdff1aSopenharmony_ci plane_info[bind_counts].pNext = NULL; 2863cabdff1aSopenharmony_ci plane_info[bind_counts].planeAspect = aspect; 2864cabdff1aSopenharmony_ci 2865cabdff1aSopenharmony_ci bind_info[bind_counts].sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO; 2866cabdff1aSopenharmony_ci bind_info[bind_counts].pNext = planes > 1 ? &plane_info[bind_counts] : NULL; 2867cabdff1aSopenharmony_ci bind_info[bind_counts].image = f->img[i]; 2868cabdff1aSopenharmony_ci bind_info[bind_counts].memory = f->mem[desc->layers[i].planes[j].object_index]; 2869cabdff1aSopenharmony_ci 2870cabdff1aSopenharmony_ci /* Offset is already signalled via pPlaneLayouts above */ 2871cabdff1aSopenharmony_ci bind_info[bind_counts].memoryOffset = 0; 2872cabdff1aSopenharmony_ci 2873cabdff1aSopenharmony_ci bind_counts++; 2874cabdff1aSopenharmony_ci } 2875cabdff1aSopenharmony_ci } 2876cabdff1aSopenharmony_ci 2877cabdff1aSopenharmony_ci /* Bind the allocated memory to the images */ 2878cabdff1aSopenharmony_ci ret = vk->BindImageMemory2(hwctx->act_dev, bind_counts, bind_info); 2879cabdff1aSopenharmony_ci if (ret != VK_SUCCESS) { 2880cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_ERROR, "Failed to bind memory: %s\n", 2881cabdff1aSopenharmony_ci vk_ret2str(ret)); 2882cabdff1aSopenharmony_ci err = AVERROR_EXTERNAL; 2883cabdff1aSopenharmony_ci goto fail; 2884cabdff1aSopenharmony_ci } 2885cabdff1aSopenharmony_ci 2886cabdff1aSopenharmony_ci err = prepare_frame(hwfc, &fp->conv_ctx, f, PREP_MODE_EXTERNAL_IMPORT); 2887cabdff1aSopenharmony_ci if (err) 2888cabdff1aSopenharmony_ci goto fail; 2889cabdff1aSopenharmony_ci 2890cabdff1aSopenharmony_ci *frame = f; 2891cabdff1aSopenharmony_ci 2892cabdff1aSopenharmony_ci return 0; 2893cabdff1aSopenharmony_ci 2894cabdff1aSopenharmony_cifail: 2895cabdff1aSopenharmony_ci for (int i = 0; i < desc->nb_layers; i++) { 2896cabdff1aSopenharmony_ci vk->DestroyImage(hwctx->act_dev, f->img[i], hwctx->alloc); 2897cabdff1aSopenharmony_ci vk->DestroySemaphore(hwctx->act_dev, f->sem[i], hwctx->alloc); 2898cabdff1aSopenharmony_ci } 2899cabdff1aSopenharmony_ci for (int i = 0; i < desc->nb_objects; i++) 2900cabdff1aSopenharmony_ci vk->FreeMemory(hwctx->act_dev, f->mem[i], hwctx->alloc); 2901cabdff1aSopenharmony_ci 2902cabdff1aSopenharmony_ci av_free(f); 2903cabdff1aSopenharmony_ci 2904cabdff1aSopenharmony_ci return err; 2905cabdff1aSopenharmony_ci} 2906cabdff1aSopenharmony_ci 2907cabdff1aSopenharmony_cistatic int vulkan_map_from_drm(AVHWFramesContext *hwfc, AVFrame *dst, 2908cabdff1aSopenharmony_ci const AVFrame *src, int flags) 2909cabdff1aSopenharmony_ci{ 2910cabdff1aSopenharmony_ci int err = 0; 2911cabdff1aSopenharmony_ci AVVkFrame *f; 2912cabdff1aSopenharmony_ci 2913cabdff1aSopenharmony_ci if ((err = vulkan_map_from_drm_frame_desc(hwfc, &f, src))) 2914cabdff1aSopenharmony_ci return err; 2915cabdff1aSopenharmony_ci 2916cabdff1aSopenharmony_ci /* The unmapping function will free this */ 2917cabdff1aSopenharmony_ci dst->data[0] = (uint8_t *)f; 2918cabdff1aSopenharmony_ci dst->width = src->width; 2919cabdff1aSopenharmony_ci dst->height = src->height; 2920cabdff1aSopenharmony_ci 2921cabdff1aSopenharmony_ci err = ff_hwframe_map_create(dst->hw_frames_ctx, dst, src, 2922cabdff1aSopenharmony_ci &vulkan_unmap_from_drm, f); 2923cabdff1aSopenharmony_ci if (err < 0) 2924cabdff1aSopenharmony_ci goto fail; 2925cabdff1aSopenharmony_ci 2926cabdff1aSopenharmony_ci av_log(hwfc, AV_LOG_DEBUG, "Mapped DRM object to Vulkan!\n"); 2927cabdff1aSopenharmony_ci 2928cabdff1aSopenharmony_ci return 0; 2929cabdff1aSopenharmony_ci 2930cabdff1aSopenharmony_cifail: 2931cabdff1aSopenharmony_ci vulkan_frame_free(hwfc->device_ctx->hwctx, (uint8_t *)f); 2932cabdff1aSopenharmony_ci dst->data[0] = NULL; 2933cabdff1aSopenharmony_ci return err; 2934cabdff1aSopenharmony_ci} 2935cabdff1aSopenharmony_ci 2936cabdff1aSopenharmony_ci#if CONFIG_VAAPI 2937cabdff1aSopenharmony_cistatic int vulkan_map_from_vaapi(AVHWFramesContext *dst_fc, 2938cabdff1aSopenharmony_ci AVFrame *dst, const AVFrame *src, 2939cabdff1aSopenharmony_ci int flags) 2940cabdff1aSopenharmony_ci{ 2941cabdff1aSopenharmony_ci int err; 2942cabdff1aSopenharmony_ci AVFrame *tmp = av_frame_alloc(); 2943cabdff1aSopenharmony_ci AVHWFramesContext *vaapi_fc = (AVHWFramesContext*)src->hw_frames_ctx->data; 2944cabdff1aSopenharmony_ci AVVAAPIDeviceContext *vaapi_ctx = vaapi_fc->device_ctx->hwctx; 2945cabdff1aSopenharmony_ci VASurfaceID surface_id = (VASurfaceID)(uintptr_t)src->data[3]; 2946cabdff1aSopenharmony_ci 2947cabdff1aSopenharmony_ci if (!tmp) 2948cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 2949cabdff1aSopenharmony_ci 2950cabdff1aSopenharmony_ci /* We have to sync since like the previous comment said, no semaphores */ 2951cabdff1aSopenharmony_ci vaSyncSurface(vaapi_ctx->display, surface_id); 2952cabdff1aSopenharmony_ci 2953cabdff1aSopenharmony_ci tmp->format = AV_PIX_FMT_DRM_PRIME; 2954cabdff1aSopenharmony_ci 2955cabdff1aSopenharmony_ci err = av_hwframe_map(tmp, src, flags); 2956cabdff1aSopenharmony_ci if (err < 0) 2957cabdff1aSopenharmony_ci goto fail; 2958cabdff1aSopenharmony_ci 2959cabdff1aSopenharmony_ci err = vulkan_map_from_drm(dst_fc, dst, tmp, flags); 2960cabdff1aSopenharmony_ci if (err < 0) 2961cabdff1aSopenharmony_ci goto fail; 2962cabdff1aSopenharmony_ci 2963cabdff1aSopenharmony_ci err = ff_hwframe_map_replace(dst, src); 2964cabdff1aSopenharmony_ci 2965cabdff1aSopenharmony_cifail: 2966cabdff1aSopenharmony_ci av_frame_free(&tmp); 2967cabdff1aSopenharmony_ci return err; 2968cabdff1aSopenharmony_ci} 2969cabdff1aSopenharmony_ci#endif 2970cabdff1aSopenharmony_ci#endif 2971cabdff1aSopenharmony_ci 2972cabdff1aSopenharmony_ci#if CONFIG_CUDA 2973cabdff1aSopenharmony_cistatic int vulkan_export_to_cuda(AVHWFramesContext *hwfc, 2974cabdff1aSopenharmony_ci AVBufferRef *cuda_hwfc, 2975cabdff1aSopenharmony_ci const AVFrame *frame) 2976cabdff1aSopenharmony_ci{ 2977cabdff1aSopenharmony_ci int err; 2978cabdff1aSopenharmony_ci VkResult ret; 2979cabdff1aSopenharmony_ci AVVkFrame *dst_f; 2980cabdff1aSopenharmony_ci AVVkFrameInternal *dst_int; 2981cabdff1aSopenharmony_ci AVHWDeviceContext *ctx = hwfc->device_ctx; 2982cabdff1aSopenharmony_ci AVVulkanDeviceContext *hwctx = ctx->hwctx; 2983cabdff1aSopenharmony_ci const int planes = av_pix_fmt_count_planes(hwfc->sw_format); 2984cabdff1aSopenharmony_ci const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(hwfc->sw_format); 2985cabdff1aSopenharmony_ci VulkanDevicePriv *p = ctx->internal->priv; 2986cabdff1aSopenharmony_ci FFVulkanFunctions *vk = &p->vkfn; 2987cabdff1aSopenharmony_ci 2988cabdff1aSopenharmony_ci AVHWFramesContext *cuda_fc = (AVHWFramesContext*)cuda_hwfc->data; 2989cabdff1aSopenharmony_ci AVHWDeviceContext *cuda_cu = cuda_fc->device_ctx; 2990cabdff1aSopenharmony_ci AVCUDADeviceContext *cuda_dev = cuda_cu->hwctx; 2991cabdff1aSopenharmony_ci AVCUDADeviceContextInternal *cu_internal = cuda_dev->internal; 2992cabdff1aSopenharmony_ci CudaFunctions *cu = cu_internal->cuda_dl; 2993cabdff1aSopenharmony_ci CUarray_format cufmt = desc->comp[0].depth > 8 ? CU_AD_FORMAT_UNSIGNED_INT16 : 2994cabdff1aSopenharmony_ci CU_AD_FORMAT_UNSIGNED_INT8; 2995cabdff1aSopenharmony_ci 2996cabdff1aSopenharmony_ci dst_f = (AVVkFrame *)frame->data[0]; 2997cabdff1aSopenharmony_ci 2998cabdff1aSopenharmony_ci dst_int = dst_f->internal; 2999cabdff1aSopenharmony_ci if (!dst_int || !dst_int->cuda_fc_ref) { 3000cabdff1aSopenharmony_ci if (!dst_f->internal) 3001cabdff1aSopenharmony_ci dst_f->internal = dst_int = av_mallocz(sizeof(*dst_f->internal)); 3002cabdff1aSopenharmony_ci 3003cabdff1aSopenharmony_ci if (!dst_int) 3004cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 3005cabdff1aSopenharmony_ci 3006cabdff1aSopenharmony_ci dst_int->cuda_fc_ref = av_buffer_ref(cuda_hwfc); 3007cabdff1aSopenharmony_ci if (!dst_int->cuda_fc_ref) { 3008cabdff1aSopenharmony_ci av_freep(&dst_f->internal); 3009cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 3010cabdff1aSopenharmony_ci } 3011cabdff1aSopenharmony_ci 3012cabdff1aSopenharmony_ci for (int i = 0; i < planes; i++) { 3013cabdff1aSopenharmony_ci CUDA_EXTERNAL_MEMORY_MIPMAPPED_ARRAY_DESC tex_desc = { 3014cabdff1aSopenharmony_ci .offset = 0, 3015cabdff1aSopenharmony_ci .arrayDesc = { 3016cabdff1aSopenharmony_ci .Depth = 0, 3017cabdff1aSopenharmony_ci .Format = cufmt, 3018cabdff1aSopenharmony_ci .NumChannels = 1 + ((planes == 2) && i), 3019cabdff1aSopenharmony_ci .Flags = 0, 3020cabdff1aSopenharmony_ci }, 3021cabdff1aSopenharmony_ci .numLevels = 1, 3022cabdff1aSopenharmony_ci }; 3023cabdff1aSopenharmony_ci int p_w, p_h; 3024cabdff1aSopenharmony_ci 3025cabdff1aSopenharmony_ci#ifdef _WIN32 3026cabdff1aSopenharmony_ci CUDA_EXTERNAL_MEMORY_HANDLE_DESC ext_desc = { 3027cabdff1aSopenharmony_ci .type = IsWindows8OrGreater() 3028cabdff1aSopenharmony_ci ? CU_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32 3029cabdff1aSopenharmony_ci : CU_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT, 3030cabdff1aSopenharmony_ci .size = dst_f->size[i], 3031cabdff1aSopenharmony_ci }; 3032cabdff1aSopenharmony_ci VkMemoryGetWin32HandleInfoKHR export_info = { 3033cabdff1aSopenharmony_ci .sType = VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR, 3034cabdff1aSopenharmony_ci .memory = dst_f->mem[i], 3035cabdff1aSopenharmony_ci .handleType = IsWindows8OrGreater() 3036cabdff1aSopenharmony_ci ? VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT 3037cabdff1aSopenharmony_ci : VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT, 3038cabdff1aSopenharmony_ci }; 3039cabdff1aSopenharmony_ci VkSemaphoreGetWin32HandleInfoKHR sem_export = { 3040cabdff1aSopenharmony_ci .sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_WIN32_HANDLE_INFO_KHR, 3041cabdff1aSopenharmony_ci .semaphore = dst_f->sem[i], 3042cabdff1aSopenharmony_ci .handleType = IsWindows8OrGreater() 3043cabdff1aSopenharmony_ci ? VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT 3044cabdff1aSopenharmony_ci : VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT, 3045cabdff1aSopenharmony_ci }; 3046cabdff1aSopenharmony_ci CUDA_EXTERNAL_SEMAPHORE_HANDLE_DESC ext_sem_desc = { 3047cabdff1aSopenharmony_ci .type = 10 /* TODO: CU_EXTERNAL_SEMAPHORE_HANDLE_TYPE_TIMELINE_SEMAPHORE_WIN32 */, 3048cabdff1aSopenharmony_ci }; 3049cabdff1aSopenharmony_ci 3050cabdff1aSopenharmony_ci ret = vk->GetMemoryWin32HandleKHR(hwctx->act_dev, &export_info, 3051cabdff1aSopenharmony_ci &ext_desc.handle.win32.handle); 3052cabdff1aSopenharmony_ci if (ret != VK_SUCCESS) { 3053cabdff1aSopenharmony_ci av_log(hwfc, AV_LOG_ERROR, "Unable to export the image as a Win32 Handle: %s!\n", 3054cabdff1aSopenharmony_ci vk_ret2str(ret)); 3055cabdff1aSopenharmony_ci err = AVERROR_EXTERNAL; 3056cabdff1aSopenharmony_ci goto fail; 3057cabdff1aSopenharmony_ci } 3058cabdff1aSopenharmony_ci dst_int->ext_mem_handle[i] = ext_desc.handle.win32.handle; 3059cabdff1aSopenharmony_ci#else 3060cabdff1aSopenharmony_ci CUDA_EXTERNAL_MEMORY_HANDLE_DESC ext_desc = { 3061cabdff1aSopenharmony_ci .type = CU_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD, 3062cabdff1aSopenharmony_ci .size = dst_f->size[i], 3063cabdff1aSopenharmony_ci }; 3064cabdff1aSopenharmony_ci VkMemoryGetFdInfoKHR export_info = { 3065cabdff1aSopenharmony_ci .sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR, 3066cabdff1aSopenharmony_ci .memory = dst_f->mem[i], 3067cabdff1aSopenharmony_ci .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR, 3068cabdff1aSopenharmony_ci }; 3069cabdff1aSopenharmony_ci VkSemaphoreGetFdInfoKHR sem_export = { 3070cabdff1aSopenharmony_ci .sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR, 3071cabdff1aSopenharmony_ci .semaphore = dst_f->sem[i], 3072cabdff1aSopenharmony_ci .handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT, 3073cabdff1aSopenharmony_ci }; 3074cabdff1aSopenharmony_ci CUDA_EXTERNAL_SEMAPHORE_HANDLE_DESC ext_sem_desc = { 3075cabdff1aSopenharmony_ci .type = 9 /* TODO: CU_EXTERNAL_SEMAPHORE_HANDLE_TYPE_TIMELINE_SEMAPHORE_FD */, 3076cabdff1aSopenharmony_ci }; 3077cabdff1aSopenharmony_ci 3078cabdff1aSopenharmony_ci ret = vk->GetMemoryFdKHR(hwctx->act_dev, &export_info, 3079cabdff1aSopenharmony_ci &ext_desc.handle.fd); 3080cabdff1aSopenharmony_ci if (ret != VK_SUCCESS) { 3081cabdff1aSopenharmony_ci av_log(hwfc, AV_LOG_ERROR, "Unable to export the image as a FD: %s!\n", 3082cabdff1aSopenharmony_ci vk_ret2str(ret)); 3083cabdff1aSopenharmony_ci err = AVERROR_EXTERNAL; 3084cabdff1aSopenharmony_ci goto fail; 3085cabdff1aSopenharmony_ci } 3086cabdff1aSopenharmony_ci#endif 3087cabdff1aSopenharmony_ci 3088cabdff1aSopenharmony_ci ret = CHECK_CU(cu->cuImportExternalMemory(&dst_int->ext_mem[i], &ext_desc)); 3089cabdff1aSopenharmony_ci if (ret < 0) { 3090cabdff1aSopenharmony_ci#ifndef _WIN32 3091cabdff1aSopenharmony_ci close(ext_desc.handle.fd); 3092cabdff1aSopenharmony_ci#endif 3093cabdff1aSopenharmony_ci err = AVERROR_EXTERNAL; 3094cabdff1aSopenharmony_ci goto fail; 3095cabdff1aSopenharmony_ci } 3096cabdff1aSopenharmony_ci 3097cabdff1aSopenharmony_ci get_plane_wh(&p_w, &p_h, hwfc->sw_format, hwfc->width, hwfc->height, i); 3098cabdff1aSopenharmony_ci tex_desc.arrayDesc.Width = p_w; 3099cabdff1aSopenharmony_ci tex_desc.arrayDesc.Height = p_h; 3100cabdff1aSopenharmony_ci 3101cabdff1aSopenharmony_ci ret = CHECK_CU(cu->cuExternalMemoryGetMappedMipmappedArray(&dst_int->cu_mma[i], 3102cabdff1aSopenharmony_ci dst_int->ext_mem[i], 3103cabdff1aSopenharmony_ci &tex_desc)); 3104cabdff1aSopenharmony_ci if (ret < 0) { 3105cabdff1aSopenharmony_ci err = AVERROR_EXTERNAL; 3106cabdff1aSopenharmony_ci goto fail; 3107cabdff1aSopenharmony_ci } 3108cabdff1aSopenharmony_ci 3109cabdff1aSopenharmony_ci ret = CHECK_CU(cu->cuMipmappedArrayGetLevel(&dst_int->cu_array[i], 3110cabdff1aSopenharmony_ci dst_int->cu_mma[i], 0)); 3111cabdff1aSopenharmony_ci if (ret < 0) { 3112cabdff1aSopenharmony_ci err = AVERROR_EXTERNAL; 3113cabdff1aSopenharmony_ci goto fail; 3114cabdff1aSopenharmony_ci } 3115cabdff1aSopenharmony_ci 3116cabdff1aSopenharmony_ci#ifdef _WIN32 3117cabdff1aSopenharmony_ci ret = vk->GetSemaphoreWin32HandleKHR(hwctx->act_dev, &sem_export, 3118cabdff1aSopenharmony_ci &ext_sem_desc.handle.win32.handle); 3119cabdff1aSopenharmony_ci#else 3120cabdff1aSopenharmony_ci ret = vk->GetSemaphoreFdKHR(hwctx->act_dev, &sem_export, 3121cabdff1aSopenharmony_ci &ext_sem_desc.handle.fd); 3122cabdff1aSopenharmony_ci#endif 3123cabdff1aSopenharmony_ci if (ret != VK_SUCCESS) { 3124cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_ERROR, "Failed to export semaphore: %s\n", 3125cabdff1aSopenharmony_ci vk_ret2str(ret)); 3126cabdff1aSopenharmony_ci err = AVERROR_EXTERNAL; 3127cabdff1aSopenharmony_ci goto fail; 3128cabdff1aSopenharmony_ci } 3129cabdff1aSopenharmony_ci#ifdef _WIN32 3130cabdff1aSopenharmony_ci dst_int->ext_sem_handle[i] = ext_sem_desc.handle.win32.handle; 3131cabdff1aSopenharmony_ci#endif 3132cabdff1aSopenharmony_ci 3133cabdff1aSopenharmony_ci ret = CHECK_CU(cu->cuImportExternalSemaphore(&dst_int->cu_sem[i], 3134cabdff1aSopenharmony_ci &ext_sem_desc)); 3135cabdff1aSopenharmony_ci if (ret < 0) { 3136cabdff1aSopenharmony_ci#ifndef _WIN32 3137cabdff1aSopenharmony_ci close(ext_sem_desc.handle.fd); 3138cabdff1aSopenharmony_ci#endif 3139cabdff1aSopenharmony_ci err = AVERROR_EXTERNAL; 3140cabdff1aSopenharmony_ci goto fail; 3141cabdff1aSopenharmony_ci } 3142cabdff1aSopenharmony_ci } 3143cabdff1aSopenharmony_ci } 3144cabdff1aSopenharmony_ci 3145cabdff1aSopenharmony_ci return 0; 3146cabdff1aSopenharmony_ci 3147cabdff1aSopenharmony_cifail: 3148cabdff1aSopenharmony_ci vulkan_free_internal(dst_f); 3149cabdff1aSopenharmony_ci return err; 3150cabdff1aSopenharmony_ci} 3151cabdff1aSopenharmony_ci 3152cabdff1aSopenharmony_cistatic int vulkan_transfer_data_from_cuda(AVHWFramesContext *hwfc, 3153cabdff1aSopenharmony_ci AVFrame *dst, const AVFrame *src) 3154cabdff1aSopenharmony_ci{ 3155cabdff1aSopenharmony_ci int err; 3156cabdff1aSopenharmony_ci CUcontext dummy; 3157cabdff1aSopenharmony_ci AVVkFrame *dst_f; 3158cabdff1aSopenharmony_ci AVVkFrameInternal *dst_int; 3159cabdff1aSopenharmony_ci VulkanFramesPriv *fp = hwfc->internal->priv; 3160cabdff1aSopenharmony_ci const int planes = av_pix_fmt_count_planes(hwfc->sw_format); 3161cabdff1aSopenharmony_ci const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(hwfc->sw_format); 3162cabdff1aSopenharmony_ci 3163cabdff1aSopenharmony_ci AVHWFramesContext *cuda_fc = (AVHWFramesContext*)src->hw_frames_ctx->data; 3164cabdff1aSopenharmony_ci AVHWDeviceContext *cuda_cu = cuda_fc->device_ctx; 3165cabdff1aSopenharmony_ci AVCUDADeviceContext *cuda_dev = cuda_cu->hwctx; 3166cabdff1aSopenharmony_ci AVCUDADeviceContextInternal *cu_internal = cuda_dev->internal; 3167cabdff1aSopenharmony_ci CudaFunctions *cu = cu_internal->cuda_dl; 3168cabdff1aSopenharmony_ci CUDA_EXTERNAL_SEMAPHORE_WAIT_PARAMS s_w_par[AV_NUM_DATA_POINTERS] = { 0 }; 3169cabdff1aSopenharmony_ci CUDA_EXTERNAL_SEMAPHORE_SIGNAL_PARAMS s_s_par[AV_NUM_DATA_POINTERS] = { 0 }; 3170cabdff1aSopenharmony_ci 3171cabdff1aSopenharmony_ci dst_f = (AVVkFrame *)dst->data[0]; 3172cabdff1aSopenharmony_ci 3173cabdff1aSopenharmony_ci err = prepare_frame(hwfc, &fp->upload_ctx, dst_f, PREP_MODE_EXTERNAL_EXPORT); 3174cabdff1aSopenharmony_ci if (err < 0) 3175cabdff1aSopenharmony_ci return err; 3176cabdff1aSopenharmony_ci 3177cabdff1aSopenharmony_ci err = CHECK_CU(cu->cuCtxPushCurrent(cuda_dev->cuda_ctx)); 3178cabdff1aSopenharmony_ci if (err < 0) 3179cabdff1aSopenharmony_ci return err; 3180cabdff1aSopenharmony_ci 3181cabdff1aSopenharmony_ci err = vulkan_export_to_cuda(hwfc, src->hw_frames_ctx, dst); 3182cabdff1aSopenharmony_ci if (err < 0) { 3183cabdff1aSopenharmony_ci CHECK_CU(cu->cuCtxPopCurrent(&dummy)); 3184cabdff1aSopenharmony_ci return err; 3185cabdff1aSopenharmony_ci } 3186cabdff1aSopenharmony_ci 3187cabdff1aSopenharmony_ci dst_int = dst_f->internal; 3188cabdff1aSopenharmony_ci 3189cabdff1aSopenharmony_ci for (int i = 0; i < planes; i++) { 3190cabdff1aSopenharmony_ci s_w_par[i].params.fence.value = dst_f->sem_value[i] + 0; 3191cabdff1aSopenharmony_ci s_s_par[i].params.fence.value = dst_f->sem_value[i] + 1; 3192cabdff1aSopenharmony_ci } 3193cabdff1aSopenharmony_ci 3194cabdff1aSopenharmony_ci err = CHECK_CU(cu->cuWaitExternalSemaphoresAsync(dst_int->cu_sem, s_w_par, 3195cabdff1aSopenharmony_ci planes, cuda_dev->stream)); 3196cabdff1aSopenharmony_ci if (err < 0) 3197cabdff1aSopenharmony_ci goto fail; 3198cabdff1aSopenharmony_ci 3199cabdff1aSopenharmony_ci for (int i = 0; i < planes; i++) { 3200cabdff1aSopenharmony_ci CUDA_MEMCPY2D cpy = { 3201cabdff1aSopenharmony_ci .srcMemoryType = CU_MEMORYTYPE_DEVICE, 3202cabdff1aSopenharmony_ci .srcDevice = (CUdeviceptr)src->data[i], 3203cabdff1aSopenharmony_ci .srcPitch = src->linesize[i], 3204cabdff1aSopenharmony_ci .srcY = 0, 3205cabdff1aSopenharmony_ci 3206cabdff1aSopenharmony_ci .dstMemoryType = CU_MEMORYTYPE_ARRAY, 3207cabdff1aSopenharmony_ci .dstArray = dst_int->cu_array[i], 3208cabdff1aSopenharmony_ci }; 3209cabdff1aSopenharmony_ci 3210cabdff1aSopenharmony_ci int p_w, p_h; 3211cabdff1aSopenharmony_ci get_plane_wh(&p_w, &p_h, hwfc->sw_format, hwfc->width, hwfc->height, i); 3212cabdff1aSopenharmony_ci 3213cabdff1aSopenharmony_ci cpy.WidthInBytes = p_w * desc->comp[i].step; 3214cabdff1aSopenharmony_ci cpy.Height = p_h; 3215cabdff1aSopenharmony_ci 3216cabdff1aSopenharmony_ci err = CHECK_CU(cu->cuMemcpy2DAsync(&cpy, cuda_dev->stream)); 3217cabdff1aSopenharmony_ci if (err < 0) 3218cabdff1aSopenharmony_ci goto fail; 3219cabdff1aSopenharmony_ci } 3220cabdff1aSopenharmony_ci 3221cabdff1aSopenharmony_ci err = CHECK_CU(cu->cuSignalExternalSemaphoresAsync(dst_int->cu_sem, s_s_par, 3222cabdff1aSopenharmony_ci planes, cuda_dev->stream)); 3223cabdff1aSopenharmony_ci if (err < 0) 3224cabdff1aSopenharmony_ci goto fail; 3225cabdff1aSopenharmony_ci 3226cabdff1aSopenharmony_ci for (int i = 0; i < planes; i++) 3227cabdff1aSopenharmony_ci dst_f->sem_value[i]++; 3228cabdff1aSopenharmony_ci 3229cabdff1aSopenharmony_ci CHECK_CU(cu->cuCtxPopCurrent(&dummy)); 3230cabdff1aSopenharmony_ci 3231cabdff1aSopenharmony_ci av_log(hwfc, AV_LOG_VERBOSE, "Transfered CUDA image to Vulkan!\n"); 3232cabdff1aSopenharmony_ci 3233cabdff1aSopenharmony_ci return err = prepare_frame(hwfc, &fp->upload_ctx, dst_f, PREP_MODE_EXTERNAL_IMPORT); 3234cabdff1aSopenharmony_ci 3235cabdff1aSopenharmony_cifail: 3236cabdff1aSopenharmony_ci CHECK_CU(cu->cuCtxPopCurrent(&dummy)); 3237cabdff1aSopenharmony_ci vulkan_free_internal(dst_f); 3238cabdff1aSopenharmony_ci dst_f->internal = NULL; 3239cabdff1aSopenharmony_ci av_buffer_unref(&dst->buf[0]); 3240cabdff1aSopenharmony_ci return err; 3241cabdff1aSopenharmony_ci} 3242cabdff1aSopenharmony_ci#endif 3243cabdff1aSopenharmony_ci 3244cabdff1aSopenharmony_cistatic int vulkan_map_to(AVHWFramesContext *hwfc, AVFrame *dst, 3245cabdff1aSopenharmony_ci const AVFrame *src, int flags) 3246cabdff1aSopenharmony_ci{ 3247cabdff1aSopenharmony_ci av_unused VulkanDevicePriv *p = hwfc->device_ctx->internal->priv; 3248cabdff1aSopenharmony_ci 3249cabdff1aSopenharmony_ci switch (src->format) { 3250cabdff1aSopenharmony_ci#if CONFIG_LIBDRM 3251cabdff1aSopenharmony_ci#if CONFIG_VAAPI 3252cabdff1aSopenharmony_ci case AV_PIX_FMT_VAAPI: 3253cabdff1aSopenharmony_ci if (p->extensions & (FF_VK_EXT_EXTERNAL_DMABUF_MEMORY | FF_VK_EXT_DRM_MODIFIER_FLAGS)) 3254cabdff1aSopenharmony_ci return vulkan_map_from_vaapi(hwfc, dst, src, flags); 3255cabdff1aSopenharmony_ci else 3256cabdff1aSopenharmony_ci return AVERROR(ENOSYS); 3257cabdff1aSopenharmony_ci#endif 3258cabdff1aSopenharmony_ci case AV_PIX_FMT_DRM_PRIME: 3259cabdff1aSopenharmony_ci if (p->extensions & (FF_VK_EXT_EXTERNAL_DMABUF_MEMORY | FF_VK_EXT_DRM_MODIFIER_FLAGS)) 3260cabdff1aSopenharmony_ci return vulkan_map_from_drm(hwfc, dst, src, flags); 3261cabdff1aSopenharmony_ci else 3262cabdff1aSopenharmony_ci return AVERROR(ENOSYS); 3263cabdff1aSopenharmony_ci#endif 3264cabdff1aSopenharmony_ci default: 3265cabdff1aSopenharmony_ci return AVERROR(ENOSYS); 3266cabdff1aSopenharmony_ci } 3267cabdff1aSopenharmony_ci} 3268cabdff1aSopenharmony_ci 3269cabdff1aSopenharmony_ci#if CONFIG_LIBDRM 3270cabdff1aSopenharmony_citypedef struct VulkanDRMMapping { 3271cabdff1aSopenharmony_ci AVDRMFrameDescriptor drm_desc; 3272cabdff1aSopenharmony_ci AVVkFrame *source; 3273cabdff1aSopenharmony_ci} VulkanDRMMapping; 3274cabdff1aSopenharmony_ci 3275cabdff1aSopenharmony_cistatic void vulkan_unmap_to_drm(AVHWFramesContext *hwfc, HWMapDescriptor *hwmap) 3276cabdff1aSopenharmony_ci{ 3277cabdff1aSopenharmony_ci AVDRMFrameDescriptor *drm_desc = hwmap->priv; 3278cabdff1aSopenharmony_ci 3279cabdff1aSopenharmony_ci for (int i = 0; i < drm_desc->nb_objects; i++) 3280cabdff1aSopenharmony_ci close(drm_desc->objects[i].fd); 3281cabdff1aSopenharmony_ci 3282cabdff1aSopenharmony_ci av_free(drm_desc); 3283cabdff1aSopenharmony_ci} 3284cabdff1aSopenharmony_ci 3285cabdff1aSopenharmony_cistatic inline uint32_t vulkan_fmt_to_drm(VkFormat vkfmt) 3286cabdff1aSopenharmony_ci{ 3287cabdff1aSopenharmony_ci for (int i = 0; i < FF_ARRAY_ELEMS(vulkan_drm_format_map); i++) 3288cabdff1aSopenharmony_ci if (vulkan_drm_format_map[i].vk_format == vkfmt) 3289cabdff1aSopenharmony_ci return vulkan_drm_format_map[i].drm_fourcc; 3290cabdff1aSopenharmony_ci return DRM_FORMAT_INVALID; 3291cabdff1aSopenharmony_ci} 3292cabdff1aSopenharmony_ci 3293cabdff1aSopenharmony_cistatic int vulkan_map_to_drm(AVHWFramesContext *hwfc, AVFrame *dst, 3294cabdff1aSopenharmony_ci const AVFrame *src, int flags) 3295cabdff1aSopenharmony_ci{ 3296cabdff1aSopenharmony_ci int err = 0; 3297cabdff1aSopenharmony_ci VkResult ret; 3298cabdff1aSopenharmony_ci AVVkFrame *f = (AVVkFrame *)src->data[0]; 3299cabdff1aSopenharmony_ci VulkanDevicePriv *p = hwfc->device_ctx->internal->priv; 3300cabdff1aSopenharmony_ci FFVulkanFunctions *vk = &p->vkfn; 3301cabdff1aSopenharmony_ci VulkanFramesPriv *fp = hwfc->internal->priv; 3302cabdff1aSopenharmony_ci AVVulkanDeviceContext *hwctx = hwfc->device_ctx->hwctx; 3303cabdff1aSopenharmony_ci AVVulkanFramesContext *hwfctx = hwfc->hwctx; 3304cabdff1aSopenharmony_ci const int planes = av_pix_fmt_count_planes(hwfc->sw_format); 3305cabdff1aSopenharmony_ci VkImageDrmFormatModifierPropertiesEXT drm_mod = { 3306cabdff1aSopenharmony_ci .sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT, 3307cabdff1aSopenharmony_ci }; 3308cabdff1aSopenharmony_ci VkSemaphoreWaitInfo wait_info = { 3309cabdff1aSopenharmony_ci .sType = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO, 3310cabdff1aSopenharmony_ci .flags = 0x0, 3311cabdff1aSopenharmony_ci .semaphoreCount = planes, 3312cabdff1aSopenharmony_ci }; 3313cabdff1aSopenharmony_ci 3314cabdff1aSopenharmony_ci AVDRMFrameDescriptor *drm_desc = av_mallocz(sizeof(*drm_desc)); 3315cabdff1aSopenharmony_ci if (!drm_desc) 3316cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 3317cabdff1aSopenharmony_ci 3318cabdff1aSopenharmony_ci err = prepare_frame(hwfc, &fp->conv_ctx, f, PREP_MODE_EXTERNAL_EXPORT); 3319cabdff1aSopenharmony_ci if (err < 0) 3320cabdff1aSopenharmony_ci goto end; 3321cabdff1aSopenharmony_ci 3322cabdff1aSopenharmony_ci /* Wait for the operation to finish so we can cleanly export it. */ 3323cabdff1aSopenharmony_ci wait_info.pSemaphores = f->sem; 3324cabdff1aSopenharmony_ci wait_info.pValues = f->sem_value; 3325cabdff1aSopenharmony_ci 3326cabdff1aSopenharmony_ci vk->WaitSemaphores(hwctx->act_dev, &wait_info, UINT64_MAX); 3327cabdff1aSopenharmony_ci 3328cabdff1aSopenharmony_ci err = ff_hwframe_map_create(src->hw_frames_ctx, dst, src, &vulkan_unmap_to_drm, drm_desc); 3329cabdff1aSopenharmony_ci if (err < 0) 3330cabdff1aSopenharmony_ci goto end; 3331cabdff1aSopenharmony_ci 3332cabdff1aSopenharmony_ci ret = vk->GetImageDrmFormatModifierPropertiesEXT(hwctx->act_dev, f->img[0], 3333cabdff1aSopenharmony_ci &drm_mod); 3334cabdff1aSopenharmony_ci if (ret != VK_SUCCESS) { 3335cabdff1aSopenharmony_ci av_log(hwfc, AV_LOG_ERROR, "Failed to retrieve DRM format modifier!\n"); 3336cabdff1aSopenharmony_ci err = AVERROR_EXTERNAL; 3337cabdff1aSopenharmony_ci goto end; 3338cabdff1aSopenharmony_ci } 3339cabdff1aSopenharmony_ci 3340cabdff1aSopenharmony_ci for (int i = 0; (i < planes) && (f->mem[i]); i++) { 3341cabdff1aSopenharmony_ci VkMemoryGetFdInfoKHR export_info = { 3342cabdff1aSopenharmony_ci .sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR, 3343cabdff1aSopenharmony_ci .memory = f->mem[i], 3344cabdff1aSopenharmony_ci .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT, 3345cabdff1aSopenharmony_ci }; 3346cabdff1aSopenharmony_ci 3347cabdff1aSopenharmony_ci ret = vk->GetMemoryFdKHR(hwctx->act_dev, &export_info, 3348cabdff1aSopenharmony_ci &drm_desc->objects[i].fd); 3349cabdff1aSopenharmony_ci if (ret != VK_SUCCESS) { 3350cabdff1aSopenharmony_ci av_log(hwfc, AV_LOG_ERROR, "Unable to export the image as a FD!\n"); 3351cabdff1aSopenharmony_ci err = AVERROR_EXTERNAL; 3352cabdff1aSopenharmony_ci goto end; 3353cabdff1aSopenharmony_ci } 3354cabdff1aSopenharmony_ci 3355cabdff1aSopenharmony_ci drm_desc->nb_objects++; 3356cabdff1aSopenharmony_ci drm_desc->objects[i].size = f->size[i]; 3357cabdff1aSopenharmony_ci drm_desc->objects[i].format_modifier = drm_mod.drmFormatModifier; 3358cabdff1aSopenharmony_ci } 3359cabdff1aSopenharmony_ci 3360cabdff1aSopenharmony_ci drm_desc->nb_layers = planes; 3361cabdff1aSopenharmony_ci for (int i = 0; i < drm_desc->nb_layers; i++) { 3362cabdff1aSopenharmony_ci VkSubresourceLayout layout; 3363cabdff1aSopenharmony_ci VkImageSubresource sub = { 3364cabdff1aSopenharmony_ci .aspectMask = VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT, 3365cabdff1aSopenharmony_ci }; 3366cabdff1aSopenharmony_ci VkFormat plane_vkfmt = av_vkfmt_from_pixfmt(hwfc->sw_format)[i]; 3367cabdff1aSopenharmony_ci 3368cabdff1aSopenharmony_ci drm_desc->layers[i].format = vulkan_fmt_to_drm(plane_vkfmt); 3369cabdff1aSopenharmony_ci drm_desc->layers[i].nb_planes = 1; 3370cabdff1aSopenharmony_ci 3371cabdff1aSopenharmony_ci if (drm_desc->layers[i].format == DRM_FORMAT_INVALID) { 3372cabdff1aSopenharmony_ci av_log(hwfc, AV_LOG_ERROR, "Cannot map to DRM layer, unsupported!\n"); 3373cabdff1aSopenharmony_ci err = AVERROR_PATCHWELCOME; 3374cabdff1aSopenharmony_ci goto end; 3375cabdff1aSopenharmony_ci } 3376cabdff1aSopenharmony_ci 3377cabdff1aSopenharmony_ci drm_desc->layers[i].planes[0].object_index = FFMIN(i, drm_desc->nb_objects - 1); 3378cabdff1aSopenharmony_ci 3379cabdff1aSopenharmony_ci if (f->tiling == VK_IMAGE_TILING_OPTIMAL) 3380cabdff1aSopenharmony_ci continue; 3381cabdff1aSopenharmony_ci 3382cabdff1aSopenharmony_ci vk->GetImageSubresourceLayout(hwctx->act_dev, f->img[i], &sub, &layout); 3383cabdff1aSopenharmony_ci drm_desc->layers[i].planes[0].offset = layout.offset; 3384cabdff1aSopenharmony_ci drm_desc->layers[i].planes[0].pitch = layout.rowPitch; 3385cabdff1aSopenharmony_ci 3386cabdff1aSopenharmony_ci if (hwfctx->flags & AV_VK_FRAME_FLAG_CONTIGUOUS_MEMORY) 3387cabdff1aSopenharmony_ci drm_desc->layers[i].planes[0].offset += f->offset[i]; 3388cabdff1aSopenharmony_ci } 3389cabdff1aSopenharmony_ci 3390cabdff1aSopenharmony_ci dst->width = src->width; 3391cabdff1aSopenharmony_ci dst->height = src->height; 3392cabdff1aSopenharmony_ci dst->data[0] = (uint8_t *)drm_desc; 3393cabdff1aSopenharmony_ci 3394cabdff1aSopenharmony_ci av_log(hwfc, AV_LOG_VERBOSE, "Mapped AVVkFrame to a DRM object!\n"); 3395cabdff1aSopenharmony_ci 3396cabdff1aSopenharmony_ci return 0; 3397cabdff1aSopenharmony_ci 3398cabdff1aSopenharmony_ciend: 3399cabdff1aSopenharmony_ci av_free(drm_desc); 3400cabdff1aSopenharmony_ci return err; 3401cabdff1aSopenharmony_ci} 3402cabdff1aSopenharmony_ci 3403cabdff1aSopenharmony_ci#if CONFIG_VAAPI 3404cabdff1aSopenharmony_cistatic int vulkan_map_to_vaapi(AVHWFramesContext *hwfc, AVFrame *dst, 3405cabdff1aSopenharmony_ci const AVFrame *src, int flags) 3406cabdff1aSopenharmony_ci{ 3407cabdff1aSopenharmony_ci int err; 3408cabdff1aSopenharmony_ci AVFrame *tmp = av_frame_alloc(); 3409cabdff1aSopenharmony_ci if (!tmp) 3410cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 3411cabdff1aSopenharmony_ci 3412cabdff1aSopenharmony_ci tmp->format = AV_PIX_FMT_DRM_PRIME; 3413cabdff1aSopenharmony_ci 3414cabdff1aSopenharmony_ci err = vulkan_map_to_drm(hwfc, tmp, src, flags); 3415cabdff1aSopenharmony_ci if (err < 0) 3416cabdff1aSopenharmony_ci goto fail; 3417cabdff1aSopenharmony_ci 3418cabdff1aSopenharmony_ci err = av_hwframe_map(dst, tmp, flags); 3419cabdff1aSopenharmony_ci if (err < 0) 3420cabdff1aSopenharmony_ci goto fail; 3421cabdff1aSopenharmony_ci 3422cabdff1aSopenharmony_ci err = ff_hwframe_map_replace(dst, src); 3423cabdff1aSopenharmony_ci 3424cabdff1aSopenharmony_cifail: 3425cabdff1aSopenharmony_ci av_frame_free(&tmp); 3426cabdff1aSopenharmony_ci return err; 3427cabdff1aSopenharmony_ci} 3428cabdff1aSopenharmony_ci#endif 3429cabdff1aSopenharmony_ci#endif 3430cabdff1aSopenharmony_ci 3431cabdff1aSopenharmony_cistatic int vulkan_map_from(AVHWFramesContext *hwfc, AVFrame *dst, 3432cabdff1aSopenharmony_ci const AVFrame *src, int flags) 3433cabdff1aSopenharmony_ci{ 3434cabdff1aSopenharmony_ci av_unused VulkanDevicePriv *p = hwfc->device_ctx->internal->priv; 3435cabdff1aSopenharmony_ci 3436cabdff1aSopenharmony_ci switch (dst->format) { 3437cabdff1aSopenharmony_ci#if CONFIG_LIBDRM 3438cabdff1aSopenharmony_ci case AV_PIX_FMT_DRM_PRIME: 3439cabdff1aSopenharmony_ci if (p->extensions & (FF_VK_EXT_EXTERNAL_DMABUF_MEMORY | FF_VK_EXT_DRM_MODIFIER_FLAGS)) 3440cabdff1aSopenharmony_ci return vulkan_map_to_drm(hwfc, dst, src, flags); 3441cabdff1aSopenharmony_ci else 3442cabdff1aSopenharmony_ci return AVERROR(ENOSYS); 3443cabdff1aSopenharmony_ci#if CONFIG_VAAPI 3444cabdff1aSopenharmony_ci case AV_PIX_FMT_VAAPI: 3445cabdff1aSopenharmony_ci if (p->extensions & (FF_VK_EXT_EXTERNAL_DMABUF_MEMORY | FF_VK_EXT_DRM_MODIFIER_FLAGS)) 3446cabdff1aSopenharmony_ci return vulkan_map_to_vaapi(hwfc, dst, src, flags); 3447cabdff1aSopenharmony_ci else 3448cabdff1aSopenharmony_ci return AVERROR(ENOSYS); 3449cabdff1aSopenharmony_ci#endif 3450cabdff1aSopenharmony_ci#endif 3451cabdff1aSopenharmony_ci default: 3452cabdff1aSopenharmony_ci return vulkan_map_frame_to_mem(hwfc, dst, src, flags); 3453cabdff1aSopenharmony_ci } 3454cabdff1aSopenharmony_ci} 3455cabdff1aSopenharmony_ci 3456cabdff1aSopenharmony_citypedef struct ImageBuffer { 3457cabdff1aSopenharmony_ci VkBuffer buf; 3458cabdff1aSopenharmony_ci VkDeviceMemory mem; 3459cabdff1aSopenharmony_ci VkMemoryPropertyFlagBits flags; 3460cabdff1aSopenharmony_ci int mapped_mem; 3461cabdff1aSopenharmony_ci} ImageBuffer; 3462cabdff1aSopenharmony_ci 3463cabdff1aSopenharmony_cistatic void free_buf(void *opaque, uint8_t *data) 3464cabdff1aSopenharmony_ci{ 3465cabdff1aSopenharmony_ci AVHWDeviceContext *ctx = opaque; 3466cabdff1aSopenharmony_ci AVVulkanDeviceContext *hwctx = ctx->hwctx; 3467cabdff1aSopenharmony_ci VulkanDevicePriv *p = ctx->internal->priv; 3468cabdff1aSopenharmony_ci FFVulkanFunctions *vk = &p->vkfn; 3469cabdff1aSopenharmony_ci ImageBuffer *vkbuf = (ImageBuffer *)data; 3470cabdff1aSopenharmony_ci 3471cabdff1aSopenharmony_ci if (vkbuf->buf) 3472cabdff1aSopenharmony_ci vk->DestroyBuffer(hwctx->act_dev, vkbuf->buf, hwctx->alloc); 3473cabdff1aSopenharmony_ci if (vkbuf->mem) 3474cabdff1aSopenharmony_ci vk->FreeMemory(hwctx->act_dev, vkbuf->mem, hwctx->alloc); 3475cabdff1aSopenharmony_ci 3476cabdff1aSopenharmony_ci av_free(data); 3477cabdff1aSopenharmony_ci} 3478cabdff1aSopenharmony_ci 3479cabdff1aSopenharmony_cistatic size_t get_req_buffer_size(VulkanDevicePriv *p, int *stride, int height) 3480cabdff1aSopenharmony_ci{ 3481cabdff1aSopenharmony_ci size_t size; 3482cabdff1aSopenharmony_ci *stride = FFALIGN(*stride, p->props.properties.limits.optimalBufferCopyRowPitchAlignment); 3483cabdff1aSopenharmony_ci size = height*(*stride); 3484cabdff1aSopenharmony_ci size = FFALIGN(size, p->props.properties.limits.minMemoryMapAlignment); 3485cabdff1aSopenharmony_ci return size; 3486cabdff1aSopenharmony_ci} 3487cabdff1aSopenharmony_ci 3488cabdff1aSopenharmony_cistatic int create_buf(AVHWDeviceContext *ctx, AVBufferRef **buf, 3489cabdff1aSopenharmony_ci VkBufferUsageFlags usage, VkMemoryPropertyFlagBits flags, 3490cabdff1aSopenharmony_ci size_t size, uint32_t req_memory_bits, int host_mapped, 3491cabdff1aSopenharmony_ci void *create_pnext, void *alloc_pnext) 3492cabdff1aSopenharmony_ci{ 3493cabdff1aSopenharmony_ci int err; 3494cabdff1aSopenharmony_ci VkResult ret; 3495cabdff1aSopenharmony_ci int use_ded_mem; 3496cabdff1aSopenharmony_ci AVVulkanDeviceContext *hwctx = ctx->hwctx; 3497cabdff1aSopenharmony_ci VulkanDevicePriv *p = ctx->internal->priv; 3498cabdff1aSopenharmony_ci FFVulkanFunctions *vk = &p->vkfn; 3499cabdff1aSopenharmony_ci 3500cabdff1aSopenharmony_ci VkBufferCreateInfo buf_spawn = { 3501cabdff1aSopenharmony_ci .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, 3502cabdff1aSopenharmony_ci .pNext = create_pnext, 3503cabdff1aSopenharmony_ci .usage = usage, 3504cabdff1aSopenharmony_ci .size = size, 3505cabdff1aSopenharmony_ci .sharingMode = VK_SHARING_MODE_EXCLUSIVE, 3506cabdff1aSopenharmony_ci }; 3507cabdff1aSopenharmony_ci 3508cabdff1aSopenharmony_ci VkBufferMemoryRequirementsInfo2 req_desc = { 3509cabdff1aSopenharmony_ci .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2, 3510cabdff1aSopenharmony_ci }; 3511cabdff1aSopenharmony_ci VkMemoryDedicatedAllocateInfo ded_alloc = { 3512cabdff1aSopenharmony_ci .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO, 3513cabdff1aSopenharmony_ci .pNext = alloc_pnext, 3514cabdff1aSopenharmony_ci }; 3515cabdff1aSopenharmony_ci VkMemoryDedicatedRequirements ded_req = { 3516cabdff1aSopenharmony_ci .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS, 3517cabdff1aSopenharmony_ci }; 3518cabdff1aSopenharmony_ci VkMemoryRequirements2 req = { 3519cabdff1aSopenharmony_ci .sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2, 3520cabdff1aSopenharmony_ci .pNext = &ded_req, 3521cabdff1aSopenharmony_ci }; 3522cabdff1aSopenharmony_ci 3523cabdff1aSopenharmony_ci ImageBuffer *vkbuf = av_mallocz(sizeof(*vkbuf)); 3524cabdff1aSopenharmony_ci if (!vkbuf) 3525cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 3526cabdff1aSopenharmony_ci 3527cabdff1aSopenharmony_ci vkbuf->mapped_mem = host_mapped; 3528cabdff1aSopenharmony_ci 3529cabdff1aSopenharmony_ci ret = vk->CreateBuffer(hwctx->act_dev, &buf_spawn, NULL, &vkbuf->buf); 3530cabdff1aSopenharmony_ci if (ret != VK_SUCCESS) { 3531cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_ERROR, "Failed to create buffer: %s\n", 3532cabdff1aSopenharmony_ci vk_ret2str(ret)); 3533cabdff1aSopenharmony_ci err = AVERROR_EXTERNAL; 3534cabdff1aSopenharmony_ci goto fail; 3535cabdff1aSopenharmony_ci } 3536cabdff1aSopenharmony_ci 3537cabdff1aSopenharmony_ci req_desc.buffer = vkbuf->buf; 3538cabdff1aSopenharmony_ci 3539cabdff1aSopenharmony_ci vk->GetBufferMemoryRequirements2(hwctx->act_dev, &req_desc, &req); 3540cabdff1aSopenharmony_ci 3541cabdff1aSopenharmony_ci /* In case the implementation prefers/requires dedicated allocation */ 3542cabdff1aSopenharmony_ci use_ded_mem = ded_req.prefersDedicatedAllocation | 3543cabdff1aSopenharmony_ci ded_req.requiresDedicatedAllocation; 3544cabdff1aSopenharmony_ci if (use_ded_mem) 3545cabdff1aSopenharmony_ci ded_alloc.buffer = vkbuf->buf; 3546cabdff1aSopenharmony_ci 3547cabdff1aSopenharmony_ci /* Additional requirements imposed on us */ 3548cabdff1aSopenharmony_ci if (req_memory_bits) 3549cabdff1aSopenharmony_ci req.memoryRequirements.memoryTypeBits &= req_memory_bits; 3550cabdff1aSopenharmony_ci 3551cabdff1aSopenharmony_ci err = alloc_mem(ctx, &req.memoryRequirements, flags, 3552cabdff1aSopenharmony_ci use_ded_mem ? &ded_alloc : (void *)ded_alloc.pNext, 3553cabdff1aSopenharmony_ci &vkbuf->flags, &vkbuf->mem); 3554cabdff1aSopenharmony_ci if (err) 3555cabdff1aSopenharmony_ci goto fail; 3556cabdff1aSopenharmony_ci 3557cabdff1aSopenharmony_ci ret = vk->BindBufferMemory(hwctx->act_dev, vkbuf->buf, vkbuf->mem, 0); 3558cabdff1aSopenharmony_ci if (ret != VK_SUCCESS) { 3559cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_ERROR, "Failed to bind memory to buffer: %s\n", 3560cabdff1aSopenharmony_ci vk_ret2str(ret)); 3561cabdff1aSopenharmony_ci err = AVERROR_EXTERNAL; 3562cabdff1aSopenharmony_ci goto fail; 3563cabdff1aSopenharmony_ci } 3564cabdff1aSopenharmony_ci 3565cabdff1aSopenharmony_ci *buf = av_buffer_create((uint8_t *)vkbuf, sizeof(*vkbuf), free_buf, ctx, 0); 3566cabdff1aSopenharmony_ci if (!(*buf)) { 3567cabdff1aSopenharmony_ci err = AVERROR(ENOMEM); 3568cabdff1aSopenharmony_ci goto fail; 3569cabdff1aSopenharmony_ci } 3570cabdff1aSopenharmony_ci 3571cabdff1aSopenharmony_ci return 0; 3572cabdff1aSopenharmony_ci 3573cabdff1aSopenharmony_cifail: 3574cabdff1aSopenharmony_ci free_buf(ctx, (uint8_t *)vkbuf); 3575cabdff1aSopenharmony_ci return err; 3576cabdff1aSopenharmony_ci} 3577cabdff1aSopenharmony_ci 3578cabdff1aSopenharmony_ci/* Skips mapping of host mapped buffers but still invalidates them */ 3579cabdff1aSopenharmony_cistatic int map_buffers(AVHWDeviceContext *ctx, AVBufferRef **bufs, uint8_t *mem[], 3580cabdff1aSopenharmony_ci int nb_buffers, int invalidate) 3581cabdff1aSopenharmony_ci{ 3582cabdff1aSopenharmony_ci VkResult ret; 3583cabdff1aSopenharmony_ci AVVulkanDeviceContext *hwctx = ctx->hwctx; 3584cabdff1aSopenharmony_ci VulkanDevicePriv *p = ctx->internal->priv; 3585cabdff1aSopenharmony_ci FFVulkanFunctions *vk = &p->vkfn; 3586cabdff1aSopenharmony_ci VkMappedMemoryRange invalidate_ctx[AV_NUM_DATA_POINTERS]; 3587cabdff1aSopenharmony_ci int invalidate_count = 0; 3588cabdff1aSopenharmony_ci 3589cabdff1aSopenharmony_ci for (int i = 0; i < nb_buffers; i++) { 3590cabdff1aSopenharmony_ci ImageBuffer *vkbuf = (ImageBuffer *)bufs[i]->data; 3591cabdff1aSopenharmony_ci if (vkbuf->mapped_mem) 3592cabdff1aSopenharmony_ci continue; 3593cabdff1aSopenharmony_ci 3594cabdff1aSopenharmony_ci ret = vk->MapMemory(hwctx->act_dev, vkbuf->mem, 0, 3595cabdff1aSopenharmony_ci VK_WHOLE_SIZE, 0, (void **)&mem[i]); 3596cabdff1aSopenharmony_ci if (ret != VK_SUCCESS) { 3597cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_ERROR, "Failed to map buffer memory: %s\n", 3598cabdff1aSopenharmony_ci vk_ret2str(ret)); 3599cabdff1aSopenharmony_ci return AVERROR_EXTERNAL; 3600cabdff1aSopenharmony_ci } 3601cabdff1aSopenharmony_ci } 3602cabdff1aSopenharmony_ci 3603cabdff1aSopenharmony_ci if (!invalidate) 3604cabdff1aSopenharmony_ci return 0; 3605cabdff1aSopenharmony_ci 3606cabdff1aSopenharmony_ci for (int i = 0; i < nb_buffers; i++) { 3607cabdff1aSopenharmony_ci ImageBuffer *vkbuf = (ImageBuffer *)bufs[i]->data; 3608cabdff1aSopenharmony_ci const VkMappedMemoryRange ival_buf = { 3609cabdff1aSopenharmony_ci .sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, 3610cabdff1aSopenharmony_ci .memory = vkbuf->mem, 3611cabdff1aSopenharmony_ci .size = VK_WHOLE_SIZE, 3612cabdff1aSopenharmony_ci }; 3613cabdff1aSopenharmony_ci 3614cabdff1aSopenharmony_ci /* For host imported memory Vulkan says to use platform-defined 3615cabdff1aSopenharmony_ci * sync methods, but doesn't really say not to call flush or invalidate 3616cabdff1aSopenharmony_ci * on original host pointers. It does explicitly allow to do that on 3617cabdff1aSopenharmony_ci * host-mapped pointers which are then mapped again using vkMapMemory, 3618cabdff1aSopenharmony_ci * but known implementations return the original pointers when mapped 3619cabdff1aSopenharmony_ci * again. */ 3620cabdff1aSopenharmony_ci if (vkbuf->flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) 3621cabdff1aSopenharmony_ci continue; 3622cabdff1aSopenharmony_ci 3623cabdff1aSopenharmony_ci invalidate_ctx[invalidate_count++] = ival_buf; 3624cabdff1aSopenharmony_ci } 3625cabdff1aSopenharmony_ci 3626cabdff1aSopenharmony_ci if (invalidate_count) { 3627cabdff1aSopenharmony_ci ret = vk->InvalidateMappedMemoryRanges(hwctx->act_dev, invalidate_count, 3628cabdff1aSopenharmony_ci invalidate_ctx); 3629cabdff1aSopenharmony_ci if (ret != VK_SUCCESS) 3630cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_WARNING, "Failed to invalidate memory: %s\n", 3631cabdff1aSopenharmony_ci vk_ret2str(ret)); 3632cabdff1aSopenharmony_ci } 3633cabdff1aSopenharmony_ci 3634cabdff1aSopenharmony_ci return 0; 3635cabdff1aSopenharmony_ci} 3636cabdff1aSopenharmony_ci 3637cabdff1aSopenharmony_cistatic int unmap_buffers(AVHWDeviceContext *ctx, AVBufferRef **bufs, 3638cabdff1aSopenharmony_ci int nb_buffers, int flush) 3639cabdff1aSopenharmony_ci{ 3640cabdff1aSopenharmony_ci int err = 0; 3641cabdff1aSopenharmony_ci VkResult ret; 3642cabdff1aSopenharmony_ci AVVulkanDeviceContext *hwctx = ctx->hwctx; 3643cabdff1aSopenharmony_ci VulkanDevicePriv *p = ctx->internal->priv; 3644cabdff1aSopenharmony_ci FFVulkanFunctions *vk = &p->vkfn; 3645cabdff1aSopenharmony_ci VkMappedMemoryRange flush_ctx[AV_NUM_DATA_POINTERS]; 3646cabdff1aSopenharmony_ci int flush_count = 0; 3647cabdff1aSopenharmony_ci 3648cabdff1aSopenharmony_ci if (flush) { 3649cabdff1aSopenharmony_ci for (int i = 0; i < nb_buffers; i++) { 3650cabdff1aSopenharmony_ci ImageBuffer *vkbuf = (ImageBuffer *)bufs[i]->data; 3651cabdff1aSopenharmony_ci const VkMappedMemoryRange flush_buf = { 3652cabdff1aSopenharmony_ci .sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, 3653cabdff1aSopenharmony_ci .memory = vkbuf->mem, 3654cabdff1aSopenharmony_ci .size = VK_WHOLE_SIZE, 3655cabdff1aSopenharmony_ci }; 3656cabdff1aSopenharmony_ci 3657cabdff1aSopenharmony_ci if (vkbuf->flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) 3658cabdff1aSopenharmony_ci continue; 3659cabdff1aSopenharmony_ci 3660cabdff1aSopenharmony_ci flush_ctx[flush_count++] = flush_buf; 3661cabdff1aSopenharmony_ci } 3662cabdff1aSopenharmony_ci } 3663cabdff1aSopenharmony_ci 3664cabdff1aSopenharmony_ci if (flush_count) { 3665cabdff1aSopenharmony_ci ret = vk->FlushMappedMemoryRanges(hwctx->act_dev, flush_count, flush_ctx); 3666cabdff1aSopenharmony_ci if (ret != VK_SUCCESS) { 3667cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_ERROR, "Failed to flush memory: %s\n", 3668cabdff1aSopenharmony_ci vk_ret2str(ret)); 3669cabdff1aSopenharmony_ci err = AVERROR_EXTERNAL; /* We still want to try to unmap them */ 3670cabdff1aSopenharmony_ci } 3671cabdff1aSopenharmony_ci } 3672cabdff1aSopenharmony_ci 3673cabdff1aSopenharmony_ci for (int i = 0; i < nb_buffers; i++) { 3674cabdff1aSopenharmony_ci ImageBuffer *vkbuf = (ImageBuffer *)bufs[i]->data; 3675cabdff1aSopenharmony_ci if (vkbuf->mapped_mem) 3676cabdff1aSopenharmony_ci continue; 3677cabdff1aSopenharmony_ci 3678cabdff1aSopenharmony_ci vk->UnmapMemory(hwctx->act_dev, vkbuf->mem); 3679cabdff1aSopenharmony_ci } 3680cabdff1aSopenharmony_ci 3681cabdff1aSopenharmony_ci return err; 3682cabdff1aSopenharmony_ci} 3683cabdff1aSopenharmony_ci 3684cabdff1aSopenharmony_cistatic int transfer_image_buf(AVHWFramesContext *hwfc, const AVFrame *f, 3685cabdff1aSopenharmony_ci AVBufferRef **bufs, size_t *buf_offsets, 3686cabdff1aSopenharmony_ci const int *buf_stride, int w, 3687cabdff1aSopenharmony_ci int h, enum AVPixelFormat pix_fmt, int to_buf) 3688cabdff1aSopenharmony_ci{ 3689cabdff1aSopenharmony_ci int err; 3690cabdff1aSopenharmony_ci AVVkFrame *frame = (AVVkFrame *)f->data[0]; 3691cabdff1aSopenharmony_ci VulkanFramesPriv *fp = hwfc->internal->priv; 3692cabdff1aSopenharmony_ci VulkanDevicePriv *p = hwfc->device_ctx->internal->priv; 3693cabdff1aSopenharmony_ci FFVulkanFunctions *vk = &p->vkfn; 3694cabdff1aSopenharmony_ci 3695cabdff1aSopenharmony_ci int bar_num = 0; 3696cabdff1aSopenharmony_ci VkPipelineStageFlagBits sem_wait_dst[AV_NUM_DATA_POINTERS]; 3697cabdff1aSopenharmony_ci 3698cabdff1aSopenharmony_ci const int planes = av_pix_fmt_count_planes(pix_fmt); 3699cabdff1aSopenharmony_ci const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); 3700cabdff1aSopenharmony_ci 3701cabdff1aSopenharmony_ci VkImageMemoryBarrier img_bar[AV_NUM_DATA_POINTERS] = { 0 }; 3702cabdff1aSopenharmony_ci VulkanExecCtx *ectx = to_buf ? &fp->download_ctx : &fp->upload_ctx; 3703cabdff1aSopenharmony_ci VkCommandBuffer cmd_buf = get_buf_exec_ctx(hwfc, ectx); 3704cabdff1aSopenharmony_ci 3705cabdff1aSopenharmony_ci uint64_t sem_signal_values[AV_NUM_DATA_POINTERS]; 3706cabdff1aSopenharmony_ci 3707cabdff1aSopenharmony_ci VkTimelineSemaphoreSubmitInfo s_timeline_sem_info = { 3708cabdff1aSopenharmony_ci .sType = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO, 3709cabdff1aSopenharmony_ci .pWaitSemaphoreValues = frame->sem_value, 3710cabdff1aSopenharmony_ci .pSignalSemaphoreValues = sem_signal_values, 3711cabdff1aSopenharmony_ci .waitSemaphoreValueCount = planes, 3712cabdff1aSopenharmony_ci .signalSemaphoreValueCount = planes, 3713cabdff1aSopenharmony_ci }; 3714cabdff1aSopenharmony_ci 3715cabdff1aSopenharmony_ci VkSubmitInfo s_info = { 3716cabdff1aSopenharmony_ci .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, 3717cabdff1aSopenharmony_ci .pNext = &s_timeline_sem_info, 3718cabdff1aSopenharmony_ci .pSignalSemaphores = frame->sem, 3719cabdff1aSopenharmony_ci .pWaitSemaphores = frame->sem, 3720cabdff1aSopenharmony_ci .pWaitDstStageMask = sem_wait_dst, 3721cabdff1aSopenharmony_ci .signalSemaphoreCount = planes, 3722cabdff1aSopenharmony_ci .waitSemaphoreCount = planes, 3723cabdff1aSopenharmony_ci }; 3724cabdff1aSopenharmony_ci 3725cabdff1aSopenharmony_ci for (int i = 0; i < planes; i++) 3726cabdff1aSopenharmony_ci sem_signal_values[i] = frame->sem_value[i] + 1; 3727cabdff1aSopenharmony_ci 3728cabdff1aSopenharmony_ci if ((err = wait_start_exec_ctx(hwfc, ectx))) 3729cabdff1aSopenharmony_ci return err; 3730cabdff1aSopenharmony_ci 3731cabdff1aSopenharmony_ci /* Change the image layout to something more optimal for transfers */ 3732cabdff1aSopenharmony_ci for (int i = 0; i < planes; i++) { 3733cabdff1aSopenharmony_ci VkImageLayout new_layout = to_buf ? VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL : 3734cabdff1aSopenharmony_ci VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; 3735cabdff1aSopenharmony_ci VkAccessFlags new_access = to_buf ? VK_ACCESS_TRANSFER_READ_BIT : 3736cabdff1aSopenharmony_ci VK_ACCESS_TRANSFER_WRITE_BIT; 3737cabdff1aSopenharmony_ci 3738cabdff1aSopenharmony_ci sem_wait_dst[i] = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; 3739cabdff1aSopenharmony_ci 3740cabdff1aSopenharmony_ci /* If the layout matches and we have read access skip the barrier */ 3741cabdff1aSopenharmony_ci if ((frame->layout[i] == new_layout) && (frame->access[i] & new_access)) 3742cabdff1aSopenharmony_ci continue; 3743cabdff1aSopenharmony_ci 3744cabdff1aSopenharmony_ci img_bar[bar_num].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; 3745cabdff1aSopenharmony_ci img_bar[bar_num].srcAccessMask = 0x0; 3746cabdff1aSopenharmony_ci img_bar[bar_num].dstAccessMask = new_access; 3747cabdff1aSopenharmony_ci img_bar[bar_num].oldLayout = frame->layout[i]; 3748cabdff1aSopenharmony_ci img_bar[bar_num].newLayout = new_layout; 3749cabdff1aSopenharmony_ci img_bar[bar_num].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; 3750cabdff1aSopenharmony_ci img_bar[bar_num].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; 3751cabdff1aSopenharmony_ci img_bar[bar_num].image = frame->img[i]; 3752cabdff1aSopenharmony_ci img_bar[bar_num].subresourceRange.levelCount = 1; 3753cabdff1aSopenharmony_ci img_bar[bar_num].subresourceRange.layerCount = 1; 3754cabdff1aSopenharmony_ci img_bar[bar_num].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; 3755cabdff1aSopenharmony_ci 3756cabdff1aSopenharmony_ci frame->layout[i] = img_bar[bar_num].newLayout; 3757cabdff1aSopenharmony_ci frame->access[i] = img_bar[bar_num].dstAccessMask; 3758cabdff1aSopenharmony_ci 3759cabdff1aSopenharmony_ci bar_num++; 3760cabdff1aSopenharmony_ci } 3761cabdff1aSopenharmony_ci 3762cabdff1aSopenharmony_ci if (bar_num) 3763cabdff1aSopenharmony_ci vk->CmdPipelineBarrier(cmd_buf, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 3764cabdff1aSopenharmony_ci VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 3765cabdff1aSopenharmony_ci 0, NULL, 0, NULL, bar_num, img_bar); 3766cabdff1aSopenharmony_ci 3767cabdff1aSopenharmony_ci /* Schedule a copy for each plane */ 3768cabdff1aSopenharmony_ci for (int i = 0; i < planes; i++) { 3769cabdff1aSopenharmony_ci ImageBuffer *vkbuf = (ImageBuffer *)bufs[i]->data; 3770cabdff1aSopenharmony_ci VkBufferImageCopy buf_reg = { 3771cabdff1aSopenharmony_ci .bufferOffset = buf_offsets[i], 3772cabdff1aSopenharmony_ci .bufferRowLength = buf_stride[i] / desc->comp[i].step, 3773cabdff1aSopenharmony_ci .imageSubresource.layerCount = 1, 3774cabdff1aSopenharmony_ci .imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, 3775cabdff1aSopenharmony_ci .imageOffset = { 0, 0, 0, }, 3776cabdff1aSopenharmony_ci }; 3777cabdff1aSopenharmony_ci 3778cabdff1aSopenharmony_ci int p_w, p_h; 3779cabdff1aSopenharmony_ci get_plane_wh(&p_w, &p_h, pix_fmt, w, h, i); 3780cabdff1aSopenharmony_ci 3781cabdff1aSopenharmony_ci buf_reg.bufferImageHeight = p_h; 3782cabdff1aSopenharmony_ci buf_reg.imageExtent = (VkExtent3D){ p_w, p_h, 1, }; 3783cabdff1aSopenharmony_ci 3784cabdff1aSopenharmony_ci if (to_buf) 3785cabdff1aSopenharmony_ci vk->CmdCopyImageToBuffer(cmd_buf, frame->img[i], frame->layout[i], 3786cabdff1aSopenharmony_ci vkbuf->buf, 1, &buf_reg); 3787cabdff1aSopenharmony_ci else 3788cabdff1aSopenharmony_ci vk->CmdCopyBufferToImage(cmd_buf, vkbuf->buf, frame->img[i], 3789cabdff1aSopenharmony_ci frame->layout[i], 1, &buf_reg); 3790cabdff1aSopenharmony_ci } 3791cabdff1aSopenharmony_ci 3792cabdff1aSopenharmony_ci /* When uploading, do this asynchronously if the source is refcounted by 3793cabdff1aSopenharmony_ci * keeping the buffers as a submission dependency. 3794cabdff1aSopenharmony_ci * The hwcontext is guaranteed to not be freed until all frames are freed 3795cabdff1aSopenharmony_ci * in the frames_unint function. 3796cabdff1aSopenharmony_ci * When downloading to buffer, do this synchronously and wait for the 3797cabdff1aSopenharmony_ci * queue submission to finish executing */ 3798cabdff1aSopenharmony_ci if (!to_buf) { 3799cabdff1aSopenharmony_ci int ref; 3800cabdff1aSopenharmony_ci for (ref = 0; ref < AV_NUM_DATA_POINTERS; ref++) { 3801cabdff1aSopenharmony_ci if (!f->buf[ref]) 3802cabdff1aSopenharmony_ci break; 3803cabdff1aSopenharmony_ci if ((err = add_buf_dep_exec_ctx(hwfc, ectx, &f->buf[ref], 1))) 3804cabdff1aSopenharmony_ci return err; 3805cabdff1aSopenharmony_ci } 3806cabdff1aSopenharmony_ci if (ref && (err = add_buf_dep_exec_ctx(hwfc, ectx, bufs, planes))) 3807cabdff1aSopenharmony_ci return err; 3808cabdff1aSopenharmony_ci return submit_exec_ctx(hwfc, ectx, &s_info, frame, !ref); 3809cabdff1aSopenharmony_ci } else { 3810cabdff1aSopenharmony_ci return submit_exec_ctx(hwfc, ectx, &s_info, frame, 1); 3811cabdff1aSopenharmony_ci } 3812cabdff1aSopenharmony_ci} 3813cabdff1aSopenharmony_ci 3814cabdff1aSopenharmony_cistatic int vulkan_transfer_data(AVHWFramesContext *hwfc, const AVFrame *vkf, 3815cabdff1aSopenharmony_ci const AVFrame *swf, int from) 3816cabdff1aSopenharmony_ci{ 3817cabdff1aSopenharmony_ci int err = 0; 3818cabdff1aSopenharmony_ci VkResult ret; 3819cabdff1aSopenharmony_ci AVVkFrame *f = (AVVkFrame *)vkf->data[0]; 3820cabdff1aSopenharmony_ci AVHWDeviceContext *dev_ctx = hwfc->device_ctx; 3821cabdff1aSopenharmony_ci AVVulkanDeviceContext *hwctx = dev_ctx->hwctx; 3822cabdff1aSopenharmony_ci VulkanDevicePriv *p = hwfc->device_ctx->internal->priv; 3823cabdff1aSopenharmony_ci FFVulkanFunctions *vk = &p->vkfn; 3824cabdff1aSopenharmony_ci 3825cabdff1aSopenharmony_ci AVFrame tmp; 3826cabdff1aSopenharmony_ci AVBufferRef *bufs[AV_NUM_DATA_POINTERS] = { 0 }; 3827cabdff1aSopenharmony_ci size_t buf_offsets[AV_NUM_DATA_POINTERS] = { 0 }; 3828cabdff1aSopenharmony_ci 3829cabdff1aSopenharmony_ci int p_w, p_h; 3830cabdff1aSopenharmony_ci const int planes = av_pix_fmt_count_planes(swf->format); 3831cabdff1aSopenharmony_ci 3832cabdff1aSopenharmony_ci int host_mapped[AV_NUM_DATA_POINTERS] = { 0 }; 3833cabdff1aSopenharmony_ci const int map_host = !!(p->extensions & FF_VK_EXT_EXTERNAL_HOST_MEMORY); 3834cabdff1aSopenharmony_ci 3835cabdff1aSopenharmony_ci if ((swf->format != AV_PIX_FMT_NONE && !av_vkfmt_from_pixfmt(swf->format))) { 3836cabdff1aSopenharmony_ci av_log(hwfc, AV_LOG_ERROR, "Unsupported software frame pixel format!\n"); 3837cabdff1aSopenharmony_ci return AVERROR(EINVAL); 3838cabdff1aSopenharmony_ci } 3839cabdff1aSopenharmony_ci 3840cabdff1aSopenharmony_ci if (swf->width > hwfc->width || swf->height > hwfc->height) 3841cabdff1aSopenharmony_ci return AVERROR(EINVAL); 3842cabdff1aSopenharmony_ci 3843cabdff1aSopenharmony_ci /* For linear, host visiable images */ 3844cabdff1aSopenharmony_ci if (f->tiling == VK_IMAGE_TILING_LINEAR && 3845cabdff1aSopenharmony_ci f->flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) { 3846cabdff1aSopenharmony_ci AVFrame *map = av_frame_alloc(); 3847cabdff1aSopenharmony_ci if (!map) 3848cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 3849cabdff1aSopenharmony_ci map->format = swf->format; 3850cabdff1aSopenharmony_ci 3851cabdff1aSopenharmony_ci err = vulkan_map_frame_to_mem(hwfc, map, vkf, AV_HWFRAME_MAP_WRITE); 3852cabdff1aSopenharmony_ci if (err) 3853cabdff1aSopenharmony_ci return err; 3854cabdff1aSopenharmony_ci 3855cabdff1aSopenharmony_ci err = av_frame_copy((AVFrame *)(from ? swf : map), from ? map : swf); 3856cabdff1aSopenharmony_ci av_frame_free(&map); 3857cabdff1aSopenharmony_ci return err; 3858cabdff1aSopenharmony_ci } 3859cabdff1aSopenharmony_ci 3860cabdff1aSopenharmony_ci /* Create buffers */ 3861cabdff1aSopenharmony_ci for (int i = 0; i < planes; i++) { 3862cabdff1aSopenharmony_ci size_t req_size; 3863cabdff1aSopenharmony_ci 3864cabdff1aSopenharmony_ci VkExternalMemoryBufferCreateInfo create_desc = { 3865cabdff1aSopenharmony_ci .sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO, 3866cabdff1aSopenharmony_ci .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT, 3867cabdff1aSopenharmony_ci }; 3868cabdff1aSopenharmony_ci 3869cabdff1aSopenharmony_ci VkImportMemoryHostPointerInfoEXT import_desc = { 3870cabdff1aSopenharmony_ci .sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT, 3871cabdff1aSopenharmony_ci .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT, 3872cabdff1aSopenharmony_ci }; 3873cabdff1aSopenharmony_ci 3874cabdff1aSopenharmony_ci VkMemoryHostPointerPropertiesEXT p_props = { 3875cabdff1aSopenharmony_ci .sType = VK_STRUCTURE_TYPE_MEMORY_HOST_POINTER_PROPERTIES_EXT, 3876cabdff1aSopenharmony_ci }; 3877cabdff1aSopenharmony_ci 3878cabdff1aSopenharmony_ci get_plane_wh(&p_w, &p_h, swf->format, swf->width, swf->height, i); 3879cabdff1aSopenharmony_ci 3880cabdff1aSopenharmony_ci tmp.linesize[i] = FFABS(swf->linesize[i]); 3881cabdff1aSopenharmony_ci 3882cabdff1aSopenharmony_ci /* Do not map images with a negative stride */ 3883cabdff1aSopenharmony_ci if (map_host && swf->linesize[i] > 0) { 3884cabdff1aSopenharmony_ci size_t offs; 3885cabdff1aSopenharmony_ci offs = (uintptr_t)swf->data[i] % p->hprops.minImportedHostPointerAlignment; 3886cabdff1aSopenharmony_ci import_desc.pHostPointer = swf->data[i] - offs; 3887cabdff1aSopenharmony_ci 3888cabdff1aSopenharmony_ci /* We have to compensate for the few extra bytes of padding we 3889cabdff1aSopenharmony_ci * completely ignore at the start */ 3890cabdff1aSopenharmony_ci req_size = FFALIGN(offs + tmp.linesize[i] * p_h, 3891cabdff1aSopenharmony_ci p->hprops.minImportedHostPointerAlignment); 3892cabdff1aSopenharmony_ci 3893cabdff1aSopenharmony_ci ret = vk->GetMemoryHostPointerPropertiesEXT(hwctx->act_dev, 3894cabdff1aSopenharmony_ci import_desc.handleType, 3895cabdff1aSopenharmony_ci import_desc.pHostPointer, 3896cabdff1aSopenharmony_ci &p_props); 3897cabdff1aSopenharmony_ci 3898cabdff1aSopenharmony_ci if (ret == VK_SUCCESS) { 3899cabdff1aSopenharmony_ci host_mapped[i] = 1; 3900cabdff1aSopenharmony_ci buf_offsets[i] = offs; 3901cabdff1aSopenharmony_ci } 3902cabdff1aSopenharmony_ci } 3903cabdff1aSopenharmony_ci 3904cabdff1aSopenharmony_ci if (!host_mapped[i]) 3905cabdff1aSopenharmony_ci req_size = get_req_buffer_size(p, &tmp.linesize[i], p_h); 3906cabdff1aSopenharmony_ci 3907cabdff1aSopenharmony_ci err = create_buf(dev_ctx, &bufs[i], 3908cabdff1aSopenharmony_ci from ? VK_BUFFER_USAGE_TRANSFER_DST_BIT : 3909cabdff1aSopenharmony_ci VK_BUFFER_USAGE_TRANSFER_SRC_BIT, 3910cabdff1aSopenharmony_ci VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, 3911cabdff1aSopenharmony_ci req_size, p_props.memoryTypeBits, host_mapped[i], 3912cabdff1aSopenharmony_ci host_mapped[i] ? &create_desc : NULL, 3913cabdff1aSopenharmony_ci host_mapped[i] ? &import_desc : NULL); 3914cabdff1aSopenharmony_ci if (err) 3915cabdff1aSopenharmony_ci goto end; 3916cabdff1aSopenharmony_ci } 3917cabdff1aSopenharmony_ci 3918cabdff1aSopenharmony_ci if (!from) { 3919cabdff1aSopenharmony_ci /* Map, copy image TO buffer (which then goes to the VkImage), unmap */ 3920cabdff1aSopenharmony_ci if ((err = map_buffers(dev_ctx, bufs, tmp.data, planes, 0))) 3921cabdff1aSopenharmony_ci goto end; 3922cabdff1aSopenharmony_ci 3923cabdff1aSopenharmony_ci for (int i = 0; i < planes; i++) { 3924cabdff1aSopenharmony_ci if (host_mapped[i]) 3925cabdff1aSopenharmony_ci continue; 3926cabdff1aSopenharmony_ci 3927cabdff1aSopenharmony_ci get_plane_wh(&p_w, &p_h, swf->format, swf->width, swf->height, i); 3928cabdff1aSopenharmony_ci 3929cabdff1aSopenharmony_ci av_image_copy_plane(tmp.data[i], tmp.linesize[i], 3930cabdff1aSopenharmony_ci (const uint8_t *)swf->data[i], swf->linesize[i], 3931cabdff1aSopenharmony_ci FFMIN(tmp.linesize[i], FFABS(swf->linesize[i])), 3932cabdff1aSopenharmony_ci p_h); 3933cabdff1aSopenharmony_ci } 3934cabdff1aSopenharmony_ci 3935cabdff1aSopenharmony_ci if ((err = unmap_buffers(dev_ctx, bufs, planes, 1))) 3936cabdff1aSopenharmony_ci goto end; 3937cabdff1aSopenharmony_ci } 3938cabdff1aSopenharmony_ci 3939cabdff1aSopenharmony_ci /* Copy buffers into/from image */ 3940cabdff1aSopenharmony_ci err = transfer_image_buf(hwfc, vkf, bufs, buf_offsets, tmp.linesize, 3941cabdff1aSopenharmony_ci swf->width, swf->height, swf->format, from); 3942cabdff1aSopenharmony_ci 3943cabdff1aSopenharmony_ci if (from) { 3944cabdff1aSopenharmony_ci /* Map, copy buffer (which came FROM the VkImage) to the frame, unmap */ 3945cabdff1aSopenharmony_ci if ((err = map_buffers(dev_ctx, bufs, tmp.data, planes, 0))) 3946cabdff1aSopenharmony_ci goto end; 3947cabdff1aSopenharmony_ci 3948cabdff1aSopenharmony_ci for (int i = 0; i < planes; i++) { 3949cabdff1aSopenharmony_ci if (host_mapped[i]) 3950cabdff1aSopenharmony_ci continue; 3951cabdff1aSopenharmony_ci 3952cabdff1aSopenharmony_ci get_plane_wh(&p_w, &p_h, swf->format, swf->width, swf->height, i); 3953cabdff1aSopenharmony_ci 3954cabdff1aSopenharmony_ci av_image_copy_plane_uc_from(swf->data[i], swf->linesize[i], 3955cabdff1aSopenharmony_ci (const uint8_t *)tmp.data[i], tmp.linesize[i], 3956cabdff1aSopenharmony_ci FFMIN(tmp.linesize[i], FFABS(swf->linesize[i])), 3957cabdff1aSopenharmony_ci p_h); 3958cabdff1aSopenharmony_ci } 3959cabdff1aSopenharmony_ci 3960cabdff1aSopenharmony_ci if ((err = unmap_buffers(dev_ctx, bufs, planes, 1))) 3961cabdff1aSopenharmony_ci goto end; 3962cabdff1aSopenharmony_ci } 3963cabdff1aSopenharmony_ci 3964cabdff1aSopenharmony_ciend: 3965cabdff1aSopenharmony_ci for (int i = 0; i < planes; i++) 3966cabdff1aSopenharmony_ci av_buffer_unref(&bufs[i]); 3967cabdff1aSopenharmony_ci 3968cabdff1aSopenharmony_ci return err; 3969cabdff1aSopenharmony_ci} 3970cabdff1aSopenharmony_ci 3971cabdff1aSopenharmony_cistatic int vulkan_transfer_data_to(AVHWFramesContext *hwfc, AVFrame *dst, 3972cabdff1aSopenharmony_ci const AVFrame *src) 3973cabdff1aSopenharmony_ci{ 3974cabdff1aSopenharmony_ci av_unused VulkanDevicePriv *p = hwfc->device_ctx->internal->priv; 3975cabdff1aSopenharmony_ci 3976cabdff1aSopenharmony_ci switch (src->format) { 3977cabdff1aSopenharmony_ci#if CONFIG_CUDA 3978cabdff1aSopenharmony_ci case AV_PIX_FMT_CUDA: 3979cabdff1aSopenharmony_ci#ifdef _WIN32 3980cabdff1aSopenharmony_ci if ((p->extensions & FF_VK_EXT_EXTERNAL_WIN32_MEMORY) && 3981cabdff1aSopenharmony_ci (p->extensions & FF_VK_EXT_EXTERNAL_WIN32_SEM)) 3982cabdff1aSopenharmony_ci#else 3983cabdff1aSopenharmony_ci if ((p->extensions & FF_VK_EXT_EXTERNAL_FD_MEMORY) && 3984cabdff1aSopenharmony_ci (p->extensions & FF_VK_EXT_EXTERNAL_FD_SEM)) 3985cabdff1aSopenharmony_ci#endif 3986cabdff1aSopenharmony_ci return vulkan_transfer_data_from_cuda(hwfc, dst, src); 3987cabdff1aSopenharmony_ci#endif 3988cabdff1aSopenharmony_ci default: 3989cabdff1aSopenharmony_ci if (src->hw_frames_ctx) 3990cabdff1aSopenharmony_ci return AVERROR(ENOSYS); 3991cabdff1aSopenharmony_ci else 3992cabdff1aSopenharmony_ci return vulkan_transfer_data(hwfc, dst, src, 0); 3993cabdff1aSopenharmony_ci } 3994cabdff1aSopenharmony_ci} 3995cabdff1aSopenharmony_ci 3996cabdff1aSopenharmony_ci#if CONFIG_CUDA 3997cabdff1aSopenharmony_cistatic int vulkan_transfer_data_to_cuda(AVHWFramesContext *hwfc, AVFrame *dst, 3998cabdff1aSopenharmony_ci const AVFrame *src) 3999cabdff1aSopenharmony_ci{ 4000cabdff1aSopenharmony_ci int err; 4001cabdff1aSopenharmony_ci CUcontext dummy; 4002cabdff1aSopenharmony_ci AVVkFrame *dst_f; 4003cabdff1aSopenharmony_ci AVVkFrameInternal *dst_int; 4004cabdff1aSopenharmony_ci VulkanFramesPriv *fp = hwfc->internal->priv; 4005cabdff1aSopenharmony_ci const int planes = av_pix_fmt_count_planes(hwfc->sw_format); 4006cabdff1aSopenharmony_ci const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(hwfc->sw_format); 4007cabdff1aSopenharmony_ci 4008cabdff1aSopenharmony_ci AVHWFramesContext *cuda_fc = (AVHWFramesContext*)dst->hw_frames_ctx->data; 4009cabdff1aSopenharmony_ci AVHWDeviceContext *cuda_cu = cuda_fc->device_ctx; 4010cabdff1aSopenharmony_ci AVCUDADeviceContext *cuda_dev = cuda_cu->hwctx; 4011cabdff1aSopenharmony_ci AVCUDADeviceContextInternal *cu_internal = cuda_dev->internal; 4012cabdff1aSopenharmony_ci CudaFunctions *cu = cu_internal->cuda_dl; 4013cabdff1aSopenharmony_ci CUDA_EXTERNAL_SEMAPHORE_WAIT_PARAMS s_w_par[AV_NUM_DATA_POINTERS] = { 0 }; 4014cabdff1aSopenharmony_ci CUDA_EXTERNAL_SEMAPHORE_SIGNAL_PARAMS s_s_par[AV_NUM_DATA_POINTERS] = { 0 }; 4015cabdff1aSopenharmony_ci 4016cabdff1aSopenharmony_ci dst_f = (AVVkFrame *)src->data[0]; 4017cabdff1aSopenharmony_ci 4018cabdff1aSopenharmony_ci err = prepare_frame(hwfc, &fp->upload_ctx, dst_f, PREP_MODE_EXTERNAL_EXPORT); 4019cabdff1aSopenharmony_ci if (err < 0) 4020cabdff1aSopenharmony_ci return err; 4021cabdff1aSopenharmony_ci 4022cabdff1aSopenharmony_ci err = CHECK_CU(cu->cuCtxPushCurrent(cuda_dev->cuda_ctx)); 4023cabdff1aSopenharmony_ci if (err < 0) 4024cabdff1aSopenharmony_ci return err; 4025cabdff1aSopenharmony_ci 4026cabdff1aSopenharmony_ci err = vulkan_export_to_cuda(hwfc, dst->hw_frames_ctx, src); 4027cabdff1aSopenharmony_ci if (err < 0) { 4028cabdff1aSopenharmony_ci CHECK_CU(cu->cuCtxPopCurrent(&dummy)); 4029cabdff1aSopenharmony_ci return err; 4030cabdff1aSopenharmony_ci } 4031cabdff1aSopenharmony_ci 4032cabdff1aSopenharmony_ci dst_int = dst_f->internal; 4033cabdff1aSopenharmony_ci 4034cabdff1aSopenharmony_ci for (int i = 0; i < planes; i++) { 4035cabdff1aSopenharmony_ci s_w_par[i].params.fence.value = dst_f->sem_value[i] + 0; 4036cabdff1aSopenharmony_ci s_s_par[i].params.fence.value = dst_f->sem_value[i] + 1; 4037cabdff1aSopenharmony_ci } 4038cabdff1aSopenharmony_ci 4039cabdff1aSopenharmony_ci err = CHECK_CU(cu->cuWaitExternalSemaphoresAsync(dst_int->cu_sem, s_w_par, 4040cabdff1aSopenharmony_ci planes, cuda_dev->stream)); 4041cabdff1aSopenharmony_ci if (err < 0) 4042cabdff1aSopenharmony_ci goto fail; 4043cabdff1aSopenharmony_ci 4044cabdff1aSopenharmony_ci for (int i = 0; i < planes; i++) { 4045cabdff1aSopenharmony_ci CUDA_MEMCPY2D cpy = { 4046cabdff1aSopenharmony_ci .dstMemoryType = CU_MEMORYTYPE_DEVICE, 4047cabdff1aSopenharmony_ci .dstDevice = (CUdeviceptr)dst->data[i], 4048cabdff1aSopenharmony_ci .dstPitch = dst->linesize[i], 4049cabdff1aSopenharmony_ci .dstY = 0, 4050cabdff1aSopenharmony_ci 4051cabdff1aSopenharmony_ci .srcMemoryType = CU_MEMORYTYPE_ARRAY, 4052cabdff1aSopenharmony_ci .srcArray = dst_int->cu_array[i], 4053cabdff1aSopenharmony_ci }; 4054cabdff1aSopenharmony_ci 4055cabdff1aSopenharmony_ci int w, h; 4056cabdff1aSopenharmony_ci get_plane_wh(&w, &h, hwfc->sw_format, hwfc->width, hwfc->height, i); 4057cabdff1aSopenharmony_ci 4058cabdff1aSopenharmony_ci cpy.WidthInBytes = w * desc->comp[i].step; 4059cabdff1aSopenharmony_ci cpy.Height = h; 4060cabdff1aSopenharmony_ci 4061cabdff1aSopenharmony_ci err = CHECK_CU(cu->cuMemcpy2DAsync(&cpy, cuda_dev->stream)); 4062cabdff1aSopenharmony_ci if (err < 0) 4063cabdff1aSopenharmony_ci goto fail; 4064cabdff1aSopenharmony_ci } 4065cabdff1aSopenharmony_ci 4066cabdff1aSopenharmony_ci err = CHECK_CU(cu->cuSignalExternalSemaphoresAsync(dst_int->cu_sem, s_s_par, 4067cabdff1aSopenharmony_ci planes, cuda_dev->stream)); 4068cabdff1aSopenharmony_ci if (err < 0) 4069cabdff1aSopenharmony_ci goto fail; 4070cabdff1aSopenharmony_ci 4071cabdff1aSopenharmony_ci for (int i = 0; i < planes; i++) 4072cabdff1aSopenharmony_ci dst_f->sem_value[i]++; 4073cabdff1aSopenharmony_ci 4074cabdff1aSopenharmony_ci CHECK_CU(cu->cuCtxPopCurrent(&dummy)); 4075cabdff1aSopenharmony_ci 4076cabdff1aSopenharmony_ci av_log(hwfc, AV_LOG_VERBOSE, "Transfered Vulkan image to CUDA!\n"); 4077cabdff1aSopenharmony_ci 4078cabdff1aSopenharmony_ci return prepare_frame(hwfc, &fp->upload_ctx, dst_f, PREP_MODE_EXTERNAL_IMPORT); 4079cabdff1aSopenharmony_ci 4080cabdff1aSopenharmony_cifail: 4081cabdff1aSopenharmony_ci CHECK_CU(cu->cuCtxPopCurrent(&dummy)); 4082cabdff1aSopenharmony_ci vulkan_free_internal(dst_f); 4083cabdff1aSopenharmony_ci dst_f->internal = NULL; 4084cabdff1aSopenharmony_ci av_buffer_unref(&dst->buf[0]); 4085cabdff1aSopenharmony_ci return err; 4086cabdff1aSopenharmony_ci} 4087cabdff1aSopenharmony_ci#endif 4088cabdff1aSopenharmony_ci 4089cabdff1aSopenharmony_cistatic int vulkan_transfer_data_from(AVHWFramesContext *hwfc, AVFrame *dst, 4090cabdff1aSopenharmony_ci const AVFrame *src) 4091cabdff1aSopenharmony_ci{ 4092cabdff1aSopenharmony_ci av_unused VulkanDevicePriv *p = hwfc->device_ctx->internal->priv; 4093cabdff1aSopenharmony_ci 4094cabdff1aSopenharmony_ci switch (dst->format) { 4095cabdff1aSopenharmony_ci#if CONFIG_CUDA 4096cabdff1aSopenharmony_ci case AV_PIX_FMT_CUDA: 4097cabdff1aSopenharmony_ci#ifdef _WIN32 4098cabdff1aSopenharmony_ci if ((p->extensions & FF_VK_EXT_EXTERNAL_WIN32_MEMORY) && 4099cabdff1aSopenharmony_ci (p->extensions & FF_VK_EXT_EXTERNAL_WIN32_SEM)) 4100cabdff1aSopenharmony_ci#else 4101cabdff1aSopenharmony_ci if ((p->extensions & FF_VK_EXT_EXTERNAL_FD_MEMORY) && 4102cabdff1aSopenharmony_ci (p->extensions & FF_VK_EXT_EXTERNAL_FD_SEM)) 4103cabdff1aSopenharmony_ci#endif 4104cabdff1aSopenharmony_ci return vulkan_transfer_data_to_cuda(hwfc, dst, src); 4105cabdff1aSopenharmony_ci#endif 4106cabdff1aSopenharmony_ci default: 4107cabdff1aSopenharmony_ci if (dst->hw_frames_ctx) 4108cabdff1aSopenharmony_ci return AVERROR(ENOSYS); 4109cabdff1aSopenharmony_ci else 4110cabdff1aSopenharmony_ci return vulkan_transfer_data(hwfc, src, dst, 1); 4111cabdff1aSopenharmony_ci } 4112cabdff1aSopenharmony_ci} 4113cabdff1aSopenharmony_ci 4114cabdff1aSopenharmony_cistatic int vulkan_frames_derive_to(AVHWFramesContext *dst_fc, 4115cabdff1aSopenharmony_ci AVHWFramesContext *src_fc, int flags) 4116cabdff1aSopenharmony_ci{ 4117cabdff1aSopenharmony_ci return vulkan_frames_init(dst_fc); 4118cabdff1aSopenharmony_ci} 4119cabdff1aSopenharmony_ci 4120cabdff1aSopenharmony_ciAVVkFrame *av_vk_frame_alloc(void) 4121cabdff1aSopenharmony_ci{ 4122cabdff1aSopenharmony_ci return av_mallocz(sizeof(AVVkFrame)); 4123cabdff1aSopenharmony_ci} 4124cabdff1aSopenharmony_ci 4125cabdff1aSopenharmony_ciconst HWContextType ff_hwcontext_type_vulkan = { 4126cabdff1aSopenharmony_ci .type = AV_HWDEVICE_TYPE_VULKAN, 4127cabdff1aSopenharmony_ci .name = "Vulkan", 4128cabdff1aSopenharmony_ci 4129cabdff1aSopenharmony_ci .device_hwctx_size = sizeof(AVVulkanDeviceContext), 4130cabdff1aSopenharmony_ci .device_priv_size = sizeof(VulkanDevicePriv), 4131cabdff1aSopenharmony_ci .frames_hwctx_size = sizeof(AVVulkanFramesContext), 4132cabdff1aSopenharmony_ci .frames_priv_size = sizeof(VulkanFramesPriv), 4133cabdff1aSopenharmony_ci 4134cabdff1aSopenharmony_ci .device_init = &vulkan_device_init, 4135cabdff1aSopenharmony_ci .device_create = &vulkan_device_create, 4136cabdff1aSopenharmony_ci .device_derive = &vulkan_device_derive, 4137cabdff1aSopenharmony_ci 4138cabdff1aSopenharmony_ci .frames_get_constraints = &vulkan_frames_get_constraints, 4139cabdff1aSopenharmony_ci .frames_init = vulkan_frames_init, 4140cabdff1aSopenharmony_ci .frames_get_buffer = vulkan_get_buffer, 4141cabdff1aSopenharmony_ci .frames_uninit = vulkan_frames_uninit, 4142cabdff1aSopenharmony_ci 4143cabdff1aSopenharmony_ci .transfer_get_formats = vulkan_transfer_get_formats, 4144cabdff1aSopenharmony_ci .transfer_data_to = vulkan_transfer_data_to, 4145cabdff1aSopenharmony_ci .transfer_data_from = vulkan_transfer_data_from, 4146cabdff1aSopenharmony_ci 4147cabdff1aSopenharmony_ci .map_to = vulkan_map_to, 4148cabdff1aSopenharmony_ci .map_from = vulkan_map_from, 4149cabdff1aSopenharmony_ci .frames_derive_to = &vulkan_frames_derive_to, 4150cabdff1aSopenharmony_ci 4151cabdff1aSopenharmony_ci .pix_fmts = (const enum AVPixelFormat []) { 4152cabdff1aSopenharmony_ci AV_PIX_FMT_VULKAN, 4153cabdff1aSopenharmony_ci AV_PIX_FMT_NONE 4154cabdff1aSopenharmony_ci }, 4155cabdff1aSopenharmony_ci}; 4156