2 * This file is part of FFmpeg.
4 * FFmpeg is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * FFmpeg is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with FFmpeg; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 #define VK_NO_PROTOTYPES
20 #define VK_ENABLE_BETA_EXTENSIONS
23 #include <windows.h> /* Included to prevent conflicts with CreateSemaphore */
24 #include <versionhelpers.h>
25 #include "compat/w32dlfcn.h"
36 #include "hwcontext.h"
38 #include "hwcontext_internal.h"
39 #include "hwcontext_vulkan.h"
42 #include "vulkan_loader.h"
46 #include <drm_fourcc.h>
47 #include "hwcontext_drm.h"
49 #include <va/va_drmcommon.h>
50 #include "hwcontext_vaapi.h"
55 #include "hwcontext_cuda_internal.h"
56 #include "cuda_check.h"
57 #define CHECK_CU(x) FF_CUDA_CHECK_DL(cuda_cu, cu, x)
60 typedef struct VulkanQueueCtx
{
65 /* Buffer dependencies */
66 AVBufferRef
**buf_deps
;
68 int buf_deps_alloc_size
;
71 typedef struct VulkanExecCtx
{
73 VkCommandBuffer
*bufs
;
74 VulkanQueueCtx
*queues
;
79 typedef struct VulkanDevicePriv
{
80 /* Vulkan library and loader functions */
82 FFVulkanFunctions vkfn
;
85 VkPhysicalDeviceProperties2 props
;
86 VkPhysicalDeviceMemoryProperties mprops
;
87 VkPhysicalDeviceExternalMemoryHostPropertiesEXT hprops
;
90 VkPhysicalDeviceVulkan11Features device_features_1_1
;
91 VkPhysicalDeviceVulkan12Features device_features_1_2
;
98 VkDebugUtilsMessengerEXT debug_ctx
;
101 FFVulkanExtensions extensions
;
104 int use_linear_images
;
106 /* Option to allocate all image planes in a single allocation */
107 int contiguous_planes
;
116 typedef struct VulkanFramesPriv
{
117 /* Image conversions */
118 VulkanExecCtx conv_ctx
;
120 /* Image transfers */
121 VulkanExecCtx upload_ctx
;
122 VulkanExecCtx download_ctx
;
124 /* Modifier info list to free at uninit */
125 VkImageDrmFormatModifierListCreateInfoEXT
*modifier_info
;
128 typedef struct AVVkFrameInternal
{
130 /* Importing external memory into cuda is really expensive so we keep the
131 * memory imported all the time */
132 AVBufferRef
*cuda_fc_ref
; /* Need to keep it around for uninit */
133 CUexternalMemory ext_mem
[AV_NUM_DATA_POINTERS
];
134 CUmipmappedArray cu_mma
[AV_NUM_DATA_POINTERS
];
135 CUarray cu_array
[AV_NUM_DATA_POINTERS
];
136 CUexternalSemaphore cu_sem
[AV_NUM_DATA_POINTERS
];
138 HANDLE ext_mem_handle
[AV_NUM_DATA_POINTERS
];
139 HANDLE ext_sem_handle
[AV_NUM_DATA_POINTERS
];
144 #define ADD_VAL_TO_LIST(list, count, val) \
146 list = av_realloc_array(list, sizeof(*list), ++count); \
148 err = AVERROR(ENOMEM); \
151 list[count - 1] = av_strdup(val); \
152 if (!list[count - 1]) { \
153 err = AVERROR(ENOMEM); \
158 #define RELEASE_PROPS(props, count) \
160 for (int i = 0; i < count; i++) \
161 av_free((void *)((props)[i])); \
162 av_free((void *)props); \
165 static const struct {
166 enum AVPixelFormat pixfmt
;
167 const VkFormat vkfmts
[4];
168 } vk_pixfmt_map
[] = {
169 { AV_PIX_FMT_GRAY8
, { VK_FORMAT_R8_UNORM
} },
170 { AV_PIX_FMT_GRAY16
, { VK_FORMAT_R16_UNORM
} },
171 { AV_PIX_FMT_GRAYF32
, { VK_FORMAT_R32_SFLOAT
} },
173 { AV_PIX_FMT_NV12
, { VK_FORMAT_R8_UNORM
, VK_FORMAT_R8G8_UNORM
} },
174 { AV_PIX_FMT_NV21
, { VK_FORMAT_R8_UNORM
, VK_FORMAT_R8G8_UNORM
} },
175 { AV_PIX_FMT_P010
, { VK_FORMAT_R16_UNORM
, VK_FORMAT_R16G16_UNORM
} },
176 { AV_PIX_FMT_P016
, { VK_FORMAT_R16_UNORM
, VK_FORMAT_R16G16_UNORM
} },
178 { AV_PIX_FMT_NV16
, { VK_FORMAT_R8_UNORM
, VK_FORMAT_R8G8_UNORM
} },
180 { AV_PIX_FMT_NV24
, { VK_FORMAT_R8_UNORM
, VK_FORMAT_R8G8_UNORM
} },
181 { AV_PIX_FMT_NV42
, { VK_FORMAT_R8_UNORM
, VK_FORMAT_R8G8_UNORM
} },
183 { AV_PIX_FMT_YUV420P
, { VK_FORMAT_R8_UNORM
, VK_FORMAT_R8_UNORM
, VK_FORMAT_R8_UNORM
} },
184 { AV_PIX_FMT_YUV420P10
, { VK_FORMAT_R16_UNORM
, VK_FORMAT_R16_UNORM
, VK_FORMAT_R16_UNORM
} },
185 { AV_PIX_FMT_YUV420P12
, { VK_FORMAT_R16_UNORM
, VK_FORMAT_R16_UNORM
, VK_FORMAT_R16_UNORM
} },
186 { AV_PIX_FMT_YUV420P16
, { VK_FORMAT_R16_UNORM
, VK_FORMAT_R16_UNORM
, VK_FORMAT_R16_UNORM
} },
188 { AV_PIX_FMT_YUV422P
, { VK_FORMAT_R8_UNORM
, VK_FORMAT_R8_UNORM
, VK_FORMAT_R8_UNORM
} },
189 { AV_PIX_FMT_YUV422P10
, { VK_FORMAT_R16_UNORM
, VK_FORMAT_R16_UNORM
, VK_FORMAT_R16_UNORM
} },
190 { AV_PIX_FMT_YUV422P12
, { VK_FORMAT_R16_UNORM
, VK_FORMAT_R16_UNORM
, VK_FORMAT_R16_UNORM
} },
191 { AV_PIX_FMT_YUV422P16
, { VK_FORMAT_R16_UNORM
, VK_FORMAT_R16_UNORM
, VK_FORMAT_R16_UNORM
} },
193 { AV_PIX_FMT_YUV444P
, { VK_FORMAT_R8_UNORM
, VK_FORMAT_R8_UNORM
, VK_FORMAT_R8_UNORM
} },
194 { AV_PIX_FMT_YUV444P10
, { VK_FORMAT_R16_UNORM
, VK_FORMAT_R16_UNORM
, VK_FORMAT_R16_UNORM
} },
195 { AV_PIX_FMT_YUV444P12
, { VK_FORMAT_R16_UNORM
, VK_FORMAT_R16_UNORM
, VK_FORMAT_R16_UNORM
} },
196 { AV_PIX_FMT_YUV444P16
, { VK_FORMAT_R16_UNORM
, VK_FORMAT_R16_UNORM
, VK_FORMAT_R16_UNORM
} },
198 { AV_PIX_FMT_YUVA420P
, { VK_FORMAT_R8_UNORM
, VK_FORMAT_R8_UNORM
, VK_FORMAT_R8_UNORM
, VK_FORMAT_R8_UNORM
} },
199 { AV_PIX_FMT_YUVA420P10
, { VK_FORMAT_R16_UNORM
, VK_FORMAT_R16_UNORM
, VK_FORMAT_R16_UNORM
, VK_FORMAT_R16_UNORM
} },
200 /* There is no AV_PIX_FMT_YUVA420P12 */
201 { AV_PIX_FMT_YUVA420P16
, { VK_FORMAT_R16_UNORM
, VK_FORMAT_R16_UNORM
, VK_FORMAT_R16_UNORM
, VK_FORMAT_R16_UNORM
} },
203 { AV_PIX_FMT_YUVA422P
, { VK_FORMAT_R8_UNORM
, VK_FORMAT_R8_UNORM
, VK_FORMAT_R8_UNORM
, VK_FORMAT_R8_UNORM
} },
204 { AV_PIX_FMT_YUVA422P10
, { VK_FORMAT_R16_UNORM
, VK_FORMAT_R16_UNORM
, VK_FORMAT_R16_UNORM
, VK_FORMAT_R16_UNORM
} },
205 { AV_PIX_FMT_YUVA422P12
, { VK_FORMAT_R16_UNORM
, VK_FORMAT_R16_UNORM
, VK_FORMAT_R16_UNORM
, VK_FORMAT_R16_UNORM
} },
206 { AV_PIX_FMT_YUVA422P16
, { VK_FORMAT_R16_UNORM
, VK_FORMAT_R16_UNORM
, VK_FORMAT_R16_UNORM
, VK_FORMAT_R16_UNORM
} },
208 { AV_PIX_FMT_YUVA444P
, { VK_FORMAT_R8_UNORM
, VK_FORMAT_R8_UNORM
, VK_FORMAT_R8_UNORM
, VK_FORMAT_R8_UNORM
} },
209 { AV_PIX_FMT_YUVA444P10
, { VK_FORMAT_R16_UNORM
, VK_FORMAT_R16_UNORM
, VK_FORMAT_R16_UNORM
, VK_FORMAT_R16_UNORM
} },
210 { AV_PIX_FMT_YUVA444P12
, { VK_FORMAT_R16_UNORM
, VK_FORMAT_R16_UNORM
, VK_FORMAT_R16_UNORM
, VK_FORMAT_R16_UNORM
} },
211 { AV_PIX_FMT_YUVA444P16
, { VK_FORMAT_R16_UNORM
, VK_FORMAT_R16_UNORM
, VK_FORMAT_R16_UNORM
, VK_FORMAT_R16_UNORM
} },
213 { AV_PIX_FMT_BGRA
, { VK_FORMAT_B8G8R8A8_UNORM
} },
214 { AV_PIX_FMT_RGBA
, { VK_FORMAT_R8G8B8A8_UNORM
} },
215 { AV_PIX_FMT_RGB24
, { VK_FORMAT_R8G8B8_UNORM
} },
216 { AV_PIX_FMT_BGR24
, { VK_FORMAT_B8G8R8_UNORM
} },
217 { AV_PIX_FMT_RGB48
, { VK_FORMAT_R16G16B16_UNORM
} },
218 { AV_PIX_FMT_RGBA64
, { VK_FORMAT_R16G16B16A16_UNORM
} },
219 { AV_PIX_FMT_RGBA64
, { VK_FORMAT_R16G16B16A16_UNORM
} },
220 { AV_PIX_FMT_RGB565
, { VK_FORMAT_R5G6B5_UNORM_PACK16
} },
221 { AV_PIX_FMT_BGR565
, { VK_FORMAT_B5G6R5_UNORM_PACK16
} },
222 { AV_PIX_FMT_BGR0
, { VK_FORMAT_B8G8R8A8_UNORM
} },
223 { AV_PIX_FMT_RGB0
, { VK_FORMAT_R8G8B8A8_UNORM
} },
225 /* Lower priority as there's an endianess-dependent overlap between these
226 * and rgba/bgr0, and PACK32 formats are more limited */
227 { AV_PIX_FMT_BGR32
, { VK_FORMAT_A8B8G8R8_UNORM_PACK32
} },
228 { AV_PIX_FMT_0BGR32
, { VK_FORMAT_A8B8G8R8_UNORM_PACK32
} },
230 { AV_PIX_FMT_X2RGB10
, { VK_FORMAT_A2R10G10B10_UNORM_PACK32
} },
232 { AV_PIX_FMT_GBRAP
, { VK_FORMAT_R8_UNORM
, VK_FORMAT_R8_UNORM
, VK_FORMAT_R8_UNORM
, VK_FORMAT_R8_UNORM
} },
233 { AV_PIX_FMT_GBRAP16
, { VK_FORMAT_R16_UNORM
, VK_FORMAT_R16_UNORM
, VK_FORMAT_R16_UNORM
, VK_FORMAT_R16_UNORM
} },
234 { AV_PIX_FMT_GBRPF32
, { VK_FORMAT_R32_SFLOAT
, VK_FORMAT_R32_SFLOAT
, VK_FORMAT_R32_SFLOAT
} },
235 { AV_PIX_FMT_GBRAPF32
, { VK_FORMAT_R32_SFLOAT
, VK_FORMAT_R32_SFLOAT
, VK_FORMAT_R32_SFLOAT
, VK_FORMAT_R32_SFLOAT
} },
238 const VkFormat
*av_vkfmt_from_pixfmt(enum AVPixelFormat p
)
240 for (enum AVPixelFormat i
= 0; i
< FF_ARRAY_ELEMS(vk_pixfmt_map
); i
++)
241 if (vk_pixfmt_map
[i
].pixfmt
== p
)
242 return vk_pixfmt_map
[i
].vkfmts
;
246 static const void *vk_find_struct(const void *chain
, VkStructureType stype
)
248 const VkBaseInStructure
*in
= chain
;
250 if (in
->sType
== stype
)
259 static void vk_link_struct(void *chain
, void *in
)
261 VkBaseOutStructure
*out
= chain
;
271 static int pixfmt_is_supported(AVHWDeviceContext
*dev_ctx
, enum AVPixelFormat p
,
274 AVVulkanDeviceContext
*hwctx
= dev_ctx
->hwctx
;
275 VulkanDevicePriv
*priv
= dev_ctx
->internal
->priv
;
276 FFVulkanFunctions
*vk
= &priv
->vkfn
;
277 const VkFormat
*fmt
= av_vkfmt_from_pixfmt(p
);
278 int planes
= av_pix_fmt_count_planes(p
);
283 for (int i
= 0; i
< planes
; i
++) {
284 VkFormatFeatureFlags flags
;
285 VkFormatProperties2 prop
= {
286 .sType
= VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2
,
288 vk
->GetPhysicalDeviceFormatProperties2(hwctx
->phys_dev
, fmt
[i
], &prop
);
289 flags
= linear
? prop
.formatProperties
.linearTilingFeatures
:
290 prop
.formatProperties
.optimalTilingFeatures
;
291 if (!(flags
& FF_VK_DEFAULT_USAGE_FLAGS
))
298 static int load_libvulkan(AVHWDeviceContext
*ctx
)
300 AVVulkanDeviceContext
*hwctx
= ctx
->hwctx
;
301 VulkanDevicePriv
*p
= ctx
->internal
->priv
;
303 static const char *lib_names
[] = {
306 #elif defined(__APPLE__)
316 for (int i
= 0; i
< FF_ARRAY_ELEMS(lib_names
); i
++) {
317 p
->libvulkan
= dlopen(lib_names
[i
], RTLD_NOW
| RTLD_LOCAL
);
323 av_log(ctx
, AV_LOG_ERROR
, "Unable to open the libvulkan library!\n");
324 return AVERROR_UNKNOWN
;
327 hwctx
->get_proc_addr
= (PFN_vkGetInstanceProcAddr
)dlsym(p
->libvulkan
, "vkGetInstanceProcAddr");
332 typedef struct VulkanOptExtension
{
334 FFVulkanExtensions flag
;
335 } VulkanOptExtension
;
337 static const VulkanOptExtension optional_instance_exts
[] = {
341 static const VulkanOptExtension optional_device_exts
[] = {
342 /* Misc or required by other extensions */
343 { VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME
, FF_VK_EXT_NO_FLAG
},
344 { VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME
, FF_VK_EXT_NO_FLAG
},
345 { VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME
, FF_VK_EXT_NO_FLAG
},
347 /* Imports/exports */
348 { VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME
, FF_VK_EXT_EXTERNAL_FD_MEMORY
},
349 { VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME
, FF_VK_EXT_EXTERNAL_DMABUF_MEMORY
},
350 { VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME
, FF_VK_EXT_DRM_MODIFIER_FLAGS
},
351 { VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME
, FF_VK_EXT_EXTERNAL_FD_SEM
},
352 { VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME
, FF_VK_EXT_EXTERNAL_HOST_MEMORY
},
354 { VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME
, FF_VK_EXT_EXTERNAL_WIN32_MEMORY
},
355 { VK_KHR_EXTERNAL_SEMAPHORE_WIN32_EXTENSION_NAME
, FF_VK_EXT_EXTERNAL_WIN32_SEM
},
359 /* Converts return values to strings */
360 static const char *vk_ret2str(VkResult res
)
362 #define CASE(VAL) case VAL: return #VAL
368 CASE(VK_EVENT_RESET
);
370 CASE(VK_ERROR_OUT_OF_HOST_MEMORY
);
371 CASE(VK_ERROR_OUT_OF_DEVICE_MEMORY
);
372 CASE(VK_ERROR_INITIALIZATION_FAILED
);
373 CASE(VK_ERROR_DEVICE_LOST
);
374 CASE(VK_ERROR_MEMORY_MAP_FAILED
);
375 CASE(VK_ERROR_LAYER_NOT_PRESENT
);
376 CASE(VK_ERROR_EXTENSION_NOT_PRESENT
);
377 CASE(VK_ERROR_FEATURE_NOT_PRESENT
);
378 CASE(VK_ERROR_INCOMPATIBLE_DRIVER
);
379 CASE(VK_ERROR_TOO_MANY_OBJECTS
);
380 CASE(VK_ERROR_FORMAT_NOT_SUPPORTED
);
381 CASE(VK_ERROR_FRAGMENTED_POOL
);
382 CASE(VK_ERROR_SURFACE_LOST_KHR
);
383 CASE(VK_ERROR_NATIVE_WINDOW_IN_USE_KHR
);
384 CASE(VK_SUBOPTIMAL_KHR
);
385 CASE(VK_ERROR_OUT_OF_DATE_KHR
);
386 CASE(VK_ERROR_INCOMPATIBLE_DISPLAY_KHR
);
387 CASE(VK_ERROR_VALIDATION_FAILED_EXT
);
388 CASE(VK_ERROR_INVALID_SHADER_NV
);
389 CASE(VK_ERROR_OUT_OF_POOL_MEMORY
);
390 CASE(VK_ERROR_INVALID_EXTERNAL_HANDLE
);
391 CASE(VK_ERROR_NOT_PERMITTED_EXT
);
392 CASE(VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT
);
393 CASE(VK_ERROR_INVALID_DEVICE_ADDRESS_EXT
);
394 CASE(VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT
);
395 default: return "Unknown error";
400 static VkBool32 VKAPI_CALL
vk_dbg_callback(VkDebugUtilsMessageSeverityFlagBitsEXT severity
,
401 VkDebugUtilsMessageTypeFlagsEXT messageType
,
402 const VkDebugUtilsMessengerCallbackDataEXT
*data
,
406 AVHWDeviceContext
*ctx
= priv
;
409 case VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT
: l
= AV_LOG_VERBOSE
; break;
410 case VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT
: l
= AV_LOG_INFO
; break;
411 case VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT
: l
= AV_LOG_WARNING
; break;
412 case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT
: l
= AV_LOG_ERROR
; break;
413 default: l
= AV_LOG_DEBUG
; break;
416 av_log(ctx
, l
, "%s\n", data
->pMessage
);
417 for (int i
= 0; i
< data
->cmdBufLabelCount
; i
++)
418 av_log(ctx
, l
, "\t%i: %s\n", i
, data
->pCmdBufLabels
[i
].pLabelName
);
423 static int check_extensions(AVHWDeviceContext
*ctx
, int dev
, AVDictionary
*opts
,
424 const char * const **dst
, uint32_t *num
, int debug
)
427 const char **extension_names
= NULL
;
428 VulkanDevicePriv
*p
= ctx
->internal
->priv
;
429 FFVulkanFunctions
*vk
= &p
->vkfn
;
430 AVVulkanDeviceContext
*hwctx
= ctx
->hwctx
;
431 int err
= 0, found
, extensions_found
= 0;
434 int optional_exts_num
;
435 uint32_t sup_ext_count
;
436 char *user_exts_str
= NULL
;
437 AVDictionaryEntry
*user_exts
;
438 VkExtensionProperties
*sup_ext
;
439 const VulkanOptExtension
*optional_exts
;
443 optional_exts
= optional_instance_exts
;
444 optional_exts_num
= FF_ARRAY_ELEMS(optional_instance_exts
);
445 user_exts
= av_dict_get(opts
, "instance_extensions", NULL
, 0);
447 user_exts_str
= av_strdup(user_exts
->value
);
448 if (!user_exts_str
) {
449 err
= AVERROR(ENOMEM
);
453 vk
->EnumerateInstanceExtensionProperties(NULL
, &sup_ext_count
, NULL
);
454 sup_ext
= av_malloc_array(sup_ext_count
, sizeof(VkExtensionProperties
));
456 return AVERROR(ENOMEM
);
457 vk
->EnumerateInstanceExtensionProperties(NULL
, &sup_ext_count
, sup_ext
);
460 optional_exts
= optional_device_exts
;
461 optional_exts_num
= FF_ARRAY_ELEMS(optional_device_exts
);
462 user_exts
= av_dict_get(opts
, "device_extensions", NULL
, 0);
464 user_exts_str
= av_strdup(user_exts
->value
);
465 if (!user_exts_str
) {
466 err
= AVERROR(ENOMEM
);
470 vk
->EnumerateDeviceExtensionProperties(hwctx
->phys_dev
, NULL
,
471 &sup_ext_count
, NULL
);
472 sup_ext
= av_malloc_array(sup_ext_count
, sizeof(VkExtensionProperties
));
474 return AVERROR(ENOMEM
);
475 vk
->EnumerateDeviceExtensionProperties(hwctx
->phys_dev
, NULL
,
476 &sup_ext_count
, sup_ext
);
479 for (int i
= 0; i
< optional_exts_num
; i
++) {
480 tstr
= optional_exts
[i
].name
;
482 for (int j
= 0; j
< sup_ext_count
; j
++) {
483 if (!strcmp(tstr
, sup_ext
[j
].extensionName
)) {
491 av_log(ctx
, AV_LOG_VERBOSE
, "Using %s extension %s\n", mod
, tstr
);
492 p
->extensions
|= optional_exts
[i
].flag
;
493 ADD_VAL_TO_LIST(extension_names
, extensions_found
, tstr
);
497 tstr
= VK_EXT_DEBUG_UTILS_EXTENSION_NAME
;
499 for (int j
= 0; j
< sup_ext_count
; j
++) {
500 if (!strcmp(tstr
, sup_ext
[j
].extensionName
)) {
506 av_log(ctx
, AV_LOG_VERBOSE
, "Using %s extension %s\n", mod
, tstr
);
507 ADD_VAL_TO_LIST(extension_names
, extensions_found
, tstr
);
508 p
->extensions
|= FF_VK_EXT_DEBUG_UTILS
;
510 av_log(ctx
, AV_LOG_ERROR
, "Debug extension \"%s\" not found!\n",
512 err
= AVERROR(EINVAL
);
518 char *save
, *token
= av_strtok(user_exts_str
, "+", &save
);
521 for (int j
= 0; j
< sup_ext_count
; j
++) {
522 if (!strcmp(token
, sup_ext
[j
].extensionName
)) {
528 av_log(ctx
, AV_LOG_VERBOSE
, "Using %s extension \"%s\"\n", mod
, token
);
529 ADD_VAL_TO_LIST(extension_names
, extensions_found
, token
);
531 av_log(ctx
, AV_LOG_WARNING
, "%s extension \"%s\" not found, excluding.\n",
534 token
= av_strtok(NULL
, "+", &save
);
538 *dst
= extension_names
;
539 *num
= extensions_found
;
541 av_free(user_exts_str
);
546 RELEASE_PROPS(extension_names
, extensions_found
);
547 av_free(user_exts_str
);
552 static int check_validation_layers(AVHWDeviceContext
*ctx
, AVDictionary
*opts
,
553 const char * const **dst
, uint32_t *num
,
556 static const char default_layer
[] = { "VK_LAYER_KHRONOS_validation" };
558 int found
= 0, err
= 0;
559 VulkanDevicePriv
*priv
= ctx
->internal
->priv
;
560 FFVulkanFunctions
*vk
= &priv
->vkfn
;
562 uint32_t sup_layer_count
;
563 VkLayerProperties
*sup_layers
;
565 AVDictionaryEntry
*user_layers
;
566 char *user_layers_str
= NULL
;
569 const char **enabled_layers
= NULL
;
570 uint32_t enabled_layers_count
= 0;
572 AVDictionaryEntry
*debug_opt
= av_dict_get(opts
, "debug", NULL
, 0);
573 int debug
= debug_opt
&& strtol(debug_opt
->value
, NULL
, 10);
575 /* If `debug=0`, enable no layers at all. */
576 if (debug_opt
&& !debug
)
579 vk
->EnumerateInstanceLayerProperties(&sup_layer_count
, NULL
);
580 sup_layers
= av_malloc_array(sup_layer_count
, sizeof(VkLayerProperties
));
582 return AVERROR(ENOMEM
);
583 vk
->EnumerateInstanceLayerProperties(&sup_layer_count
, sup_layers
);
585 av_log(ctx
, AV_LOG_VERBOSE
, "Supported validation layers:\n");
586 for (int i
= 0; i
< sup_layer_count
; i
++)
587 av_log(ctx
, AV_LOG_VERBOSE
, "\t%s\n", sup_layers
[i
].layerName
);
589 /* If `debug=1` is specified, enable the standard validation layer extension */
592 for (int i
= 0; i
< sup_layer_count
; i
++) {
593 if (!strcmp(default_layer
, sup_layers
[i
].layerName
)) {
595 av_log(ctx
, AV_LOG_VERBOSE
, "Default validation layer %s is enabled\n",
597 ADD_VAL_TO_LIST(enabled_layers
, enabled_layers_count
, default_layer
);
603 user_layers
= av_dict_get(opts
, "validation_layers", NULL
, 0);
607 user_layers_str
= av_strdup(user_layers
->value
);
608 if (!user_layers_str
) {
609 err
= AVERROR(ENOMEM
);
613 token
= av_strtok(user_layers_str
, "+", &save
);
616 if (!strcmp(default_layer
, token
)) {
618 /* if the `debug=1`, default_layer is enabled, skip here */
619 token
= av_strtok(NULL
, "+", &save
);
622 /* if the `debug=0`, enable debug mode to load its callback properly */
626 for (int j
= 0; j
< sup_layer_count
; j
++) {
627 if (!strcmp(token
, sup_layers
[j
].layerName
)) {
633 av_log(ctx
, AV_LOG_VERBOSE
, "Requested Validation Layer: %s\n", token
);
634 ADD_VAL_TO_LIST(enabled_layers
, enabled_layers_count
, token
);
636 av_log(ctx
, AV_LOG_ERROR
,
637 "Validation Layer \"%s\" not support.\n", token
);
638 err
= AVERROR(EINVAL
);
641 token
= av_strtok(NULL
, "+", &save
);
644 av_free(user_layers_str
);
649 *dst
= enabled_layers
;
650 *num
= enabled_layers_count
;
655 RELEASE_PROPS(enabled_layers
, enabled_layers_count
);
657 av_free(user_layers_str
);
661 /* Creates a VkInstance */
662 static int create_instance(AVHWDeviceContext
*ctx
, AVDictionary
*opts
)
664 int err
= 0, debug_mode
= 0;
666 VulkanDevicePriv
*p
= ctx
->internal
->priv
;
667 FFVulkanFunctions
*vk
= &p
->vkfn
;
668 AVVulkanDeviceContext
*hwctx
= ctx
->hwctx
;
669 VkApplicationInfo application_info
= {
670 .sType
= VK_STRUCTURE_TYPE_APPLICATION_INFO
,
671 .pEngineName
= "libavutil",
672 .apiVersion
= VK_API_VERSION_1_2
,
673 .engineVersion
= VK_MAKE_VERSION(LIBAVUTIL_VERSION_MAJOR
,
674 LIBAVUTIL_VERSION_MINOR
,
675 LIBAVUTIL_VERSION_MICRO
),
677 VkInstanceCreateInfo inst_props
= {
678 .sType
= VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO
,
679 .pApplicationInfo
= &application_info
,
682 if (!hwctx
->get_proc_addr
) {
683 err
= load_libvulkan(ctx
);
688 err
= ff_vk_load_functions(ctx
, vk
, p
->extensions
, 0, 0);
690 av_log(ctx
, AV_LOG_ERROR
, "Unable to load instance enumeration functions!\n");
694 err
= check_validation_layers(ctx
, opts
, &inst_props
.ppEnabledLayerNames
,
695 &inst_props
.enabledLayerCount
, &debug_mode
);
699 /* Check for present/missing extensions */
700 err
= check_extensions(ctx
, 0, opts
, &inst_props
.ppEnabledExtensionNames
,
701 &inst_props
.enabledExtensionCount
, debug_mode
);
702 hwctx
->enabled_inst_extensions
= inst_props
.ppEnabledExtensionNames
;
703 hwctx
->nb_enabled_inst_extensions
= inst_props
.enabledExtensionCount
;
707 /* Try to create the instance */
708 ret
= vk
->CreateInstance(&inst_props
, hwctx
->alloc
, &hwctx
->inst
);
710 /* Check for errors */
711 if (ret
!= VK_SUCCESS
) {
712 av_log(ctx
, AV_LOG_ERROR
, "Instance creation failure: %s\n",
714 err
= AVERROR_EXTERNAL
;
718 err
= ff_vk_load_functions(ctx
, vk
, p
->extensions
, 1, 0);
720 av_log(ctx
, AV_LOG_ERROR
, "Unable to load instance functions!\n");
725 VkDebugUtilsMessengerCreateInfoEXT dbg
= {
726 .sType
= VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT
,
727 .messageSeverity
= VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT
|
728 VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT
|
729 VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT
|
730 VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT
,
731 .messageType
= VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT
|
732 VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT
|
733 VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT
,
734 .pfnUserCallback
= vk_dbg_callback
,
738 vk
->CreateDebugUtilsMessengerEXT(hwctx
->inst
, &dbg
,
739 hwctx
->alloc
, &p
->debug_ctx
);
745 RELEASE_PROPS(inst_props
.ppEnabledLayerNames
, inst_props
.enabledLayerCount
);
749 typedef struct VulkanDeviceSelection
{
750 uint8_t uuid
[VK_UUID_SIZE
]; /* Will use this first unless !has_uuid */
752 const char *name
; /* Will use this second unless NULL */
753 uint32_t pci_device
; /* Will use this third unless 0x0 */
754 uint32_t vendor_id
; /* Last resort to find something deterministic */
755 int index
; /* Finally fall back to index */
756 } VulkanDeviceSelection
;
758 static const char *vk_dev_type(enum VkPhysicalDeviceType type
)
761 case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU
: return "integrated";
762 case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU
: return "discrete";
763 case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU
: return "virtual";
764 case VK_PHYSICAL_DEVICE_TYPE_CPU
: return "software";
765 default: return "unknown";
770 static int find_device(AVHWDeviceContext
*ctx
, VulkanDeviceSelection
*select
)
772 int err
= 0, choice
= -1;
775 VulkanDevicePriv
*p
= ctx
->internal
->priv
;
776 FFVulkanFunctions
*vk
= &p
->vkfn
;
777 VkPhysicalDevice
*devices
= NULL
;
778 VkPhysicalDeviceIDProperties
*idp
= NULL
;
779 VkPhysicalDeviceProperties2
*prop
= NULL
;
780 AVVulkanDeviceContext
*hwctx
= ctx
->hwctx
;
782 ret
= vk
->EnumeratePhysicalDevices(hwctx
->inst
, &num
, NULL
);
783 if (ret
!= VK_SUCCESS
|| !num
) {
784 av_log(ctx
, AV_LOG_ERROR
, "No devices found: %s!\n", vk_ret2str(ret
));
785 return AVERROR(ENODEV
);
788 devices
= av_malloc_array(num
, sizeof(VkPhysicalDevice
));
790 return AVERROR(ENOMEM
);
792 ret
= vk
->EnumeratePhysicalDevices(hwctx
->inst
, &num
, devices
);
793 if (ret
!= VK_SUCCESS
) {
794 av_log(ctx
, AV_LOG_ERROR
, "Failed enumerating devices: %s\n",
796 err
= AVERROR(ENODEV
);
800 prop
= av_calloc(num
, sizeof(*prop
));
802 err
= AVERROR(ENOMEM
);
806 idp
= av_calloc(num
, sizeof(*idp
));
808 err
= AVERROR(ENOMEM
);
812 av_log(ctx
, AV_LOG_VERBOSE
, "GPU listing:\n");
813 for (int i
= 0; i
< num
; i
++) {
814 idp
[i
].sType
= VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES
;
815 prop
[i
].sType
= VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2
;
816 prop
[i
].pNext
= &idp
[i
];
818 vk
->GetPhysicalDeviceProperties2(devices
[i
], &prop
[i
]);
819 av_log(ctx
, AV_LOG_VERBOSE
, " %d: %s (%s) (0x%x)\n", i
,
820 prop
[i
].properties
.deviceName
,
821 vk_dev_type(prop
[i
].properties
.deviceType
),
822 prop
[i
].properties
.deviceID
);
825 if (select
->has_uuid
) {
826 for (int i
= 0; i
< num
; i
++) {
827 if (!strncmp(idp
[i
].deviceUUID
, select
->uuid
, VK_UUID_SIZE
)) {
832 av_log(ctx
, AV_LOG_ERROR
, "Unable to find device by given UUID!\n");
833 err
= AVERROR(ENODEV
);
835 } else if (select
->name
) {
836 av_log(ctx
, AV_LOG_VERBOSE
, "Requested device: %s\n", select
->name
);
837 for (int i
= 0; i
< num
; i
++) {
838 if (strstr(prop
[i
].properties
.deviceName
, select
->name
)) {
843 av_log(ctx
, AV_LOG_ERROR
, "Unable to find device \"%s\"!\n",
845 err
= AVERROR(ENODEV
);
847 } else if (select
->pci_device
) {
848 av_log(ctx
, AV_LOG_VERBOSE
, "Requested device: 0x%x\n", select
->pci_device
);
849 for (int i
= 0; i
< num
; i
++) {
850 if (select
->pci_device
== prop
[i
].properties
.deviceID
) {
855 av_log(ctx
, AV_LOG_ERROR
, "Unable to find device with PCI ID 0x%x!\n",
857 err
= AVERROR(EINVAL
);
859 } else if (select
->vendor_id
) {
860 av_log(ctx
, AV_LOG_VERBOSE
, "Requested vendor: 0x%x\n", select
->vendor_id
);
861 for (int i
= 0; i
< num
; i
++) {
862 if (select
->vendor_id
== prop
[i
].properties
.vendorID
) {
867 av_log(ctx
, AV_LOG_ERROR
, "Unable to find device with Vendor ID 0x%x!\n",
869 err
= AVERROR(ENODEV
);
872 if (select
->index
< num
) {
873 choice
= select
->index
;
876 av_log(ctx
, AV_LOG_ERROR
, "Unable to find device with index %i!\n",
878 err
= AVERROR(ENODEV
);
884 av_log(ctx
, AV_LOG_VERBOSE
, "Device %d selected: %s (%s) (0x%x)\n",
885 choice
, prop
[choice
].properties
.deviceName
,
886 vk_dev_type(prop
[choice
].properties
.deviceType
),
887 prop
[choice
].properties
.deviceID
);
888 hwctx
->phys_dev
= devices
[choice
];
898 /* Picks the least used qf with the fewest unneeded flags, or -1 if none found */
899 static inline int pick_queue_family(VkQueueFamilyProperties
*qf
, uint32_t num_qf
,
900 VkQueueFlagBits flags
)
903 uint32_t min_score
= UINT32_MAX
;
905 for (int i
= 0; i
< num_qf
; i
++) {
906 const VkQueueFlagBits qflags
= qf
[i
].queueFlags
;
907 if (qflags
& flags
) {
908 uint32_t score
= av_popcount(qflags
) + qf
[i
].timestampValidBits
;
909 if (score
< min_score
) {
917 qf
[index
].timestampValidBits
++;
922 static int setup_queue_families(AVHWDeviceContext
*ctx
, VkDeviceCreateInfo
*cd
)
926 VkQueueFamilyProperties
*qf
= NULL
;
927 VulkanDevicePriv
*p
= ctx
->internal
->priv
;
928 FFVulkanFunctions
*vk
= &p
->vkfn
;
929 AVVulkanDeviceContext
*hwctx
= ctx
->hwctx
;
930 int graph_index
, comp_index
, tx_index
, enc_index
, dec_index
;
932 /* First get the number of queue families */
933 vk
->GetPhysicalDeviceQueueFamilyProperties(hwctx
->phys_dev
, &num
, NULL
);
935 av_log(ctx
, AV_LOG_ERROR
, "Failed to get queues!\n");
936 return AVERROR_EXTERNAL
;
939 /* Then allocate memory */
940 qf
= av_malloc_array(num
, sizeof(VkQueueFamilyProperties
));
942 return AVERROR(ENOMEM
);
944 /* Finally retrieve the queue families */
945 vk
->GetPhysicalDeviceQueueFamilyProperties(hwctx
->phys_dev
, &num
, qf
);
947 av_log(ctx
, AV_LOG_VERBOSE
, "Queue families:\n");
948 for (int i
= 0; i
< num
; i
++) {
949 av_log(ctx
, AV_LOG_VERBOSE
, " %i:%s%s%s%s%s%s%s (queues: %i)\n", i
,
950 ((qf
[i
].queueFlags
) & VK_QUEUE_GRAPHICS_BIT
) ? " graphics" : "",
951 ((qf
[i
].queueFlags
) & VK_QUEUE_COMPUTE_BIT
) ? " compute" : "",
952 ((qf
[i
].queueFlags
) & VK_QUEUE_TRANSFER_BIT
) ? " transfer" : "",
953 ((qf
[i
].queueFlags
) & VK_QUEUE_VIDEO_ENCODE_BIT_KHR
) ? " encode" : "",
954 ((qf
[i
].queueFlags
) & VK_QUEUE_VIDEO_DECODE_BIT_KHR
) ? " decode" : "",
955 ((qf
[i
].queueFlags
) & VK_QUEUE_SPARSE_BINDING_BIT
) ? " sparse" : "",
956 ((qf
[i
].queueFlags
) & VK_QUEUE_PROTECTED_BIT
) ? " protected" : "",
959 /* We use this field to keep a score of how many times we've used that
960 * queue family in order to make better choices. */
961 qf
[i
].timestampValidBits
= 0;
964 /* Pick each queue family to use */
965 graph_index
= pick_queue_family(qf
, num
, VK_QUEUE_GRAPHICS_BIT
);
966 comp_index
= pick_queue_family(qf
, num
, VK_QUEUE_COMPUTE_BIT
);
967 tx_index
= pick_queue_family(qf
, num
, VK_QUEUE_TRANSFER_BIT
);
968 enc_index
= pick_queue_family(qf
, num
, VK_QUEUE_VIDEO_ENCODE_BIT_KHR
);
969 dec_index
= pick_queue_family(qf
, num
, VK_QUEUE_VIDEO_DECODE_BIT_KHR
);
971 /* Signalling the transfer capabilities on a queue family is optional */
973 tx_index
= pick_queue_family(qf
, num
, VK_QUEUE_COMPUTE_BIT
);
975 tx_index
= pick_queue_family(qf
, num
, VK_QUEUE_GRAPHICS_BIT
);
978 hwctx
->queue_family_index
= -1;
979 hwctx
->queue_family_comp_index
= -1;
980 hwctx
->queue_family_tx_index
= -1;
981 hwctx
->queue_family_encode_index
= -1;
982 hwctx
->queue_family_decode_index
= -1;
984 #define SETUP_QUEUE(qf_idx) \
987 int qc = qf[fidx].queueCount; \
988 VkDeviceQueueCreateInfo *pc; \
990 if (fidx == graph_index) { \
991 hwctx->queue_family_index = fidx; \
992 hwctx->nb_graphics_queues = qc; \
995 if (fidx == comp_index) { \
996 hwctx->queue_family_comp_index = fidx; \
997 hwctx->nb_comp_queues = qc; \
1000 if (fidx == tx_index) { \
1001 hwctx->queue_family_tx_index = fidx; \
1002 hwctx->nb_tx_queues = qc; \
1005 if (fidx == enc_index) { \
1006 hwctx->queue_family_encode_index = fidx; \
1007 hwctx->nb_encode_queues = qc; \
1010 if (fidx == dec_index) { \
1011 hwctx->queue_family_decode_index = fidx; \
1012 hwctx->nb_decode_queues = qc; \
1016 pc = av_realloc((void *)cd->pQueueCreateInfos, \
1017 sizeof(*pc) * (cd->queueCreateInfoCount + 1)); \
1020 return AVERROR(ENOMEM); \
1022 cd->pQueueCreateInfos = pc; \
1023 pc = &pc[cd->queueCreateInfoCount]; \
1025 weights = av_malloc(qc * sizeof(float)); \
1028 return AVERROR(ENOMEM); \
1031 memset(pc, 0, sizeof(*pc)); \
1032 pc->sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; \
1033 pc->queueFamilyIndex = fidx; \
1034 pc->queueCount = qc; \
1035 pc->pQueuePriorities = weights; \
1037 for (int i = 0; i < qc; i++) \
1038 weights[i] = 1.0f / qc; \
1040 cd->queueCreateInfoCount++; \
1043 SETUP_QUEUE(graph_index
)
1044 SETUP_QUEUE(comp_index
)
1045 SETUP_QUEUE(tx_index
)
1046 SETUP_QUEUE(enc_index
)
1047 SETUP_QUEUE(dec_index
)
1056 static int create_exec_ctx(AVHWFramesContext
*hwfc
, VulkanExecCtx
*cmd
,
1057 int queue_family_index
, int num_queues
)
1060 AVVulkanDeviceContext
*hwctx
= hwfc
->device_ctx
->hwctx
;
1061 VulkanDevicePriv
*p
= hwfc
->device_ctx
->internal
->priv
;
1062 FFVulkanFunctions
*vk
= &p
->vkfn
;
1064 VkCommandPoolCreateInfo cqueue_create
= {
1065 .sType
= VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO
,
1066 .flags
= VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT
,
1067 .queueFamilyIndex
= queue_family_index
,
1069 VkCommandBufferAllocateInfo cbuf_create
= {
1070 .sType
= VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO
,
1071 .level
= VK_COMMAND_BUFFER_LEVEL_PRIMARY
,
1072 .commandBufferCount
= num_queues
,
1075 cmd
->nb_queues
= num_queues
;
1077 /* Create command pool */
1078 ret
= vk
->CreateCommandPool(hwctx
->act_dev
, &cqueue_create
,
1079 hwctx
->alloc
, &cmd
->pool
);
1080 if (ret
!= VK_SUCCESS
) {
1081 av_log(hwfc
, AV_LOG_ERROR
, "Command pool creation failure: %s\n",
1083 return AVERROR_EXTERNAL
;
1086 cmd
->bufs
= av_mallocz(num_queues
* sizeof(*cmd
->bufs
));
1088 return AVERROR(ENOMEM
);
1090 cbuf_create
.commandPool
= cmd
->pool
;
1092 /* Allocate command buffer */
1093 ret
= vk
->AllocateCommandBuffers(hwctx
->act_dev
, &cbuf_create
, cmd
->bufs
);
1094 if (ret
!= VK_SUCCESS
) {
1095 av_log(hwfc
, AV_LOG_ERROR
, "Command buffer alloc failure: %s\n",
1097 av_freep(&cmd
->bufs
);
1098 return AVERROR_EXTERNAL
;
1101 cmd
->queues
= av_mallocz(num_queues
* sizeof(*cmd
->queues
));
1103 return AVERROR(ENOMEM
);
1105 for (int i
= 0; i
< num_queues
; i
++) {
1106 VulkanQueueCtx
*q
= &cmd
->queues
[i
];
1107 vk
->GetDeviceQueue(hwctx
->act_dev
, queue_family_index
, i
, &q
->queue
);
1108 q
->was_synchronous
= 1;
1114 static void free_exec_ctx(AVHWFramesContext
*hwfc
, VulkanExecCtx
*cmd
)
1116 AVVulkanDeviceContext
*hwctx
= hwfc
->device_ctx
->hwctx
;
1117 VulkanDevicePriv
*p
= hwfc
->device_ctx
->internal
->priv
;
1118 FFVulkanFunctions
*vk
= &p
->vkfn
;
1121 for (int i
= 0; i
< cmd
->nb_queues
; i
++) {
1122 VulkanQueueCtx
*q
= &cmd
->queues
[i
];
1124 /* Make sure all queues have finished executing */
1125 if (q
->fence
&& !q
->was_synchronous
) {
1126 vk
->WaitForFences(hwctx
->act_dev
, 1, &q
->fence
, VK_TRUE
, UINT64_MAX
);
1127 vk
->ResetFences(hwctx
->act_dev
, 1, &q
->fence
);
1130 /* Free the fence */
1132 vk
->DestroyFence(hwctx
->act_dev
, q
->fence
, hwctx
->alloc
);
1134 /* Free buffer dependencies */
1135 for (int j
= 0; j
< q
->nb_buf_deps
; j
++)
1136 av_buffer_unref(&q
->buf_deps
[j
]);
1137 av_free(q
->buf_deps
);
1142 vk
->FreeCommandBuffers(hwctx
->act_dev
, cmd
->pool
, cmd
->nb_queues
, cmd
->bufs
);
1144 vk
->DestroyCommandPool(hwctx
->act_dev
, cmd
->pool
, hwctx
->alloc
);
1146 av_freep(&cmd
->queues
);
1147 av_freep(&cmd
->bufs
);
1148 cmd
->pool
= VK_NULL_HANDLE
;
1151 static VkCommandBuffer
get_buf_exec_ctx(AVHWFramesContext
*hwfc
, VulkanExecCtx
*cmd
)
1153 return cmd
->bufs
[cmd
->cur_queue_idx
];
1156 static void unref_exec_ctx_deps(AVHWFramesContext
*hwfc
, VulkanExecCtx
*cmd
)
1158 VulkanQueueCtx
*q
= &cmd
->queues
[cmd
->cur_queue_idx
];
1160 for (int j
= 0; j
< q
->nb_buf_deps
; j
++)
1161 av_buffer_unref(&q
->buf_deps
[j
]);
1165 static int wait_start_exec_ctx(AVHWFramesContext
*hwfc
, VulkanExecCtx
*cmd
)
1168 AVVulkanDeviceContext
*hwctx
= hwfc
->device_ctx
->hwctx
;
1169 VulkanQueueCtx
*q
= &cmd
->queues
[cmd
->cur_queue_idx
];
1170 VulkanDevicePriv
*p
= hwfc
->device_ctx
->internal
->priv
;
1171 FFVulkanFunctions
*vk
= &p
->vkfn
;
1173 VkCommandBufferBeginInfo cmd_start
= {
1174 .sType
= VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO
,
1175 .flags
= VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT
,
1178 /* Create the fence and don't wait for it initially */
1180 VkFenceCreateInfo fence_spawn
= {
1181 .sType
= VK_STRUCTURE_TYPE_FENCE_CREATE_INFO
,
1183 ret
= vk
->CreateFence(hwctx
->act_dev
, &fence_spawn
, hwctx
->alloc
,
1185 if (ret
!= VK_SUCCESS
) {
1186 av_log(hwfc
, AV_LOG_ERROR
, "Failed to queue frame fence: %s\n",
1188 return AVERROR_EXTERNAL
;
1190 } else if (!q
->was_synchronous
) {
1191 vk
->WaitForFences(hwctx
->act_dev
, 1, &q
->fence
, VK_TRUE
, UINT64_MAX
);
1192 vk
->ResetFences(hwctx
->act_dev
, 1, &q
->fence
);
1195 /* Discard queue dependencies */
1196 unref_exec_ctx_deps(hwfc
, cmd
);
1198 ret
= vk
->BeginCommandBuffer(cmd
->bufs
[cmd
->cur_queue_idx
], &cmd_start
);
1199 if (ret
!= VK_SUCCESS
) {
1200 av_log(hwfc
, AV_LOG_ERROR
, "Unable to init command buffer: %s\n",
1202 return AVERROR_EXTERNAL
;
1208 static int add_buf_dep_exec_ctx(AVHWFramesContext
*hwfc
, VulkanExecCtx
*cmd
,
1209 AVBufferRef
* const *deps
, int nb_deps
)
1212 VulkanQueueCtx
*q
= &cmd
->queues
[cmd
->cur_queue_idx
];
1214 if (!deps
|| !nb_deps
)
1217 dst
= av_fast_realloc(q
->buf_deps
, &q
->buf_deps_alloc_size
,
1218 (q
->nb_buf_deps
+ nb_deps
) * sizeof(*dst
));
1224 for (int i
= 0; i
< nb_deps
; i
++) {
1225 q
->buf_deps
[q
->nb_buf_deps
] = av_buffer_ref(deps
[i
]);
1226 if (!q
->buf_deps
[q
->nb_buf_deps
])
1234 unref_exec_ctx_deps(hwfc
, cmd
);
1235 return AVERROR(ENOMEM
);
1238 static int submit_exec_ctx(AVHWFramesContext
*hwfc
, VulkanExecCtx
*cmd
,
1239 VkSubmitInfo
*s_info
, AVVkFrame
*f
, int synchronous
)
1242 VulkanQueueCtx
*q
= &cmd
->queues
[cmd
->cur_queue_idx
];
1243 VulkanDevicePriv
*p
= hwfc
->device_ctx
->internal
->priv
;
1244 FFVulkanFunctions
*vk
= &p
->vkfn
;
1246 ret
= vk
->EndCommandBuffer(cmd
->bufs
[cmd
->cur_queue_idx
]);
1247 if (ret
!= VK_SUCCESS
) {
1248 av_log(hwfc
, AV_LOG_ERROR
, "Unable to finish command buffer: %s\n",
1250 unref_exec_ctx_deps(hwfc
, cmd
);
1251 return AVERROR_EXTERNAL
;
1254 s_info
->pCommandBuffers
= &cmd
->bufs
[cmd
->cur_queue_idx
];
1255 s_info
->commandBufferCount
= 1;
1257 ret
= vk
->QueueSubmit(q
->queue
, 1, s_info
, q
->fence
);
1258 if (ret
!= VK_SUCCESS
) {
1259 av_log(hwfc
, AV_LOG_ERROR
, "Queue submission failure: %s\n",
1261 unref_exec_ctx_deps(hwfc
, cmd
);
1262 return AVERROR_EXTERNAL
;
1266 for (int i
= 0; i
< s_info
->signalSemaphoreCount
; i
++)
1269 q
->was_synchronous
= synchronous
;
1272 AVVulkanDeviceContext
*hwctx
= hwfc
->device_ctx
->hwctx
;
1273 vk
->WaitForFences(hwctx
->act_dev
, 1, &q
->fence
, VK_TRUE
, UINT64_MAX
);
1274 vk
->ResetFences(hwctx
->act_dev
, 1, &q
->fence
);
1275 unref_exec_ctx_deps(hwfc
, cmd
);
1276 } else { /* Rotate queues */
1277 cmd
->cur_queue_idx
= (cmd
->cur_queue_idx
+ 1) % cmd
->nb_queues
;
1283 static void vulkan_device_free(AVHWDeviceContext
*ctx
)
1285 VulkanDevicePriv
*p
= ctx
->internal
->priv
;
1286 FFVulkanFunctions
*vk
= &p
->vkfn
;
1287 AVVulkanDeviceContext
*hwctx
= ctx
->hwctx
;
1290 vk
->DestroyDevice(hwctx
->act_dev
, hwctx
->alloc
);
1293 vk
->DestroyDebugUtilsMessengerEXT(hwctx
->inst
, p
->debug_ctx
,
1297 vk
->DestroyInstance(hwctx
->inst
, hwctx
->alloc
);
1300 dlclose(p
->libvulkan
);
1302 RELEASE_PROPS(hwctx
->enabled_inst_extensions
, hwctx
->nb_enabled_inst_extensions
);
1303 RELEASE_PROPS(hwctx
->enabled_dev_extensions
, hwctx
->nb_enabled_dev_extensions
);
1306 static int vulkan_device_create_internal(AVHWDeviceContext
*ctx
,
1307 VulkanDeviceSelection
*dev_select
,
1308 AVDictionary
*opts
, int flags
)
1312 AVDictionaryEntry
*opt_d
;
1313 VulkanDevicePriv
*p
= ctx
->internal
->priv
;
1314 FFVulkanFunctions
*vk
= &p
->vkfn
;
1315 AVVulkanDeviceContext
*hwctx
= ctx
->hwctx
;
1318 * VkPhysicalDeviceVulkan12Features has a timelineSemaphore field, but
1319 * MoltenVK doesn't implement VkPhysicalDeviceVulkan12Features yet, so we
1320 * use VkPhysicalDeviceTimelineSemaphoreFeatures directly.
1322 VkPhysicalDeviceTimelineSemaphoreFeatures timeline_features
= {
1323 .sType
= VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES
,
1325 VkPhysicalDeviceVulkan12Features dev_features_1_2
= {
1326 .sType
= VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES
,
1327 .pNext
= &timeline_features
,
1329 VkPhysicalDeviceVulkan11Features dev_features_1_1
= {
1330 .sType
= VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES
,
1331 .pNext
= &dev_features_1_2
,
1333 VkPhysicalDeviceFeatures2 dev_features
= {
1334 .sType
= VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2
,
1335 .pNext
= &dev_features_1_1
,
1338 VkDeviceCreateInfo dev_info
= {
1339 .sType
= VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO
,
1340 .pNext
= &hwctx
->device_features
,
1343 hwctx
->device_features
.sType
= VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2
;
1344 hwctx
->device_features
.pNext
= &p
->device_features_1_1
;
1345 p
->device_features_1_1
.sType
= VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES
;
1346 p
->device_features_1_1
.pNext
= &p
->device_features_1_2
;
1347 p
->device_features_1_2
.sType
= VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES
;
1348 ctx
->free
= vulkan_device_free
;
1350 /* Create an instance if not given one */
1351 if ((err
= create_instance(ctx
, opts
)))
1354 /* Find a device (if not given one) */
1355 if ((err
= find_device(ctx
, dev_select
)))
1358 vk
->GetPhysicalDeviceFeatures2(hwctx
->phys_dev
, &dev_features
);
1360 /* Try to keep in sync with libplacebo */
1361 #define COPY_FEATURE(DST, NAME) (DST).features.NAME = dev_features.features.NAME;
1362 COPY_FEATURE(hwctx
->device_features
, shaderImageGatherExtended
)
1363 COPY_FEATURE(hwctx
->device_features
, shaderStorageImageReadWithoutFormat
)
1364 COPY_FEATURE(hwctx
->device_features
, shaderStorageImageWriteWithoutFormat
)
1365 COPY_FEATURE(hwctx
->device_features
, fragmentStoresAndAtomics
)
1366 COPY_FEATURE(hwctx
->device_features
, vertexPipelineStoresAndAtomics
)
1367 COPY_FEATURE(hwctx
->device_features
, shaderInt64
)
1370 /* We require timeline semaphores */
1371 if (!timeline_features
.timelineSemaphore
) {
1372 av_log(ctx
, AV_LOG_ERROR
, "Device does not support timeline semaphores!\n");
1373 err
= AVERROR(ENOSYS
);
1376 p
->device_features_1_2
.timelineSemaphore
= 1;
1378 /* Setup queue family */
1379 if ((err
= setup_queue_families(ctx
, &dev_info
)))
1382 if ((err
= check_extensions(ctx
, 1, opts
, &dev_info
.ppEnabledExtensionNames
,
1383 &dev_info
.enabledExtensionCount
, 0))) {
1384 for (int i
= 0; i
< dev_info
.queueCreateInfoCount
; i
++)
1385 av_free((void *)dev_info
.pQueueCreateInfos
[i
].pQueuePriorities
);
1386 av_free((void *)dev_info
.pQueueCreateInfos
);
1390 ret
= vk
->CreateDevice(hwctx
->phys_dev
, &dev_info
, hwctx
->alloc
,
1393 for (int i
= 0; i
< dev_info
.queueCreateInfoCount
; i
++)
1394 av_free((void *)dev_info
.pQueueCreateInfos
[i
].pQueuePriorities
);
1395 av_free((void *)dev_info
.pQueueCreateInfos
);
1397 if (ret
!= VK_SUCCESS
) {
1398 av_log(ctx
, AV_LOG_ERROR
, "Device creation failure: %s\n",
1400 for (int i
= 0; i
< dev_info
.enabledExtensionCount
; i
++)
1401 av_free((void *)dev_info
.ppEnabledExtensionNames
[i
]);
1402 av_free((void *)dev_info
.ppEnabledExtensionNames
);
1403 err
= AVERROR_EXTERNAL
;
1407 /* Tiled images setting, use them by default */
1408 opt_d
= av_dict_get(opts
, "linear_images", NULL
, 0);
1410 p
->use_linear_images
= strtol(opt_d
->value
, NULL
, 10);
1412 opt_d
= av_dict_get(opts
, "contiguous_planes", NULL
, 0);
1414 p
->contiguous_planes
= strtol(opt_d
->value
, NULL
, 10);
1416 p
->contiguous_planes
= -1;
1418 hwctx
->enabled_dev_extensions
= dev_info
.ppEnabledExtensionNames
;
1419 hwctx
->nb_enabled_dev_extensions
= dev_info
.enabledExtensionCount
;
1425 static int vulkan_device_init(AVHWDeviceContext
*ctx
)
1429 AVVulkanDeviceContext
*hwctx
= ctx
->hwctx
;
1430 VulkanDevicePriv
*p
= ctx
->internal
->priv
;
1431 FFVulkanFunctions
*vk
= &p
->vkfn
;
1432 int graph_index
, comp_index
, tx_index
, enc_index
, dec_index
;
1434 /* Set device extension flags */
1435 for (int i
= 0; i
< hwctx
->nb_enabled_dev_extensions
; i
++) {
1436 for (int j
= 0; j
< FF_ARRAY_ELEMS(optional_device_exts
); j
++) {
1437 if (!strcmp(hwctx
->enabled_dev_extensions
[i
],
1438 optional_device_exts
[j
].name
)) {
1439 p
->extensions
|= optional_device_exts
[j
].flag
;
1445 err
= ff_vk_load_functions(ctx
, vk
, p
->extensions
, 1, 1);
1447 av_log(ctx
, AV_LOG_ERROR
, "Unable to load functions!\n");
1451 p
->props
.sType
= VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2
;
1452 p
->props
.pNext
= &p
->hprops
;
1453 p
->hprops
.sType
= VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT
;
1455 vk
->GetPhysicalDeviceProperties2(hwctx
->phys_dev
, &p
->props
);
1456 av_log(ctx
, AV_LOG_VERBOSE
, "Using device: %s\n",
1457 p
->props
.properties
.deviceName
);
1458 av_log(ctx
, AV_LOG_VERBOSE
, "Alignments:\n");
1459 av_log(ctx
, AV_LOG_VERBOSE
, " optimalBufferCopyRowPitchAlignment: %"PRIu64
"\n",
1460 p
->props
.properties
.limits
.optimalBufferCopyRowPitchAlignment
);
1461 av_log(ctx
, AV_LOG_VERBOSE
, " minMemoryMapAlignment: %"SIZE_SPECIFIER
"\n",
1462 p
->props
.properties
.limits
.minMemoryMapAlignment
);
1463 if (p
->extensions
& FF_VK_EXT_EXTERNAL_HOST_MEMORY
)
1464 av_log(ctx
, AV_LOG_VERBOSE
, " minImportedHostPointerAlignment: %"PRIu64
"\n",
1465 p
->hprops
.minImportedHostPointerAlignment
);
1467 p
->dev_is_nvidia
= (p
->props
.properties
.vendorID
== 0x10de);
1468 p
->dev_is_intel
= (p
->props
.properties
.vendorID
== 0x8086);
1470 vk
->GetPhysicalDeviceQueueFamilyProperties(hwctx
->phys_dev
, &queue_num
, NULL
);
1472 av_log(ctx
, AV_LOG_ERROR
, "Failed to get queues!\n");
1473 return AVERROR_EXTERNAL
;
1476 graph_index
= hwctx
->queue_family_index
;
1477 comp_index
= hwctx
->queue_family_comp_index
;
1478 tx_index
= hwctx
->queue_family_tx_index
;
1479 enc_index
= hwctx
->queue_family_encode_index
;
1480 dec_index
= hwctx
->queue_family_decode_index
;
1482 #define CHECK_QUEUE(type, required, fidx, ctx_qf, qc) \
1484 if (ctx_qf < 0 && required) { \
1485 av_log(ctx, AV_LOG_ERROR, "%s queue family is required, but marked as missing" \
1486 " in the context!\n", type); \
1487 return AVERROR(EINVAL); \
1488 } else if (fidx < 0 || ctx_qf < 0) { \
1490 } else if (ctx_qf >= queue_num) { \
1491 av_log(ctx, AV_LOG_ERROR, "Invalid %s family index %i (device has %i families)!\n", \
1492 type, ctx_qf, queue_num); \
1493 return AVERROR(EINVAL); \
1496 av_log(ctx, AV_LOG_VERBOSE, "Using queue family %i (queues: %i)" \
1497 " for%s%s%s%s%s\n", \
1499 ctx_qf == graph_index ? " graphics" : "", \
1500 ctx_qf == comp_index ? " compute" : "", \
1501 ctx_qf == tx_index ? " transfers" : "", \
1502 ctx_qf == enc_index ? " encode" : "", \
1503 ctx_qf == dec_index ? " decode" : ""); \
1504 graph_index = (ctx_qf == graph_index) ? -1 : graph_index; \
1505 comp_index = (ctx_qf == comp_index) ? -1 : comp_index; \
1506 tx_index = (ctx_qf == tx_index) ? -1 : tx_index; \
1507 enc_index = (ctx_qf == enc_index) ? -1 : enc_index; \
1508 dec_index = (ctx_qf == dec_index) ? -1 : dec_index; \
1509 p->qfs[p->num_qfs++] = ctx_qf; \
1512 CHECK_QUEUE("graphics", 0, graph_index
, hwctx
->queue_family_index
, hwctx
->nb_graphics_queues
);
1513 CHECK_QUEUE("upload", 1, tx_index
, hwctx
->queue_family_tx_index
, hwctx
->nb_tx_queues
);
1514 CHECK_QUEUE("compute", 1, comp_index
, hwctx
->queue_family_comp_index
, hwctx
->nb_comp_queues
);
1515 CHECK_QUEUE("encode", 0, enc_index
, hwctx
->queue_family_encode_index
, hwctx
->nb_encode_queues
);
1516 CHECK_QUEUE("decode", 0, dec_index
, hwctx
->queue_family_decode_index
, hwctx
->nb_decode_queues
);
1520 /* Get device capabilities */
1521 vk
->GetPhysicalDeviceMemoryProperties(hwctx
->phys_dev
, &p
->mprops
);
1526 static int vulkan_device_create(AVHWDeviceContext
*ctx
, const char *device
,
1527 AVDictionary
*opts
, int flags
)
1529 VulkanDeviceSelection dev_select
= { 0 };
1530 if (device
&& device
[0]) {
1532 dev_select
.index
= strtol(device
, &end
, 10);
1533 if (end
== device
) {
1534 dev_select
.index
= 0;
1535 dev_select
.name
= device
;
1539 return vulkan_device_create_internal(ctx
, &dev_select
, opts
, flags
);
1542 static int vulkan_device_derive(AVHWDeviceContext
*ctx
,
1543 AVHWDeviceContext
*src_ctx
,
1544 AVDictionary
*opts
, int flags
)
1546 av_unused VulkanDeviceSelection dev_select
= { 0 };
1548 /* If there's only one device on the system, then even if its not covered
1549 * by the following checks (e.g. non-PCIe ARM GPU), having an empty
1550 * dev_select will mean it'll get picked. */
1551 switch(src_ctx
->type
) {
1554 case AV_HWDEVICE_TYPE_VAAPI
: {
1555 AVVAAPIDeviceContext
*src_hwctx
= src_ctx
->hwctx
;
1557 const char *vendor
= vaQueryVendorString(src_hwctx
->display
);
1559 av_log(ctx
, AV_LOG_ERROR
, "Unable to get device info from VAAPI!\n");
1560 return AVERROR_EXTERNAL
;
1563 if (strstr(vendor
, "Intel"))
1564 dev_select
.vendor_id
= 0x8086;
1565 if (strstr(vendor
, "AMD"))
1566 dev_select
.vendor_id
= 0x1002;
1568 return vulkan_device_create_internal(ctx
, &dev_select
, opts
, flags
);
1571 case AV_HWDEVICE_TYPE_DRM
: {
1572 AVDRMDeviceContext
*src_hwctx
= src_ctx
->hwctx
;
1574 drmDevice
*drm_dev_info
;
1575 int err
= drmGetDevice(src_hwctx
->fd
, &drm_dev_info
);
1577 av_log(ctx
, AV_LOG_ERROR
, "Unable to get device info from DRM fd!\n");
1578 return AVERROR_EXTERNAL
;
1581 if (drm_dev_info
->bustype
== DRM_BUS_PCI
)
1582 dev_select
.pci_device
= drm_dev_info
->deviceinfo
.pci
->device_id
;
1584 drmFreeDevice(&drm_dev_info
);
1586 return vulkan_device_create_internal(ctx
, &dev_select
, opts
, flags
);
1590 case AV_HWDEVICE_TYPE_CUDA
: {
1591 AVHWDeviceContext
*cuda_cu
= src_ctx
;
1592 AVCUDADeviceContext
*src_hwctx
= src_ctx
->hwctx
;
1593 AVCUDADeviceContextInternal
*cu_internal
= src_hwctx
->internal
;
1594 CudaFunctions
*cu
= cu_internal
->cuda_dl
;
1596 int ret
= CHECK_CU(cu
->cuDeviceGetUuid((CUuuid
*)&dev_select
.uuid
,
1597 cu_internal
->cuda_device
));
1599 av_log(ctx
, AV_LOG_ERROR
, "Unable to get UUID from CUDA!\n");
1600 return AVERROR_EXTERNAL
;
1603 dev_select
.has_uuid
= 1;
1605 return vulkan_device_create_internal(ctx
, &dev_select
, opts
, flags
);
1609 return AVERROR(ENOSYS
);
1613 static int vulkan_frames_get_constraints(AVHWDeviceContext
*ctx
,
1614 const void *hwconfig
,
1615 AVHWFramesConstraints
*constraints
)
1618 VulkanDevicePriv
*p
= ctx
->internal
->priv
;
1620 for (enum AVPixelFormat i
= 0; i
< AV_PIX_FMT_NB
; i
++)
1621 count
+= pixfmt_is_supported(ctx
, i
, p
->use_linear_images
);
1624 if (p
->dev_is_nvidia
)
1628 constraints
->valid_sw_formats
= av_malloc_array(count
+ 1,
1629 sizeof(enum AVPixelFormat
));
1630 if (!constraints
->valid_sw_formats
)
1631 return AVERROR(ENOMEM
);
1634 for (enum AVPixelFormat i
= 0; i
< AV_PIX_FMT_NB
; i
++)
1635 if (pixfmt_is_supported(ctx
, i
, p
->use_linear_images
))
1636 constraints
->valid_sw_formats
[count
++] = i
;
1639 if (p
->dev_is_nvidia
)
1640 constraints
->valid_sw_formats
[count
++] = AV_PIX_FMT_CUDA
;
1642 constraints
->valid_sw_formats
[count
++] = AV_PIX_FMT_NONE
;
1644 constraints
->min_width
= 0;
1645 constraints
->min_height
= 0;
1646 constraints
->max_width
= p
->props
.properties
.limits
.maxImageDimension2D
;
1647 constraints
->max_height
= p
->props
.properties
.limits
.maxImageDimension2D
;
1649 constraints
->valid_hw_formats
= av_malloc_array(2, sizeof(enum AVPixelFormat
));
1650 if (!constraints
->valid_hw_formats
)
1651 return AVERROR(ENOMEM
);
1653 constraints
->valid_hw_formats
[0] = AV_PIX_FMT_VULKAN
;
1654 constraints
->valid_hw_formats
[1] = AV_PIX_FMT_NONE
;
1659 static int alloc_mem(AVHWDeviceContext
*ctx
, VkMemoryRequirements
*req
,
1660 VkMemoryPropertyFlagBits req_flags
, const void *alloc_extension
,
1661 VkMemoryPropertyFlagBits
*mem_flags
, VkDeviceMemory
*mem
)
1665 VulkanDevicePriv
*p
= ctx
->internal
->priv
;
1666 FFVulkanFunctions
*vk
= &p
->vkfn
;
1667 AVVulkanDeviceContext
*dev_hwctx
= ctx
->hwctx
;
1668 VkMemoryAllocateInfo alloc_info
= {
1669 .sType
= VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO
,
1670 .pNext
= alloc_extension
,
1671 .allocationSize
= req
->size
,
1674 /* The vulkan spec requires memory types to be sorted in the "optimal"
1675 * order, so the first matching type we find will be the best/fastest one */
1676 for (int i
= 0; i
< p
->mprops
.memoryTypeCount
; i
++) {
1677 const VkMemoryType
*type
= &p
->mprops
.memoryTypes
[i
];
1679 /* The memory type must be supported by the requirements (bitfield) */
1680 if (!(req
->memoryTypeBits
& (1 << i
)))
1683 /* The memory type flags must include our properties */
1684 if ((type
->propertyFlags
& req_flags
) != req_flags
)
1687 /* The memory type must be large enough */
1688 if (req
->size
> p
->mprops
.memoryHeaps
[type
->heapIndex
].size
)
1691 /* Found a suitable memory type */
1697 av_log(ctx
, AV_LOG_ERROR
, "No memory type found for flags 0x%x\n",
1699 return AVERROR(EINVAL
);
1702 alloc_info
.memoryTypeIndex
= index
;
1704 ret
= vk
->AllocateMemory(dev_hwctx
->act_dev
, &alloc_info
,
1705 dev_hwctx
->alloc
, mem
);
1706 if (ret
!= VK_SUCCESS
) {
1707 av_log(ctx
, AV_LOG_ERROR
, "Failed to allocate memory: %s\n",
1709 return AVERROR(ENOMEM
);
1712 *mem_flags
|= p
->mprops
.memoryTypes
[index
].propertyFlags
;
1717 static void vulkan_free_internal(AVVkFrame
*f
)
1719 AVVkFrameInternal
*internal
= f
->internal
;
1725 if (internal
->cuda_fc_ref
) {
1726 AVHWFramesContext
*cuda_fc
= (AVHWFramesContext
*)internal
->cuda_fc_ref
->data
;
1727 int planes
= av_pix_fmt_count_planes(cuda_fc
->sw_format
);
1728 AVHWDeviceContext
*cuda_cu
= cuda_fc
->device_ctx
;
1729 AVCUDADeviceContext
*cuda_dev
= cuda_cu
->hwctx
;
1730 AVCUDADeviceContextInternal
*cu_internal
= cuda_dev
->internal
;
1731 CudaFunctions
*cu
= cu_internal
->cuda_dl
;
1733 for (int i
= 0; i
< planes
; i
++) {
1734 if (internal
->cu_sem
[i
])
1735 CHECK_CU(cu
->cuDestroyExternalSemaphore(internal
->cu_sem
[i
]));
1736 if (internal
->cu_mma
[i
])
1737 CHECK_CU(cu
->cuMipmappedArrayDestroy(internal
->cu_mma
[i
]));
1738 if (internal
->ext_mem
[i
])
1739 CHECK_CU(cu
->cuDestroyExternalMemory(internal
->ext_mem
[i
]));
1741 if (internal
->ext_sem_handle
[i
])
1742 CloseHandle(internal
->ext_sem_handle
[i
]);
1743 if (internal
->ext_mem_handle
[i
])
1744 CloseHandle(internal
->ext_mem_handle
[i
]);
1748 av_buffer_unref(&internal
->cuda_fc_ref
);
1752 av_freep(&f
->internal
);
1755 static void vulkan_frame_free(void *opaque
, uint8_t *data
)
1757 AVVkFrame
*f
= (AVVkFrame
*)data
;
1758 AVHWFramesContext
*hwfc
= opaque
;
1759 AVVulkanDeviceContext
*hwctx
= hwfc
->device_ctx
->hwctx
;
1760 VulkanDevicePriv
*p
= hwfc
->device_ctx
->internal
->priv
;
1761 FFVulkanFunctions
*vk
= &p
->vkfn
;
1762 int planes
= av_pix_fmt_count_planes(hwfc
->sw_format
);
1764 /* We could use vkWaitSemaphores, but the validation layer seems to have
1765 * issues tracking command buffer execution state on uninit. */
1766 vk
->DeviceWaitIdle(hwctx
->act_dev
);
1768 vulkan_free_internal(f
);
1770 for (int i
= 0; i
< planes
; i
++) {
1771 vk
->DestroyImage(hwctx
->act_dev
, f
->img
[i
], hwctx
->alloc
);
1772 vk
->FreeMemory(hwctx
->act_dev
, f
->mem
[i
], hwctx
->alloc
);
1773 vk
->DestroySemaphore(hwctx
->act_dev
, f
->sem
[i
], hwctx
->alloc
);
1779 static int alloc_bind_mem(AVHWFramesContext
*hwfc
, AVVkFrame
*f
,
1780 void *alloc_pnext
, size_t alloc_pnext_stride
)
1784 AVHWDeviceContext
*ctx
= hwfc
->device_ctx
;
1785 VulkanDevicePriv
*p
= ctx
->internal
->priv
;
1786 FFVulkanFunctions
*vk
= &p
->vkfn
;
1787 AVVulkanFramesContext
*hwfctx
= hwfc
->hwctx
;
1788 const int planes
= av_pix_fmt_count_planes(hwfc
->sw_format
);
1789 VkBindImageMemoryInfo bind_info
[AV_NUM_DATA_POINTERS
] = { { 0 } };
1791 VkMemoryRequirements cont_memory_requirements
= { 0 };
1792 int cont_mem_size_list
[AV_NUM_DATA_POINTERS
] = { 0 };
1793 int cont_mem_size
= 0;
1795 AVVulkanDeviceContext
*hwctx
= ctx
->hwctx
;
1797 for (int i
= 0; i
< planes
; i
++) {
1799 VkImageMemoryRequirementsInfo2 req_desc
= {
1800 .sType
= VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2
,
1803 VkMemoryDedicatedAllocateInfo ded_alloc
= {
1804 .sType
= VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO
,
1805 .pNext
= (void *)(((uint8_t *)alloc_pnext
) + i
*alloc_pnext_stride
),
1807 VkMemoryDedicatedRequirements ded_req
= {
1808 .sType
= VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS
,
1810 VkMemoryRequirements2 req
= {
1811 .sType
= VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2
,
1815 vk
->GetImageMemoryRequirements2(hwctx
->act_dev
, &req_desc
, &req
);
1817 if (f
->tiling
== VK_IMAGE_TILING_LINEAR
)
1818 req
.memoryRequirements
.size
= FFALIGN(req
.memoryRequirements
.size
,
1819 p
->props
.properties
.limits
.minMemoryMapAlignment
);
1821 if (hwfctx
->flags
& AV_VK_FRAME_FLAG_CONTIGUOUS_MEMORY
) {
1822 if (ded_req
.requiresDedicatedAllocation
) {
1823 av_log(hwfc
, AV_LOG_ERROR
, "Cannot allocate all planes in a single allocation, "
1824 "device requires dedicated image allocation!\n");
1825 return AVERROR(EINVAL
);
1827 cont_memory_requirements
= req
.memoryRequirements
;
1828 } else if (cont_memory_requirements
.memoryTypeBits
!=
1829 req
.memoryRequirements
.memoryTypeBits
) {
1830 av_log(hwfc
, AV_LOG_ERROR
, "The memory requirements differ between plane 0 "
1831 "and %i, cannot allocate in a single region!\n",
1833 return AVERROR(EINVAL
);
1836 cont_mem_size_list
[i
] = FFALIGN(req
.memoryRequirements
.size
,
1837 req
.memoryRequirements
.alignment
);
1838 cont_mem_size
+= cont_mem_size_list
[i
];
1842 /* In case the implementation prefers/requires dedicated allocation */
1843 use_ded_mem
= ded_req
.prefersDedicatedAllocation
|
1844 ded_req
.requiresDedicatedAllocation
;
1846 ded_alloc
.image
= f
->img
[i
];
1848 /* Allocate memory */
1849 if ((err
= alloc_mem(ctx
, &req
.memoryRequirements
,
1850 f
->tiling
== VK_IMAGE_TILING_LINEAR
?
1851 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
:
1852 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT
,
1853 use_ded_mem
? &ded_alloc
: (void *)ded_alloc
.pNext
,
1854 &f
->flags
, &f
->mem
[i
])))
1857 f
->size
[i
] = req
.memoryRequirements
.size
;
1858 bind_info
[i
].sType
= VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO
;
1859 bind_info
[i
].image
= f
->img
[i
];
1860 bind_info
[i
].memory
= f
->mem
[i
];
1863 if (hwfctx
->flags
& AV_VK_FRAME_FLAG_CONTIGUOUS_MEMORY
) {
1864 cont_memory_requirements
.size
= cont_mem_size
;
1866 /* Allocate memory */
1867 if ((err
= alloc_mem(ctx
, &cont_memory_requirements
,
1868 f
->tiling
== VK_IMAGE_TILING_LINEAR
?
1869 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
:
1870 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT
,
1871 (void *)(((uint8_t *)alloc_pnext
)),
1872 &f
->flags
, &f
->mem
[0])))
1875 f
->size
[0] = cont_memory_requirements
.size
;
1877 for (int i
= 0, offset
= 0; i
< planes
; i
++) {
1878 bind_info
[i
].sType
= VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO
;
1879 bind_info
[i
].image
= f
->img
[i
];
1880 bind_info
[i
].memory
= f
->mem
[0];
1881 bind_info
[i
].memoryOffset
= offset
;
1883 f
->offset
[i
] = bind_info
[i
].memoryOffset
;
1884 offset
+= cont_mem_size_list
[i
];
1888 /* Bind the allocated memory to the images */
1889 ret
= vk
->BindImageMemory2(hwctx
->act_dev
, planes
, bind_info
);
1890 if (ret
!= VK_SUCCESS
) {
1891 av_log(ctx
, AV_LOG_ERROR
, "Failed to bind memory: %s\n",
1893 return AVERROR_EXTERNAL
;
1901 PREP_MODE_EXTERNAL_EXPORT
,
1902 PREP_MODE_EXTERNAL_IMPORT
1905 static int prepare_frame(AVHWFramesContext
*hwfc
, VulkanExecCtx
*ectx
,
1906 AVVkFrame
*frame
, enum PrepMode pmode
)
1909 uint32_t src_qf
, dst_qf
;
1910 VkImageLayout new_layout
;
1911 VkAccessFlags new_access
;
1912 const int planes
= av_pix_fmt_count_planes(hwfc
->sw_format
);
1913 VulkanDevicePriv
*p
= hwfc
->device_ctx
->internal
->priv
;
1914 FFVulkanFunctions
*vk
= &p
->vkfn
;
1915 uint64_t sem_sig_val
[AV_NUM_DATA_POINTERS
];
1917 VkImageMemoryBarrier img_bar
[AV_NUM_DATA_POINTERS
] = { 0 };
1919 VkTimelineSemaphoreSubmitInfo s_timeline_sem_info
= {
1920 .sType
= VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO
,
1921 .pSignalSemaphoreValues
= sem_sig_val
,
1922 .signalSemaphoreValueCount
= planes
,
1925 VkSubmitInfo s_info
= {
1926 .sType
= VK_STRUCTURE_TYPE_SUBMIT_INFO
,
1927 .pNext
= &s_timeline_sem_info
,
1928 .pSignalSemaphores
= frame
->sem
,
1929 .signalSemaphoreCount
= planes
,
1932 VkPipelineStageFlagBits wait_st
[AV_NUM_DATA_POINTERS
];
1933 for (int i
= 0; i
< planes
; i
++) {
1934 wait_st
[i
] = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT
;
1935 sem_sig_val
[i
] = frame
->sem_value
[i
] + 1;
1939 case PREP_MODE_WRITE
:
1940 new_layout
= VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL
;
1941 new_access
= VK_ACCESS_TRANSFER_WRITE_BIT
;
1942 src_qf
= VK_QUEUE_FAMILY_IGNORED
;
1943 dst_qf
= VK_QUEUE_FAMILY_IGNORED
;
1945 case PREP_MODE_EXTERNAL_IMPORT
:
1946 new_layout
= VK_IMAGE_LAYOUT_GENERAL
;
1947 new_access
= VK_ACCESS_MEMORY_READ_BIT
| VK_ACCESS_MEMORY_WRITE_BIT
;
1948 src_qf
= VK_QUEUE_FAMILY_EXTERNAL_KHR
;
1949 dst_qf
= VK_QUEUE_FAMILY_IGNORED
;
1950 s_timeline_sem_info
.pWaitSemaphoreValues
= frame
->sem_value
;
1951 s_timeline_sem_info
.waitSemaphoreValueCount
= planes
;
1952 s_info
.pWaitSemaphores
= frame
->sem
;
1953 s_info
.pWaitDstStageMask
= wait_st
;
1954 s_info
.waitSemaphoreCount
= planes
;
1956 case PREP_MODE_EXTERNAL_EXPORT
:
1957 new_layout
= VK_IMAGE_LAYOUT_GENERAL
;
1958 new_access
= VK_ACCESS_MEMORY_READ_BIT
| VK_ACCESS_MEMORY_WRITE_BIT
;
1959 src_qf
= VK_QUEUE_FAMILY_IGNORED
;
1960 dst_qf
= VK_QUEUE_FAMILY_EXTERNAL_KHR
;
1961 s_timeline_sem_info
.pWaitSemaphoreValues
= frame
->sem_value
;
1962 s_timeline_sem_info
.waitSemaphoreValueCount
= planes
;
1963 s_info
.pWaitSemaphores
= frame
->sem
;
1964 s_info
.pWaitDstStageMask
= wait_st
;
1965 s_info
.waitSemaphoreCount
= planes
;
1969 if ((err
= wait_start_exec_ctx(hwfc
, ectx
)))
1972 /* Change the image layout to something more optimal for writes.
1973 * This also signals the newly created semaphore, making it usable
1974 * for synchronization */
1975 for (int i
= 0; i
< planes
; i
++) {
1976 img_bar
[i
].sType
= VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER
;
1977 img_bar
[i
].srcAccessMask
= 0x0;
1978 img_bar
[i
].dstAccessMask
= new_access
;
1979 img_bar
[i
].oldLayout
= frame
->layout
[i
];
1980 img_bar
[i
].newLayout
= new_layout
;
1981 img_bar
[i
].srcQueueFamilyIndex
= src_qf
;
1982 img_bar
[i
].dstQueueFamilyIndex
= dst_qf
;
1983 img_bar
[i
].image
= frame
->img
[i
];
1984 img_bar
[i
].subresourceRange
.levelCount
= 1;
1985 img_bar
[i
].subresourceRange
.layerCount
= 1;
1986 img_bar
[i
].subresourceRange
.aspectMask
= VK_IMAGE_ASPECT_COLOR_BIT
;
1988 frame
->layout
[i
] = img_bar
[i
].newLayout
;
1989 frame
->access
[i
] = img_bar
[i
].dstAccessMask
;
1992 vk
->CmdPipelineBarrier(get_buf_exec_ctx(hwfc
, ectx
),
1993 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT
,
1994 VK_PIPELINE_STAGE_TRANSFER_BIT
,
1995 0, 0, NULL
, 0, NULL
, planes
, img_bar
);
1997 return submit_exec_ctx(hwfc
, ectx
, &s_info
, frame
, 0);
2000 static inline void get_plane_wh(int *w
, int *h
, enum AVPixelFormat format
,
2001 int frame_w
, int frame_h
, int plane
)
2003 const AVPixFmtDescriptor
*desc
= av_pix_fmt_desc_get(format
);
2005 /* Currently always true unless gray + alpha support is added */
2006 if (!plane
|| (plane
== 3) || desc
->flags
& AV_PIX_FMT_FLAG_RGB
||
2007 !(desc
->flags
& AV_PIX_FMT_FLAG_PLANAR
)) {
2013 *w
= AV_CEIL_RSHIFT(frame_w
, desc
->log2_chroma_w
);
2014 *h
= AV_CEIL_RSHIFT(frame_h
, desc
->log2_chroma_h
);
2017 static int create_frame(AVHWFramesContext
*hwfc
, AVVkFrame
**frame
,
2018 VkImageTiling tiling
, VkImageUsageFlagBits usage
,
2023 AVHWDeviceContext
*ctx
= hwfc
->device_ctx
;
2024 VulkanDevicePriv
*p
= ctx
->internal
->priv
;
2025 FFVulkanFunctions
*vk
= &p
->vkfn
;
2026 AVVulkanDeviceContext
*hwctx
= ctx
->hwctx
;
2027 enum AVPixelFormat format
= hwfc
->sw_format
;
2028 const VkFormat
*img_fmts
= av_vkfmt_from_pixfmt(format
);
2029 const int planes
= av_pix_fmt_count_planes(format
);
2031 VkExportSemaphoreCreateInfo ext_sem_info
= {
2032 .sType
= VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO
,
2034 .handleTypes
= IsWindows8OrGreater()
2035 ? VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT
2036 : VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT
,
2038 .handleTypes
= VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT
,
2042 VkSemaphoreTypeCreateInfo sem_type_info
= {
2043 .sType
= VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO
,
2045 .pNext
= p
->extensions
& FF_VK_EXT_EXTERNAL_WIN32_SEM
? &ext_sem_info
: NULL
,
2047 .pNext
= p
->extensions
& FF_VK_EXT_EXTERNAL_FD_SEM
? &ext_sem_info
: NULL
,
2049 .semaphoreType
= VK_SEMAPHORE_TYPE_TIMELINE
,
2053 VkSemaphoreCreateInfo sem_spawn
= {
2054 .sType
= VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO
,
2055 .pNext
= &sem_type_info
,
2058 AVVkFrame
*f
= av_vk_frame_alloc();
2060 av_log(ctx
, AV_LOG_ERROR
, "Unable to allocate memory for AVVkFrame!\n");
2061 return AVERROR(ENOMEM
);
2064 /* Create the images */
2065 for (int i
= 0; i
< planes
; i
++) {
2066 VkImageCreateInfo create_info
= {
2067 .sType
= VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO
,
2068 .pNext
= create_pnext
,
2069 .imageType
= VK_IMAGE_TYPE_2D
,
2070 .format
= img_fmts
[i
],
2074 .flags
= VK_IMAGE_CREATE_ALIAS_BIT
,
2076 .initialLayout
= VK_IMAGE_LAYOUT_UNDEFINED
,
2078 .samples
= VK_SAMPLE_COUNT_1_BIT
,
2079 .pQueueFamilyIndices
= p
->qfs
,
2080 .queueFamilyIndexCount
= p
->num_qfs
,
2081 .sharingMode
= p
->num_qfs
> 1 ? VK_SHARING_MODE_CONCURRENT
:
2082 VK_SHARING_MODE_EXCLUSIVE
,
2085 get_plane_wh(&create_info
.extent
.width
, &create_info
.extent
.height
,
2086 format
, hwfc
->width
, hwfc
->height
, i
);
2088 ret
= vk
->CreateImage(hwctx
->act_dev
, &create_info
,
2089 hwctx
->alloc
, &f
->img
[i
]);
2090 if (ret
!= VK_SUCCESS
) {
2091 av_log(ctx
, AV_LOG_ERROR
, "Image creation failure: %s\n",
2093 err
= AVERROR(EINVAL
);
2097 /* Create semaphore */
2098 ret
= vk
->CreateSemaphore(hwctx
->act_dev
, &sem_spawn
,
2099 hwctx
->alloc
, &f
->sem
[i
]);
2100 if (ret
!= VK_SUCCESS
) {
2101 av_log(hwctx
, AV_LOG_ERROR
, "Failed to create semaphore: %s\n",
2103 return AVERROR_EXTERNAL
;
2106 f
->layout
[i
] = create_info
.initialLayout
;
2108 f
->sem_value
[i
] = 0;
2118 vulkan_frame_free(hwfc
, (uint8_t *)f
);
2122 /* Checks if an export flag is enabled, and if it is ORs it with *iexp */
2123 static void try_export_flags(AVHWFramesContext
*hwfc
,
2124 VkExternalMemoryHandleTypeFlags
*comp_handle_types
,
2125 VkExternalMemoryHandleTypeFlagBits
*iexp
,
2126 VkExternalMemoryHandleTypeFlagBits exp
)
2129 AVVulkanFramesContext
*hwctx
= hwfc
->hwctx
;
2130 AVVulkanDeviceContext
*dev_hwctx
= hwfc
->device_ctx
->hwctx
;
2131 VulkanDevicePriv
*p
= hwfc
->device_ctx
->internal
->priv
;
2132 FFVulkanFunctions
*vk
= &p
->vkfn
;
2134 const VkImageDrmFormatModifierListCreateInfoEXT
*drm_mod_info
=
2135 vk_find_struct(hwctx
->create_pnext
,
2136 VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT
);
2137 int has_mods
= hwctx
->tiling
== VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT
&& drm_mod_info
;
2140 VkExternalImageFormatProperties eprops
= {
2141 .sType
= VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES_KHR
,
2143 VkImageFormatProperties2 props
= {
2144 .sType
= VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2
,
2147 VkPhysicalDeviceImageDrmFormatModifierInfoEXT phy_dev_mod_info
= {
2148 .sType
= VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT
,
2150 .pQueueFamilyIndices
= p
->qfs
,
2151 .queueFamilyIndexCount
= p
->num_qfs
,
2152 .sharingMode
= p
->num_qfs
> 1 ? VK_SHARING_MODE_CONCURRENT
:
2153 VK_SHARING_MODE_EXCLUSIVE
,
2155 VkPhysicalDeviceExternalImageFormatInfo enext
= {
2156 .sType
= VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO
,
2158 .pNext
= has_mods
? &phy_dev_mod_info
: NULL
,
2160 VkPhysicalDeviceImageFormatInfo2 pinfo
= {
2161 .sType
= VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2
,
2162 .pNext
= !exp
? NULL
: &enext
,
2163 .format
= av_vkfmt_from_pixfmt(hwfc
->sw_format
)[0],
2164 .type
= VK_IMAGE_TYPE_2D
,
2165 .tiling
= hwctx
->tiling
,
2166 .usage
= hwctx
->usage
,
2167 .flags
= VK_IMAGE_CREATE_ALIAS_BIT
,
2170 nb_mods
= has_mods
? drm_mod_info
->drmFormatModifierCount
: 1;
2171 for (int i
= 0; i
< nb_mods
; i
++) {
2173 phy_dev_mod_info
.drmFormatModifier
= drm_mod_info
->pDrmFormatModifiers
[i
];
2175 ret
= vk
->GetPhysicalDeviceImageFormatProperties2(dev_hwctx
->phys_dev
,
2178 if (ret
== VK_SUCCESS
) {
2180 *comp_handle_types
|= eprops
.externalMemoryProperties
.compatibleHandleTypes
;
2185 static AVBufferRef
*vulkan_pool_alloc(void *opaque
, size_t size
)
2189 AVBufferRef
*avbuf
= NULL
;
2190 AVHWFramesContext
*hwfc
= opaque
;
2191 AVVulkanFramesContext
*hwctx
= hwfc
->hwctx
;
2192 VulkanDevicePriv
*p
= hwfc
->device_ctx
->internal
->priv
;
2193 VulkanFramesPriv
*fp
= hwfc
->internal
->priv
;
2194 VkExportMemoryAllocateInfo eminfo
[AV_NUM_DATA_POINTERS
];
2195 VkExternalMemoryHandleTypeFlags e
= 0x0;
2197 VkExternalMemoryImageCreateInfo eiinfo
= {
2198 .sType
= VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO
,
2199 .pNext
= hwctx
->create_pnext
,
2203 if (p
->extensions
& FF_VK_EXT_EXTERNAL_WIN32_MEMORY
)
2204 try_export_flags(hwfc
, &eiinfo
.handleTypes
, &e
, IsWindows8OrGreater()
2205 ? VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT
2206 : VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT
);
2208 if (p
->extensions
& FF_VK_EXT_EXTERNAL_FD_MEMORY
)
2209 try_export_flags(hwfc
, &eiinfo
.handleTypes
, &e
,
2210 VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT
);
2212 if (p
->extensions
& (FF_VK_EXT_EXTERNAL_DMABUF_MEMORY
| FF_VK_EXT_DRM_MODIFIER_FLAGS
))
2213 try_export_flags(hwfc
, &eiinfo
.handleTypes
, &e
,
2214 VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT
);
2217 for (int i
= 0; i
< av_pix_fmt_count_planes(hwfc
->sw_format
); i
++) {
2218 eminfo
[i
].sType
= VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO
;
2219 eminfo
[i
].pNext
= hwctx
->alloc_pnext
[i
];
2220 eminfo
[i
].handleTypes
= e
;
2223 err
= create_frame(hwfc
, &f
, hwctx
->tiling
, hwctx
->usage
,
2224 eiinfo
.handleTypes
? &eiinfo
: NULL
);
2228 err
= alloc_bind_mem(hwfc
, f
, eminfo
, sizeof(*eminfo
));
2232 err
= prepare_frame(hwfc
, &fp
->conv_ctx
, f
, PREP_MODE_WRITE
);
2236 avbuf
= av_buffer_create((uint8_t *)f
, sizeof(AVVkFrame
),
2237 vulkan_frame_free
, hwfc
, 0);
2244 vulkan_frame_free(hwfc
, (uint8_t *)f
);
2248 static void vulkan_frames_uninit(AVHWFramesContext
*hwfc
)
2250 VulkanFramesPriv
*fp
= hwfc
->internal
->priv
;
2252 if (fp
->modifier_info
) {
2253 if (fp
->modifier_info
->pDrmFormatModifiers
)
2254 av_freep(&fp
->modifier_info
->pDrmFormatModifiers
);
2255 av_freep(&fp
->modifier_info
);
2258 free_exec_ctx(hwfc
, &fp
->conv_ctx
);
2259 free_exec_ctx(hwfc
, &fp
->upload_ctx
);
2260 free_exec_ctx(hwfc
, &fp
->download_ctx
);
2263 static int vulkan_frames_init(AVHWFramesContext
*hwfc
)
2267 AVVulkanFramesContext
*hwctx
= hwfc
->hwctx
;
2268 VulkanFramesPriv
*fp
= hwfc
->internal
->priv
;
2269 AVVulkanDeviceContext
*dev_hwctx
= hwfc
->device_ctx
->hwctx
;
2270 VulkanDevicePriv
*p
= hwfc
->device_ctx
->internal
->priv
;
2271 const VkImageDrmFormatModifierListCreateInfoEXT
*modifier_info
;
2272 const int has_modifiers
= !!(p
->extensions
& FF_VK_EXT_DRM_MODIFIER_FLAGS
);
2274 /* Default tiling flags */
2275 hwctx
->tiling
= hwctx
->tiling
? hwctx
->tiling
:
2276 has_modifiers
? VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT
:
2277 p
->use_linear_images
? VK_IMAGE_TILING_LINEAR
:
2278 VK_IMAGE_TILING_OPTIMAL
;
2281 hwctx
->usage
= FF_VK_DEFAULT_USAGE_FLAGS
;
2283 if (!(hwctx
->flags
& AV_VK_FRAME_FLAG_NONE
)) {
2284 if (p
->contiguous_planes
== 1 ||
2285 ((p
->contiguous_planes
== -1) && p
->dev_is_intel
))
2286 hwctx
->flags
|= AV_VK_FRAME_FLAG_CONTIGUOUS_MEMORY
;
2289 modifier_info
= vk_find_struct(hwctx
->create_pnext
,
2290 VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT
);
2292 /* Get the supported modifiers if the user has not given any. */
2293 if (has_modifiers
&& !modifier_info
) {
2294 const VkFormat
*fmt
= av_vkfmt_from_pixfmt(hwfc
->sw_format
);
2295 VkImageDrmFormatModifierListCreateInfoEXT
*modifier_info
;
2296 FFVulkanFunctions
*vk
= &p
->vkfn
;
2297 VkDrmFormatModifierPropertiesEXT
*mod_props
;
2298 uint64_t *modifiers
;
2299 int modifier_count
= 0;
2301 VkDrmFormatModifierPropertiesListEXT mod_props_list
= {
2302 .sType
= VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT
,
2304 .drmFormatModifierCount
= 0,
2305 .pDrmFormatModifierProperties
= NULL
,
2307 VkFormatProperties2 prop
= {
2308 .sType
= VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2
,
2309 .pNext
= &mod_props_list
,
2312 /* Get all supported modifiers */
2313 vk
->GetPhysicalDeviceFormatProperties2(dev_hwctx
->phys_dev
, fmt
[0], &prop
);
2315 if (!mod_props_list
.drmFormatModifierCount
) {
2316 av_log(hwfc
, AV_LOG_ERROR
, "There are no supported modifiers for the given sw_format\n");
2317 return AVERROR(EINVAL
);
2320 /* Createa structure to hold the modifier list info */
2321 modifier_info
= av_mallocz(sizeof(*modifier_info
));
2323 return AVERROR(ENOMEM
);
2325 modifier_info
->pNext
= NULL
;
2326 modifier_info
->sType
= VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT
;
2328 /* Add structure to the image creation pNext chain */
2329 if (!hwctx
->create_pnext
)
2330 hwctx
->create_pnext
= modifier_info
;
2332 vk_link_struct(hwctx
->create_pnext
, (void *)modifier_info
);
2334 /* Backup the allocated struct to be freed later */
2335 fp
->modifier_info
= modifier_info
;
2337 /* Allocate list of modifiers */
2338 modifiers
= av_mallocz(mod_props_list
.drmFormatModifierCount
*
2339 sizeof(*modifiers
));
2341 return AVERROR(ENOMEM
);
2343 modifier_info
->pDrmFormatModifiers
= modifiers
;
2345 /* Allocate a temporary list to hold all modifiers supported */
2346 mod_props
= av_mallocz(mod_props_list
.drmFormatModifierCount
*
2347 sizeof(*mod_props
));
2349 return AVERROR(ENOMEM
);
2351 mod_props_list
.pDrmFormatModifierProperties
= mod_props
;
2353 /* Finally get all modifiers from the device */
2354 vk
->GetPhysicalDeviceFormatProperties2(dev_hwctx
->phys_dev
, fmt
[0], &prop
);
2356 /* Reject any modifiers that don't match our requirements */
2357 for (int i
= 0; i
< mod_props_list
.drmFormatModifierCount
; i
++) {
2358 if (!(mod_props
[i
].drmFormatModifierTilingFeatures
& hwctx
->usage
))
2361 modifiers
[modifier_count
++] = mod_props
[i
].drmFormatModifier
;
2364 if (!modifier_count
) {
2365 av_log(hwfc
, AV_LOG_ERROR
, "None of the given modifiers supports"
2366 " the usage flags!\n");
2367 av_freep(&mod_props
);
2368 return AVERROR(EINVAL
);
2371 modifier_info
->drmFormatModifierCount
= modifier_count
;
2372 av_freep(&mod_props
);
2375 err
= create_exec_ctx(hwfc
, &fp
->conv_ctx
,
2376 dev_hwctx
->queue_family_comp_index
,
2377 dev_hwctx
->nb_comp_queues
);
2381 err
= create_exec_ctx(hwfc
, &fp
->upload_ctx
,
2382 dev_hwctx
->queue_family_tx_index
,
2383 dev_hwctx
->nb_tx_queues
);
2387 err
= create_exec_ctx(hwfc
, &fp
->download_ctx
,
2388 dev_hwctx
->queue_family_tx_index
, 1);
2392 /* Test to see if allocation will fail */
2393 err
= create_frame(hwfc
, &f
, hwctx
->tiling
, hwctx
->usage
,
2394 hwctx
->create_pnext
);
2398 vulkan_frame_free(hwfc
, (uint8_t *)f
);
2400 /* If user did not specify a pool, hwfc->pool will be set to the internal one
2401 * in hwcontext.c just after this gets called */
2403 hwfc
->internal
->pool_internal
= av_buffer_pool_init2(sizeof(AVVkFrame
),
2404 hwfc
, vulkan_pool_alloc
,
2406 if (!hwfc
->internal
->pool_internal
)
2407 return AVERROR(ENOMEM
);
2413 static int vulkan_get_buffer(AVHWFramesContext
*hwfc
, AVFrame
*frame
)
2415 frame
->buf
[0] = av_buffer_pool_get(hwfc
->pool
);
2417 return AVERROR(ENOMEM
);
2419 frame
->data
[0] = frame
->buf
[0]->data
;
2420 frame
->format
= AV_PIX_FMT_VULKAN
;
2421 frame
->width
= hwfc
->width
;
2422 frame
->height
= hwfc
->height
;
2427 static int vulkan_transfer_get_formats(AVHWFramesContext
*hwfc
,
2428 enum AVHWFrameTransferDirection dir
,
2429 enum AVPixelFormat
**formats
)
2431 enum AVPixelFormat
*fmts
= av_malloc_array(2, sizeof(*fmts
));
2433 return AVERROR(ENOMEM
);
2435 fmts
[0] = hwfc
->sw_format
;
2436 fmts
[1] = AV_PIX_FMT_NONE
;
2442 typedef struct VulkanMapping
{
2447 static void vulkan_unmap_frame(AVHWFramesContext
*hwfc
, HWMapDescriptor
*hwmap
)
2449 VulkanMapping
*map
= hwmap
->priv
;
2450 AVVulkanDeviceContext
*hwctx
= hwfc
->device_ctx
->hwctx
;
2451 const int planes
= av_pix_fmt_count_planes(hwfc
->sw_format
);
2452 VulkanDevicePriv
*p
= hwfc
->device_ctx
->internal
->priv
;
2453 FFVulkanFunctions
*vk
= &p
->vkfn
;
2455 /* Check if buffer needs flushing */
2456 if ((map
->flags
& AV_HWFRAME_MAP_WRITE
) &&
2457 !(map
->frame
->flags
& VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
)) {
2459 VkMappedMemoryRange flush_ranges
[AV_NUM_DATA_POINTERS
] = { { 0 } };
2461 for (int i
= 0; i
< planes
; i
++) {
2462 flush_ranges
[i
].sType
= VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE
;
2463 flush_ranges
[i
].memory
= map
->frame
->mem
[i
];
2464 flush_ranges
[i
].size
= VK_WHOLE_SIZE
;
2467 ret
= vk
->FlushMappedMemoryRanges(hwctx
->act_dev
, planes
,
2469 if (ret
!= VK_SUCCESS
) {
2470 av_log(hwfc
, AV_LOG_ERROR
, "Failed to flush memory: %s\n",
2475 for (int i
= 0; i
< planes
; i
++)
2476 vk
->UnmapMemory(hwctx
->act_dev
, map
->frame
->mem
[i
]);
2481 static int vulkan_map_frame_to_mem(AVHWFramesContext
*hwfc
, AVFrame
*dst
,
2482 const AVFrame
*src
, int flags
)
2485 int err
, mapped_mem_count
= 0, mem_planes
= 0;
2486 AVVkFrame
*f
= (AVVkFrame
*)src
->data
[0];
2487 AVVulkanDeviceContext
*hwctx
= hwfc
->device_ctx
->hwctx
;
2488 AVVulkanFramesContext
*hwfctx
= hwfc
->hwctx
;
2489 const int planes
= av_pix_fmt_count_planes(hwfc
->sw_format
);
2490 VulkanDevicePriv
*p
= hwfc
->device_ctx
->internal
->priv
;
2491 FFVulkanFunctions
*vk
= &p
->vkfn
;
2493 VulkanMapping
*map
= av_mallocz(sizeof(VulkanMapping
));
2495 return AVERROR(EINVAL
);
2497 if (src
->format
!= AV_PIX_FMT_VULKAN
) {
2498 av_log(hwfc
, AV_LOG_ERROR
, "Cannot map from pixel format %s!\n",
2499 av_get_pix_fmt_name(src
->format
));
2500 err
= AVERROR(EINVAL
);
2504 if (!(f
->flags
& VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
) ||
2505 !(f
->tiling
== VK_IMAGE_TILING_LINEAR
)) {
2506 av_log(hwfc
, AV_LOG_ERROR
, "Unable to map frame, not host visible "
2508 err
= AVERROR(EINVAL
);
2512 dst
->width
= src
->width
;
2513 dst
->height
= src
->height
;
2515 mem_planes
= hwfctx
->flags
& AV_VK_FRAME_FLAG_CONTIGUOUS_MEMORY
? 1 : planes
;
2516 for (int i
= 0; i
< mem_planes
; i
++) {
2517 ret
= vk
->MapMemory(hwctx
->act_dev
, f
->mem
[i
], 0,
2518 VK_WHOLE_SIZE
, 0, (void **)&dst
->data
[i
]);
2519 if (ret
!= VK_SUCCESS
) {
2520 av_log(hwfc
, AV_LOG_ERROR
, "Failed to map image memory: %s\n",
2522 err
= AVERROR_EXTERNAL
;
2528 if (hwfctx
->flags
& AV_VK_FRAME_FLAG_CONTIGUOUS_MEMORY
) {
2529 for (int i
= 0; i
< planes
; i
++)
2530 dst
->data
[i
] = dst
->data
[0] + f
->offset
[i
];
2533 /* Check if the memory contents matter */
2534 if (((flags
& AV_HWFRAME_MAP_READ
) || !(flags
& AV_HWFRAME_MAP_OVERWRITE
)) &&
2535 !(f
->flags
& VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
)) {
2536 VkMappedMemoryRange map_mem_ranges
[AV_NUM_DATA_POINTERS
] = { { 0 } };
2537 for (int i
= 0; i
< planes
; i
++) {
2538 map_mem_ranges
[i
].sType
= VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE
;
2539 map_mem_ranges
[i
].size
= VK_WHOLE_SIZE
;
2540 map_mem_ranges
[i
].memory
= f
->mem
[i
];
2543 ret
= vk
->InvalidateMappedMemoryRanges(hwctx
->act_dev
, planes
,
2545 if (ret
!= VK_SUCCESS
) {
2546 av_log(hwfc
, AV_LOG_ERROR
, "Failed to invalidate memory: %s\n",
2548 err
= AVERROR_EXTERNAL
;
2553 for (int i
= 0; i
< planes
; i
++) {
2554 VkImageSubresource sub
= {
2555 .aspectMask
= VK_IMAGE_ASPECT_COLOR_BIT
,
2557 VkSubresourceLayout layout
;
2558 vk
->GetImageSubresourceLayout(hwctx
->act_dev
, f
->img
[i
], &sub
, &layout
);
2559 dst
->linesize
[i
] = layout
.rowPitch
;
2565 err
= ff_hwframe_map_create(src
->hw_frames_ctx
, dst
, src
,
2566 &vulkan_unmap_frame
, map
);
2573 for (int i
= 0; i
< mapped_mem_count
; i
++)
2574 vk
->UnmapMemory(hwctx
->act_dev
, f
->mem
[i
]);
2581 static void vulkan_unmap_from_drm(AVHWFramesContext
*hwfc
, HWMapDescriptor
*hwmap
)
2583 AVVkFrame
*f
= hwmap
->priv
;
2584 AVVulkanDeviceContext
*hwctx
= hwfc
->device_ctx
->hwctx
;
2585 const int planes
= av_pix_fmt_count_planes(hwfc
->sw_format
);
2586 VulkanDevicePriv
*p
= hwfc
->device_ctx
->internal
->priv
;
2587 FFVulkanFunctions
*vk
= &p
->vkfn
;
2589 VkSemaphoreWaitInfo wait_info
= {
2590 .sType
= VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO
,
2592 .pSemaphores
= f
->sem
,
2593 .pValues
= f
->sem_value
,
2594 .semaphoreCount
= planes
,
2597 vk
->WaitSemaphores(hwctx
->act_dev
, &wait_info
, UINT64_MAX
);
2599 vulkan_free_internal(f
);
2601 for (int i
= 0; i
< planes
; i
++) {
2602 vk
->DestroyImage(hwctx
->act_dev
, f
->img
[i
], hwctx
->alloc
);
2603 vk
->FreeMemory(hwctx
->act_dev
, f
->mem
[i
], hwctx
->alloc
);
2604 vk
->DestroySemaphore(hwctx
->act_dev
, f
->sem
[i
], hwctx
->alloc
);
2610 static const struct {
2611 uint32_t drm_fourcc
;
2613 } vulkan_drm_format_map
[] = {
2614 { DRM_FORMAT_R8
, VK_FORMAT_R8_UNORM
},
2615 { DRM_FORMAT_R16
, VK_FORMAT_R16_UNORM
},
2616 { DRM_FORMAT_GR88
, VK_FORMAT_R8G8_UNORM
},
2617 { DRM_FORMAT_RG88
, VK_FORMAT_R8G8_UNORM
},
2618 { DRM_FORMAT_GR1616
, VK_FORMAT_R16G16_UNORM
},
2619 { DRM_FORMAT_RG1616
, VK_FORMAT_R16G16_UNORM
},
2620 { DRM_FORMAT_ARGB8888
, VK_FORMAT_B8G8R8A8_UNORM
},
2621 { DRM_FORMAT_XRGB8888
, VK_FORMAT_B8G8R8A8_UNORM
},
2622 { DRM_FORMAT_ABGR8888
, VK_FORMAT_R8G8B8A8_UNORM
},
2623 { DRM_FORMAT_XBGR8888
, VK_FORMAT_R8G8B8A8_UNORM
},
2626 static inline VkFormat
drm_to_vulkan_fmt(uint32_t drm_fourcc
)
2628 for (int i
= 0; i
< FF_ARRAY_ELEMS(vulkan_drm_format_map
); i
++)
2629 if (vulkan_drm_format_map
[i
].drm_fourcc
== drm_fourcc
)
2630 return vulkan_drm_format_map
[i
].vk_format
;
2631 return VK_FORMAT_UNDEFINED
;
2634 static int vulkan_map_from_drm_frame_desc(AVHWFramesContext
*hwfc
, AVVkFrame
**frame
,
2640 int bind_counts
= 0;
2641 AVHWDeviceContext
*ctx
= hwfc
->device_ctx
;
2642 AVVulkanDeviceContext
*hwctx
= ctx
->hwctx
;
2643 VulkanDevicePriv
*p
= ctx
->internal
->priv
;
2644 FFVulkanFunctions
*vk
= &p
->vkfn
;
2645 VulkanFramesPriv
*fp
= hwfc
->internal
->priv
;
2646 const AVDRMFrameDescriptor
*desc
= (AVDRMFrameDescriptor
*)src
->data
[0];
2647 VkBindImageMemoryInfo bind_info
[AV_DRM_MAX_PLANES
];
2648 VkBindImagePlaneMemoryInfo plane_info
[AV_DRM_MAX_PLANES
];
2650 for (int i
= 0; i
< desc
->nb_layers
; i
++) {
2651 if (drm_to_vulkan_fmt(desc
->layers
[i
].format
) == VK_FORMAT_UNDEFINED
) {
2652 av_log(ctx
, AV_LOG_ERROR
, "Unsupported DMABUF layer format %#08x!\n",
2653 desc
->layers
[i
].format
);
2654 return AVERROR(EINVAL
);
2658 if (!(f
= av_vk_frame_alloc())) {
2659 av_log(ctx
, AV_LOG_ERROR
, "Unable to allocate memory for AVVkFrame!\n");
2660 err
= AVERROR(ENOMEM
);
2664 f
->tiling
= VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT
;
2666 for (int i
= 0; i
< desc
->nb_layers
; i
++) {
2667 const int planes
= desc
->layers
[i
].nb_planes
;
2670 VkSemaphoreTypeCreateInfo sem_type_info
= {
2671 .sType
= VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO
,
2672 .semaphoreType
= VK_SEMAPHORE_TYPE_TIMELINE
,
2675 VkSemaphoreCreateInfo sem_spawn
= {
2676 .sType
= VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO
,
2677 .pNext
= &sem_type_info
,
2680 /* Image creation */
2681 VkSubresourceLayout ext_img_layouts
[AV_DRM_MAX_PLANES
];
2682 VkImageDrmFormatModifierExplicitCreateInfoEXT ext_img_mod_spec
= {
2683 .sType
= VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT
,
2684 .drmFormatModifier
= desc
->objects
[0].format_modifier
,
2685 .drmFormatModifierPlaneCount
= planes
,
2686 .pPlaneLayouts
= (const VkSubresourceLayout
*)&ext_img_layouts
,
2688 VkExternalMemoryImageCreateInfo ext_img_spec
= {
2689 .sType
= VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO
,
2690 .pNext
= &ext_img_mod_spec
,
2691 .handleTypes
= VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT
,
2693 VkImageCreateInfo create_info
= {
2694 .sType
= VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO
,
2695 .pNext
= &ext_img_spec
,
2696 .imageType
= VK_IMAGE_TYPE_2D
,
2697 .format
= drm_to_vulkan_fmt(desc
->layers
[i
].format
),
2701 .flags
= 0x0, /* ALIAS flag is implicit for imported images */
2702 .tiling
= f
->tiling
,
2703 .initialLayout
= VK_IMAGE_LAYOUT_UNDEFINED
, /* specs say so */
2704 .usage
= VK_IMAGE_USAGE_SAMPLED_BIT
|
2705 VK_IMAGE_USAGE_TRANSFER_SRC_BIT
,
2706 .samples
= VK_SAMPLE_COUNT_1_BIT
,
2707 .pQueueFamilyIndices
= p
->qfs
,
2708 .queueFamilyIndexCount
= p
->num_qfs
,
2709 .sharingMode
= p
->num_qfs
> 1 ? VK_SHARING_MODE_CONCURRENT
:
2710 VK_SHARING_MODE_EXCLUSIVE
,
2713 /* Image format verification */
2714 VkExternalImageFormatProperties ext_props
= {
2715 .sType
= VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES_KHR
,
2717 VkImageFormatProperties2 props_ret
= {
2718 .sType
= VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2
,
2719 .pNext
= &ext_props
,
2721 VkPhysicalDeviceImageDrmFormatModifierInfoEXT props_drm_mod
= {
2722 .sType
= VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT
,
2723 .drmFormatModifier
= ext_img_mod_spec
.drmFormatModifier
,
2724 .pQueueFamilyIndices
= create_info
.pQueueFamilyIndices
,
2725 .queueFamilyIndexCount
= create_info
.queueFamilyIndexCount
,
2726 .sharingMode
= create_info
.sharingMode
,
2728 VkPhysicalDeviceExternalImageFormatInfo props_ext
= {
2729 .sType
= VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO
,
2730 .pNext
= &props_drm_mod
,
2731 .handleType
= ext_img_spec
.handleTypes
,
2733 VkPhysicalDeviceImageFormatInfo2 fmt_props
= {
2734 .sType
= VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2
,
2735 .pNext
= &props_ext
,
2736 .format
= create_info
.format
,
2737 .type
= create_info
.imageType
,
2738 .tiling
= create_info
.tiling
,
2739 .usage
= create_info
.usage
,
2740 .flags
= create_info
.flags
,
2743 /* Check if importing is possible for this combination of parameters */
2744 ret
= vk
->GetPhysicalDeviceImageFormatProperties2(hwctx
->phys_dev
,
2745 &fmt_props
, &props_ret
);
2746 if (ret
!= VK_SUCCESS
) {
2747 av_log(ctx
, AV_LOG_ERROR
, "Cannot map DRM frame to Vulkan: %s\n",
2749 err
= AVERROR_EXTERNAL
;
2753 /* Set the image width/height */
2754 get_plane_wh(&create_info
.extent
.width
, &create_info
.extent
.height
,
2755 hwfc
->sw_format
, src
->width
, src
->height
, i
);
2757 /* Set the subresource layout based on the layer properties */
2758 for (int j
= 0; j
< planes
; j
++) {
2759 ext_img_layouts
[j
].offset
= desc
->layers
[i
].planes
[j
].offset
;
2760 ext_img_layouts
[j
].rowPitch
= desc
->layers
[i
].planes
[j
].pitch
;
2761 ext_img_layouts
[j
].size
= 0; /* The specs say so for all 3 */
2762 ext_img_layouts
[j
].arrayPitch
= 0;
2763 ext_img_layouts
[j
].depthPitch
= 0;
2767 ret
= vk
->CreateImage(hwctx
->act_dev
, &create_info
,
2768 hwctx
->alloc
, &f
->img
[i
]);
2769 if (ret
!= VK_SUCCESS
) {
2770 av_log(ctx
, AV_LOG_ERROR
, "Image creation failure: %s\n",
2772 err
= AVERROR(EINVAL
);
2776 ret
= vk
->CreateSemaphore(hwctx
->act_dev
, &sem_spawn
,
2777 hwctx
->alloc
, &f
->sem
[i
]);
2778 if (ret
!= VK_SUCCESS
) {
2779 av_log(hwctx
, AV_LOG_ERROR
, "Failed to create semaphore: %s\n",
2781 return AVERROR_EXTERNAL
;
2784 /* We'd import a semaphore onto the one we created using
2785 * vkImportSemaphoreFdKHR but unfortunately neither DRM nor VAAPI
2786 * offer us anything we could import and sync with, so instead
2787 * just signal the semaphore we created. */
2789 f
->layout
[i
] = create_info
.initialLayout
;
2791 f
->sem_value
[i
] = 0;
2794 for (int i
= 0; i
< desc
->nb_objects
; i
++) {
2795 /* Memory requirements */
2796 VkImageMemoryRequirementsInfo2 req_desc
= {
2797 .sType
= VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2
,
2800 VkMemoryDedicatedRequirements ded_req
= {
2801 .sType
= VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS
,
2803 VkMemoryRequirements2 req2
= {
2804 .sType
= VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2
,
2808 /* Allocation/importing */
2809 VkMemoryFdPropertiesKHR fdmp
= {
2810 .sType
= VK_STRUCTURE_TYPE_MEMORY_FD_PROPERTIES_KHR
,
2812 VkImportMemoryFdInfoKHR idesc
= {
2813 .sType
= VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR
,
2814 .fd
= dup(desc
->objects
[i
].fd
),
2815 .handleType
= VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT
,
2817 VkMemoryDedicatedAllocateInfo ded_alloc
= {
2818 .sType
= VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO
,
2820 .image
= req_desc
.image
,
2823 /* Get object properties */
2824 ret
= vk
->GetMemoryFdPropertiesKHR(hwctx
->act_dev
,
2825 VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT
,
2827 if (ret
!= VK_SUCCESS
) {
2828 av_log(hwfc
, AV_LOG_ERROR
, "Failed to get FD properties: %s\n",
2830 err
= AVERROR_EXTERNAL
;
2835 vk
->GetImageMemoryRequirements2(hwctx
->act_dev
, &req_desc
, &req2
);
2837 /* Only a single bit must be set, not a range, and it must match */
2838 req2
.memoryRequirements
.memoryTypeBits
= fdmp
.memoryTypeBits
;
2840 err
= alloc_mem(ctx
, &req2
.memoryRequirements
,
2841 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT
,
2842 (ded_req
.prefersDedicatedAllocation
||
2843 ded_req
.requiresDedicatedAllocation
) ?
2844 &ded_alloc
: ded_alloc
.pNext
,
2845 &f
->flags
, &f
->mem
[i
]);
2851 f
->size
[i
] = req2
.memoryRequirements
.size
;
2854 for (int i
= 0; i
< desc
->nb_layers
; i
++) {
2855 const int planes
= desc
->layers
[i
].nb_planes
;
2856 for (int j
= 0; j
< planes
; j
++) {
2857 VkImageAspectFlagBits aspect
= j
== 0 ? VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT
:
2858 j
== 1 ? VK_IMAGE_ASPECT_MEMORY_PLANE_1_BIT_EXT
:
2859 VK_IMAGE_ASPECT_MEMORY_PLANE_2_BIT_EXT
;
2861 plane_info
[bind_counts
].sType
= VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO
;
2862 plane_info
[bind_counts
].pNext
= NULL
;
2863 plane_info
[bind_counts
].planeAspect
= aspect
;
2865 bind_info
[bind_counts
].sType
= VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO
;
2866 bind_info
[bind_counts
].pNext
= planes
> 1 ? &plane_info
[bind_counts
] : NULL
;
2867 bind_info
[bind_counts
].image
= f
->img
[i
];
2868 bind_info
[bind_counts
].memory
= f
->mem
[desc
->layers
[i
].planes
[j
].object_index
];
2870 /* Offset is already signalled via pPlaneLayouts above */
2871 bind_info
[bind_counts
].memoryOffset
= 0;
2877 /* Bind the allocated memory to the images */
2878 ret
= vk
->BindImageMemory2(hwctx
->act_dev
, bind_counts
, bind_info
);
2879 if (ret
!= VK_SUCCESS
) {
2880 av_log(ctx
, AV_LOG_ERROR
, "Failed to bind memory: %s\n",
2882 err
= AVERROR_EXTERNAL
;
2886 err
= prepare_frame(hwfc
, &fp
->conv_ctx
, f
, PREP_MODE_EXTERNAL_IMPORT
);
2895 for (int i
= 0; i
< desc
->nb_layers
; i
++) {
2896 vk
->DestroyImage(hwctx
->act_dev
, f
->img
[i
], hwctx
->alloc
);
2897 vk
->DestroySemaphore(hwctx
->act_dev
, f
->sem
[i
], hwctx
->alloc
);
2899 for (int i
= 0; i
< desc
->nb_objects
; i
++)
2900 vk
->FreeMemory(hwctx
->act_dev
, f
->mem
[i
], hwctx
->alloc
);
2907 static int vulkan_map_from_drm(AVHWFramesContext
*hwfc
, AVFrame
*dst
,
2908 const AVFrame
*src
, int flags
)
2913 if ((err
= vulkan_map_from_drm_frame_desc(hwfc
, &f
, src
)))
2916 /* The unmapping function will free this */
2917 dst
->data
[0] = (uint8_t *)f
;
2918 dst
->width
= src
->width
;
2919 dst
->height
= src
->height
;
2921 err
= ff_hwframe_map_create(dst
->hw_frames_ctx
, dst
, src
,
2922 &vulkan_unmap_from_drm
, f
);
2926 av_log(hwfc
, AV_LOG_DEBUG
, "Mapped DRM object to Vulkan!\n");
2931 vulkan_frame_free(hwfc
->device_ctx
->hwctx
, (uint8_t *)f
);
2932 dst
->data
[0] = NULL
;
2937 static int vulkan_map_from_vaapi(AVHWFramesContext
*dst_fc
,
2938 AVFrame
*dst
, const AVFrame
*src
,
2942 AVFrame
*tmp
= av_frame_alloc();
2943 AVHWFramesContext
*vaapi_fc
= (AVHWFramesContext
*)src
->hw_frames_ctx
->data
;
2944 AVVAAPIDeviceContext
*vaapi_ctx
= vaapi_fc
->device_ctx
->hwctx
;
2945 VASurfaceID surface_id
= (VASurfaceID
)(uintptr_t)src
->data
[3];
2948 return AVERROR(ENOMEM
);
2950 /* We have to sync since like the previous comment said, no semaphores */
2951 vaSyncSurface(vaapi_ctx
->display
, surface_id
);
2953 tmp
->format
= AV_PIX_FMT_DRM_PRIME
;
2955 err
= av_hwframe_map(tmp
, src
, flags
);
2959 err
= vulkan_map_from_drm(dst_fc
, dst
, tmp
, flags
);
2963 err
= ff_hwframe_map_replace(dst
, src
);
2966 av_frame_free(&tmp
);
2973 static int vulkan_export_to_cuda(AVHWFramesContext
*hwfc
,
2974 AVBufferRef
*cuda_hwfc
,
2975 const AVFrame
*frame
)
2980 AVVkFrameInternal
*dst_int
;
2981 AVHWDeviceContext
*ctx
= hwfc
->device_ctx
;
2982 AVVulkanDeviceContext
*hwctx
= ctx
->hwctx
;
2983 const int planes
= av_pix_fmt_count_planes(hwfc
->sw_format
);
2984 const AVPixFmtDescriptor
*desc
= av_pix_fmt_desc_get(hwfc
->sw_format
);
2985 VulkanDevicePriv
*p
= ctx
->internal
->priv
;
2986 FFVulkanFunctions
*vk
= &p
->vkfn
;
2988 AVHWFramesContext
*cuda_fc
= (AVHWFramesContext
*)cuda_hwfc
->data
;
2989 AVHWDeviceContext
*cuda_cu
= cuda_fc
->device_ctx
;
2990 AVCUDADeviceContext
*cuda_dev
= cuda_cu
->hwctx
;
2991 AVCUDADeviceContextInternal
*cu_internal
= cuda_dev
->internal
;
2992 CudaFunctions
*cu
= cu_internal
->cuda_dl
;
2993 CUarray_format cufmt
= desc
->comp
[0].depth
> 8 ? CU_AD_FORMAT_UNSIGNED_INT16
:
2994 CU_AD_FORMAT_UNSIGNED_INT8
;
2996 dst_f
= (AVVkFrame
*)frame
->data
[0];
2998 dst_int
= dst_f
->internal
;
2999 if (!dst_int
|| !dst_int
->cuda_fc_ref
) {
3000 if (!dst_f
->internal
)
3001 dst_f
->internal
= dst_int
= av_mallocz(sizeof(*dst_f
->internal
));
3004 return AVERROR(ENOMEM
);
3006 dst_int
->cuda_fc_ref
= av_buffer_ref(cuda_hwfc
);
3007 if (!dst_int
->cuda_fc_ref
) {
3008 av_freep(&dst_f
->internal
);
3009 return AVERROR(ENOMEM
);
3012 for (int i
= 0; i
< planes
; i
++) {
3013 CUDA_EXTERNAL_MEMORY_MIPMAPPED_ARRAY_DESC tex_desc
= {
3018 .NumChannels
= 1 + ((planes
== 2) && i
),
3026 CUDA_EXTERNAL_MEMORY_HANDLE_DESC ext_desc
= {
3027 .type
= IsWindows8OrGreater()
3028 ? CU_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32
3029 : CU_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT
,
3030 .size
= dst_f
->size
[i
],
3032 VkMemoryGetWin32HandleInfoKHR export_info
= {
3033 .sType
= VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR
,
3034 .memory
= dst_f
->mem
[i
],
3035 .handleType
= IsWindows8OrGreater()
3036 ? VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT
3037 : VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT
,
3039 VkSemaphoreGetWin32HandleInfoKHR sem_export
= {
3040 .sType
= VK_STRUCTURE_TYPE_SEMAPHORE_GET_WIN32_HANDLE_INFO_KHR
,
3041 .semaphore
= dst_f
->sem
[i
],
3042 .handleType
= IsWindows8OrGreater()
3043 ? VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT
3044 : VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT
,
3046 CUDA_EXTERNAL_SEMAPHORE_HANDLE_DESC ext_sem_desc
= {
3047 .type
= 10 /* TODO: CU_EXTERNAL_SEMAPHORE_HANDLE_TYPE_TIMELINE_SEMAPHORE_WIN32 */,
3050 ret
= vk
->GetMemoryWin32HandleKHR(hwctx
->act_dev
, &export_info
,
3051 &ext_desc
.handle
.win32
.handle
);
3052 if (ret
!= VK_SUCCESS
) {
3053 av_log(hwfc
, AV_LOG_ERROR
, "Unable to export the image as a Win32 Handle: %s!\n",
3055 err
= AVERROR_EXTERNAL
;
3058 dst_int
->ext_mem_handle
[i
] = ext_desc
.handle
.win32
.handle
;
3060 CUDA_EXTERNAL_MEMORY_HANDLE_DESC ext_desc
= {
3061 .type
= CU_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD
,
3062 .size
= dst_f
->size
[i
],
3064 VkMemoryGetFdInfoKHR export_info
= {
3065 .sType
= VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR
,
3066 .memory
= dst_f
->mem
[i
],
3067 .handleType
= VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR
,
3069 VkSemaphoreGetFdInfoKHR sem_export
= {
3070 .sType
= VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR
,
3071 .semaphore
= dst_f
->sem
[i
],
3072 .handleType
= VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT
,
3074 CUDA_EXTERNAL_SEMAPHORE_HANDLE_DESC ext_sem_desc
= {
3075 .type
= 9 /* TODO: CU_EXTERNAL_SEMAPHORE_HANDLE_TYPE_TIMELINE_SEMAPHORE_FD */,
3078 ret
= vk
->GetMemoryFdKHR(hwctx
->act_dev
, &export_info
,
3079 &ext_desc
.handle
.fd
);
3080 if (ret
!= VK_SUCCESS
) {
3081 av_log(hwfc
, AV_LOG_ERROR
, "Unable to export the image as a FD: %s!\n",
3083 err
= AVERROR_EXTERNAL
;
3088 ret
= CHECK_CU(cu
->cuImportExternalMemory(&dst_int
->ext_mem
[i
], &ext_desc
));
3091 close(ext_desc
.handle
.fd
);
3093 err
= AVERROR_EXTERNAL
;
3097 get_plane_wh(&p_w
, &p_h
, hwfc
->sw_format
, hwfc
->width
, hwfc
->height
, i
);
3098 tex_desc
.arrayDesc
.Width
= p_w
;
3099 tex_desc
.arrayDesc
.Height
= p_h
;
3101 ret
= CHECK_CU(cu
->cuExternalMemoryGetMappedMipmappedArray(&dst_int
->cu_mma
[i
],
3102 dst_int
->ext_mem
[i
],
3105 err
= AVERROR_EXTERNAL
;
3109 ret
= CHECK_CU(cu
->cuMipmappedArrayGetLevel(&dst_int
->cu_array
[i
],
3110 dst_int
->cu_mma
[i
], 0));
3112 err
= AVERROR_EXTERNAL
;
3117 ret
= vk
->GetSemaphoreWin32HandleKHR(hwctx
->act_dev
, &sem_export
,
3118 &ext_sem_desc
.handle
.win32
.handle
);
3120 ret
= vk
->GetSemaphoreFdKHR(hwctx
->act_dev
, &sem_export
,
3121 &ext_sem_desc
.handle
.fd
);
3123 if (ret
!= VK_SUCCESS
) {
3124 av_log(ctx
, AV_LOG_ERROR
, "Failed to export semaphore: %s\n",
3126 err
= AVERROR_EXTERNAL
;
3130 dst_int
->ext_sem_handle
[i
] = ext_sem_desc
.handle
.win32
.handle
;
3133 ret
= CHECK_CU(cu
->cuImportExternalSemaphore(&dst_int
->cu_sem
[i
],
3137 close(ext_sem_desc
.handle
.fd
);
3139 err
= AVERROR_EXTERNAL
;
3148 vulkan_free_internal(dst_f
);
3152 static int vulkan_transfer_data_from_cuda(AVHWFramesContext
*hwfc
,
3153 AVFrame
*dst
, const AVFrame
*src
)
3158 AVVkFrameInternal
*dst_int
;
3159 VulkanFramesPriv
*fp
= hwfc
->internal
->priv
;
3160 const int planes
= av_pix_fmt_count_planes(hwfc
->sw_format
);
3161 const AVPixFmtDescriptor
*desc
= av_pix_fmt_desc_get(hwfc
->sw_format
);
3163 AVHWFramesContext
*cuda_fc
= (AVHWFramesContext
*)src
->hw_frames_ctx
->data
;
3164 AVHWDeviceContext
*cuda_cu
= cuda_fc
->device_ctx
;
3165 AVCUDADeviceContext
*cuda_dev
= cuda_cu
->hwctx
;
3166 AVCUDADeviceContextInternal
*cu_internal
= cuda_dev
->internal
;
3167 CudaFunctions
*cu
= cu_internal
->cuda_dl
;
3168 CUDA_EXTERNAL_SEMAPHORE_WAIT_PARAMS s_w_par
[AV_NUM_DATA_POINTERS
] = { 0 };
3169 CUDA_EXTERNAL_SEMAPHORE_SIGNAL_PARAMS s_s_par
[AV_NUM_DATA_POINTERS
] = { 0 };
3171 dst_f
= (AVVkFrame
*)dst
->data
[0];
3173 err
= prepare_frame(hwfc
, &fp
->upload_ctx
, dst_f
, PREP_MODE_EXTERNAL_EXPORT
);
3177 err
= CHECK_CU(cu
->cuCtxPushCurrent(cuda_dev
->cuda_ctx
));
3181 err
= vulkan_export_to_cuda(hwfc
, src
->hw_frames_ctx
, dst
);
3183 CHECK_CU(cu
->cuCtxPopCurrent(&dummy
));
3187 dst_int
= dst_f
->internal
;
3189 for (int i
= 0; i
< planes
; i
++) {
3190 s_w_par
[i
].params
.fence
.value
= dst_f
->sem_value
[i
] + 0;
3191 s_s_par
[i
].params
.fence
.value
= dst_f
->sem_value
[i
] + 1;
3194 err
= CHECK_CU(cu
->cuWaitExternalSemaphoresAsync(dst_int
->cu_sem
, s_w_par
,
3195 planes
, cuda_dev
->stream
));
3199 for (int i
= 0; i
< planes
; i
++) {
3200 CUDA_MEMCPY2D cpy
= {
3201 .srcMemoryType
= CU_MEMORYTYPE_DEVICE
,
3202 .srcDevice
= (CUdeviceptr
)src
->data
[i
],
3203 .srcPitch
= src
->linesize
[i
],
3206 .dstMemoryType
= CU_MEMORYTYPE_ARRAY
,
3207 .dstArray
= dst_int
->cu_array
[i
],
3211 get_plane_wh(&p_w
, &p_h
, hwfc
->sw_format
, hwfc
->width
, hwfc
->height
, i
);
3213 cpy
.WidthInBytes
= p_w
* desc
->comp
[i
].step
;
3216 err
= CHECK_CU(cu
->cuMemcpy2DAsync(&cpy
, cuda_dev
->stream
));
3221 err
= CHECK_CU(cu
->cuSignalExternalSemaphoresAsync(dst_int
->cu_sem
, s_s_par
,
3222 planes
, cuda_dev
->stream
));
3226 for (int i
= 0; i
< planes
; i
++)
3227 dst_f
->sem_value
[i
]++;
3229 CHECK_CU(cu
->cuCtxPopCurrent(&dummy
));
3231 av_log(hwfc
, AV_LOG_VERBOSE
, "Transfered CUDA image to Vulkan!\n");
3233 return err
= prepare_frame(hwfc
, &fp
->upload_ctx
, dst_f
, PREP_MODE_EXTERNAL_IMPORT
);
3236 CHECK_CU(cu
->cuCtxPopCurrent(&dummy
));
3237 vulkan_free_internal(dst_f
);
3238 dst_f
->internal
= NULL
;
3239 av_buffer_unref(&dst
->buf
[0]);
3244 static int vulkan_map_to(AVHWFramesContext
*hwfc
, AVFrame
*dst
,
3245 const AVFrame
*src
, int flags
)
3247 av_unused VulkanDevicePriv
*p
= hwfc
->device_ctx
->internal
->priv
;
3249 switch (src
->format
) {
3252 case AV_PIX_FMT_VAAPI
:
3253 if (p
->extensions
& (FF_VK_EXT_EXTERNAL_DMABUF_MEMORY
| FF_VK_EXT_DRM_MODIFIER_FLAGS
))
3254 return vulkan_map_from_vaapi(hwfc
, dst
, src
, flags
);
3256 return AVERROR(ENOSYS
);
3258 case AV_PIX_FMT_DRM_PRIME
:
3259 if (p
->extensions
& (FF_VK_EXT_EXTERNAL_DMABUF_MEMORY
| FF_VK_EXT_DRM_MODIFIER_FLAGS
))
3260 return vulkan_map_from_drm(hwfc
, dst
, src
, flags
);
3262 return AVERROR(ENOSYS
);
3265 return AVERROR(ENOSYS
);
3270 typedef struct VulkanDRMMapping
{
3271 AVDRMFrameDescriptor drm_desc
;
3275 static void vulkan_unmap_to_drm(AVHWFramesContext
*hwfc
, HWMapDescriptor
*hwmap
)
3277 AVDRMFrameDescriptor
*drm_desc
= hwmap
->priv
;
3279 for (int i
= 0; i
< drm_desc
->nb_objects
; i
++)
3280 close(drm_desc
->objects
[i
].fd
);
3285 static inline uint32_t vulkan_fmt_to_drm(VkFormat vkfmt
)
3287 for (int i
= 0; i
< FF_ARRAY_ELEMS(vulkan_drm_format_map
); i
++)
3288 if (vulkan_drm_format_map
[i
].vk_format
== vkfmt
)
3289 return vulkan_drm_format_map
[i
].drm_fourcc
;
3290 return DRM_FORMAT_INVALID
;
3293 static int vulkan_map_to_drm(AVHWFramesContext
*hwfc
, AVFrame
*dst
,
3294 const AVFrame
*src
, int flags
)
3298 AVVkFrame
*f
= (AVVkFrame
*)src
->data
[0];
3299 VulkanDevicePriv
*p
= hwfc
->device_ctx
->internal
->priv
;
3300 FFVulkanFunctions
*vk
= &p
->vkfn
;
3301 VulkanFramesPriv
*fp
= hwfc
->internal
->priv
;
3302 AVVulkanDeviceContext
*hwctx
= hwfc
->device_ctx
->hwctx
;
3303 AVVulkanFramesContext
*hwfctx
= hwfc
->hwctx
;
3304 const int planes
= av_pix_fmt_count_planes(hwfc
->sw_format
);
3305 VkImageDrmFormatModifierPropertiesEXT drm_mod
= {
3306 .sType
= VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT
,
3308 VkSemaphoreWaitInfo wait_info
= {
3309 .sType
= VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO
,
3311 .semaphoreCount
= planes
,
3314 AVDRMFrameDescriptor
*drm_desc
= av_mallocz(sizeof(*drm_desc
));
3316 return AVERROR(ENOMEM
);
3318 err
= prepare_frame(hwfc
, &fp
->conv_ctx
, f
, PREP_MODE_EXTERNAL_EXPORT
);
3322 /* Wait for the operation to finish so we can cleanly export it. */
3323 wait_info
.pSemaphores
= f
->sem
;
3324 wait_info
.pValues
= f
->sem_value
;
3326 vk
->WaitSemaphores(hwctx
->act_dev
, &wait_info
, UINT64_MAX
);
3328 err
= ff_hwframe_map_create(src
->hw_frames_ctx
, dst
, src
, &vulkan_unmap_to_drm
, drm_desc
);
3332 ret
= vk
->GetImageDrmFormatModifierPropertiesEXT(hwctx
->act_dev
, f
->img
[0],
3334 if (ret
!= VK_SUCCESS
) {
3335 av_log(hwfc
, AV_LOG_ERROR
, "Failed to retrieve DRM format modifier!\n");
3336 err
= AVERROR_EXTERNAL
;
3340 for (int i
= 0; (i
< planes
) && (f
->mem
[i
]); i
++) {
3341 VkMemoryGetFdInfoKHR export_info
= {
3342 .sType
= VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR
,
3343 .memory
= f
->mem
[i
],
3344 .handleType
= VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT
,
3347 ret
= vk
->GetMemoryFdKHR(hwctx
->act_dev
, &export_info
,
3348 &drm_desc
->objects
[i
].fd
);
3349 if (ret
!= VK_SUCCESS
) {
3350 av_log(hwfc
, AV_LOG_ERROR
, "Unable to export the image as a FD!\n");
3351 err
= AVERROR_EXTERNAL
;
3355 drm_desc
->nb_objects
++;
3356 drm_desc
->objects
[i
].size
= f
->size
[i
];
3357 drm_desc
->objects
[i
].format_modifier
= drm_mod
.drmFormatModifier
;
3360 drm_desc
->nb_layers
= planes
;
3361 for (int i
= 0; i
< drm_desc
->nb_layers
; i
++) {
3362 VkSubresourceLayout layout
;
3363 VkImageSubresource sub
= {
3364 .aspectMask
= VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT
,
3366 VkFormat plane_vkfmt
= av_vkfmt_from_pixfmt(hwfc
->sw_format
)[i
];
3368 drm_desc
->layers
[i
].format
= vulkan_fmt_to_drm(plane_vkfmt
);
3369 drm_desc
->layers
[i
].nb_planes
= 1;
3371 if (drm_desc
->layers
[i
].format
== DRM_FORMAT_INVALID
) {
3372 av_log(hwfc
, AV_LOG_ERROR
, "Cannot map to DRM layer, unsupported!\n");
3373 err
= AVERROR_PATCHWELCOME
;
3377 drm_desc
->layers
[i
].planes
[0].object_index
= FFMIN(i
, drm_desc
->nb_objects
- 1);
3379 if (f
->tiling
== VK_IMAGE_TILING_OPTIMAL
)
3382 vk
->GetImageSubresourceLayout(hwctx
->act_dev
, f
->img
[i
], &sub
, &layout
);
3383 drm_desc
->layers
[i
].planes
[0].offset
= layout
.offset
;
3384 drm_desc
->layers
[i
].planes
[0].pitch
= layout
.rowPitch
;
3386 if (hwfctx
->flags
& AV_VK_FRAME_FLAG_CONTIGUOUS_MEMORY
)
3387 drm_desc
->layers
[i
].planes
[0].offset
+= f
->offset
[i
];
3390 dst
->width
= src
->width
;
3391 dst
->height
= src
->height
;
3392 dst
->data
[0] = (uint8_t *)drm_desc
;
3394 av_log(hwfc
, AV_LOG_VERBOSE
, "Mapped AVVkFrame to a DRM object!\n");
3404 static int vulkan_map_to_vaapi(AVHWFramesContext
*hwfc
, AVFrame
*dst
,
3405 const AVFrame
*src
, int flags
)
3408 AVFrame
*tmp
= av_frame_alloc();
3410 return AVERROR(ENOMEM
);
3412 tmp
->format
= AV_PIX_FMT_DRM_PRIME
;
3414 err
= vulkan_map_to_drm(hwfc
, tmp
, src
, flags
);
3418 err
= av_hwframe_map(dst
, tmp
, flags
);
3422 err
= ff_hwframe_map_replace(dst
, src
);
3425 av_frame_free(&tmp
);
3431 static int vulkan_map_from(AVHWFramesContext
*hwfc
, AVFrame
*dst
,
3432 const AVFrame
*src
, int flags
)
3434 av_unused VulkanDevicePriv
*p
= hwfc
->device_ctx
->internal
->priv
;
3436 switch (dst
->format
) {
3438 case AV_PIX_FMT_DRM_PRIME
:
3439 if (p
->extensions
& (FF_VK_EXT_EXTERNAL_DMABUF_MEMORY
| FF_VK_EXT_DRM_MODIFIER_FLAGS
))
3440 return vulkan_map_to_drm(hwfc
, dst
, src
, flags
);
3442 return AVERROR(ENOSYS
);
3444 case AV_PIX_FMT_VAAPI
:
3445 if (p
->extensions
& (FF_VK_EXT_EXTERNAL_DMABUF_MEMORY
| FF_VK_EXT_DRM_MODIFIER_FLAGS
))
3446 return vulkan_map_to_vaapi(hwfc
, dst
, src
, flags
);
3448 return AVERROR(ENOSYS
);
3452 return vulkan_map_frame_to_mem(hwfc
, dst
, src
, flags
);
3456 typedef struct ImageBuffer
{
3459 VkMemoryPropertyFlagBits flags
;
3463 static void free_buf(void *opaque
, uint8_t *data
)
3465 AVHWDeviceContext
*ctx
= opaque
;
3466 AVVulkanDeviceContext
*hwctx
= ctx
->hwctx
;
3467 VulkanDevicePriv
*p
= ctx
->internal
->priv
;
3468 FFVulkanFunctions
*vk
= &p
->vkfn
;
3469 ImageBuffer
*vkbuf
= (ImageBuffer
*)data
;
3472 vk
->DestroyBuffer(hwctx
->act_dev
, vkbuf
->buf
, hwctx
->alloc
);
3474 vk
->FreeMemory(hwctx
->act_dev
, vkbuf
->mem
, hwctx
->alloc
);
3479 static size_t get_req_buffer_size(VulkanDevicePriv
*p
, int *stride
, int height
)
3482 *stride
= FFALIGN(*stride
, p
->props
.properties
.limits
.optimalBufferCopyRowPitchAlignment
);
3483 size
= height
*(*stride
);
3484 size
= FFALIGN(size
, p
->props
.properties
.limits
.minMemoryMapAlignment
);
3488 static int create_buf(AVHWDeviceContext
*ctx
, AVBufferRef
**buf
,
3489 VkBufferUsageFlags usage
, VkMemoryPropertyFlagBits flags
,
3490 size_t size
, uint32_t req_memory_bits
, int host_mapped
,
3491 void *create_pnext
, void *alloc_pnext
)
3496 AVVulkanDeviceContext
*hwctx
= ctx
->hwctx
;
3497 VulkanDevicePriv
*p
= ctx
->internal
->priv
;
3498 FFVulkanFunctions
*vk
= &p
->vkfn
;
3500 VkBufferCreateInfo buf_spawn
= {
3501 .sType
= VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO
,
3502 .pNext
= create_pnext
,
3505 .sharingMode
= VK_SHARING_MODE_EXCLUSIVE
,
3508 VkBufferMemoryRequirementsInfo2 req_desc
= {
3509 .sType
= VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2
,
3511 VkMemoryDedicatedAllocateInfo ded_alloc
= {
3512 .sType
= VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO
,
3513 .pNext
= alloc_pnext
,
3515 VkMemoryDedicatedRequirements ded_req
= {
3516 .sType
= VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS
,
3518 VkMemoryRequirements2 req
= {
3519 .sType
= VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2
,
3523 ImageBuffer
*vkbuf
= av_mallocz(sizeof(*vkbuf
));
3525 return AVERROR(ENOMEM
);
3527 vkbuf
->mapped_mem
= host_mapped
;
3529 ret
= vk
->CreateBuffer(hwctx
->act_dev
, &buf_spawn
, NULL
, &vkbuf
->buf
);
3530 if (ret
!= VK_SUCCESS
) {
3531 av_log(ctx
, AV_LOG_ERROR
, "Failed to create buffer: %s\n",
3533 err
= AVERROR_EXTERNAL
;
3537 req_desc
.buffer
= vkbuf
->buf
;
3539 vk
->GetBufferMemoryRequirements2(hwctx
->act_dev
, &req_desc
, &req
);
3541 /* In case the implementation prefers/requires dedicated allocation */
3542 use_ded_mem
= ded_req
.prefersDedicatedAllocation
|
3543 ded_req
.requiresDedicatedAllocation
;
3545 ded_alloc
.buffer
= vkbuf
->buf
;
3547 /* Additional requirements imposed on us */
3548 if (req_memory_bits
)
3549 req
.memoryRequirements
.memoryTypeBits
&= req_memory_bits
;
3551 err
= alloc_mem(ctx
, &req
.memoryRequirements
, flags
,
3552 use_ded_mem
? &ded_alloc
: (void *)ded_alloc
.pNext
,
3553 &vkbuf
->flags
, &vkbuf
->mem
);
3557 ret
= vk
->BindBufferMemory(hwctx
->act_dev
, vkbuf
->buf
, vkbuf
->mem
, 0);
3558 if (ret
!= VK_SUCCESS
) {
3559 av_log(ctx
, AV_LOG_ERROR
, "Failed to bind memory to buffer: %s\n",
3561 err
= AVERROR_EXTERNAL
;
3565 *buf
= av_buffer_create((uint8_t *)vkbuf
, sizeof(*vkbuf
), free_buf
, ctx
, 0);
3567 err
= AVERROR(ENOMEM
);
3574 free_buf(ctx
, (uint8_t *)vkbuf
);
3578 /* Skips mapping of host mapped buffers but still invalidates them */
3579 static int map_buffers(AVHWDeviceContext
*ctx
, AVBufferRef
**bufs
, uint8_t *mem
[],
3580 int nb_buffers
, int invalidate
)
3583 AVVulkanDeviceContext
*hwctx
= ctx
->hwctx
;
3584 VulkanDevicePriv
*p
= ctx
->internal
->priv
;
3585 FFVulkanFunctions
*vk
= &p
->vkfn
;
3586 VkMappedMemoryRange invalidate_ctx
[AV_NUM_DATA_POINTERS
];
3587 int invalidate_count
= 0;
3589 for (int i
= 0; i
< nb_buffers
; i
++) {
3590 ImageBuffer
*vkbuf
= (ImageBuffer
*)bufs
[i
]->data
;
3591 if (vkbuf
->mapped_mem
)
3594 ret
= vk
->MapMemory(hwctx
->act_dev
, vkbuf
->mem
, 0,
3595 VK_WHOLE_SIZE
, 0, (void **)&mem
[i
]);
3596 if (ret
!= VK_SUCCESS
) {
3597 av_log(ctx
, AV_LOG_ERROR
, "Failed to map buffer memory: %s\n",
3599 return AVERROR_EXTERNAL
;
3606 for (int i
= 0; i
< nb_buffers
; i
++) {
3607 ImageBuffer
*vkbuf
= (ImageBuffer
*)bufs
[i
]->data
;
3608 const VkMappedMemoryRange ival_buf
= {
3609 .sType
= VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE
,
3610 .memory
= vkbuf
->mem
,
3611 .size
= VK_WHOLE_SIZE
,
3614 /* For host imported memory Vulkan says to use platform-defined
3615 * sync methods, but doesn't really say not to call flush or invalidate
3616 * on original host pointers. It does explicitly allow to do that on
3617 * host-mapped pointers which are then mapped again using vkMapMemory,
3618 * but known implementations return the original pointers when mapped
3620 if (vkbuf
->flags
& VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
)
3623 invalidate_ctx
[invalidate_count
++] = ival_buf
;
3626 if (invalidate_count
) {
3627 ret
= vk
->InvalidateMappedMemoryRanges(hwctx
->act_dev
, invalidate_count
,
3629 if (ret
!= VK_SUCCESS
)
3630 av_log(ctx
, AV_LOG_WARNING
, "Failed to invalidate memory: %s\n",
3637 static int unmap_buffers(AVHWDeviceContext
*ctx
, AVBufferRef
**bufs
,
3638 int nb_buffers
, int flush
)
3642 AVVulkanDeviceContext
*hwctx
= ctx
->hwctx
;
3643 VulkanDevicePriv
*p
= ctx
->internal
->priv
;
3644 FFVulkanFunctions
*vk
= &p
->vkfn
;
3645 VkMappedMemoryRange flush_ctx
[AV_NUM_DATA_POINTERS
];
3646 int flush_count
= 0;
3649 for (int i
= 0; i
< nb_buffers
; i
++) {
3650 ImageBuffer
*vkbuf
= (ImageBuffer
*)bufs
[i
]->data
;
3651 const VkMappedMemoryRange flush_buf
= {
3652 .sType
= VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE
,
3653 .memory
= vkbuf
->mem
,
3654 .size
= VK_WHOLE_SIZE
,
3657 if (vkbuf
->flags
& VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
)
3660 flush_ctx
[flush_count
++] = flush_buf
;
3665 ret
= vk
->FlushMappedMemoryRanges(hwctx
->act_dev
, flush_count
, flush_ctx
);
3666 if (ret
!= VK_SUCCESS
) {
3667 av_log(ctx
, AV_LOG_ERROR
, "Failed to flush memory: %s\n",
3669 err
= AVERROR_EXTERNAL
; /* We still want to try to unmap them */
3673 for (int i
= 0; i
< nb_buffers
; i
++) {
3674 ImageBuffer
*vkbuf
= (ImageBuffer
*)bufs
[i
]->data
;
3675 if (vkbuf
->mapped_mem
)
3678 vk
->UnmapMemory(hwctx
->act_dev
, vkbuf
->mem
);
3684 static int transfer_image_buf(AVHWFramesContext
*hwfc
, const AVFrame
*f
,
3685 AVBufferRef
**bufs
, size_t *buf_offsets
,
3686 const int *buf_stride
, int w
,
3687 int h
, enum AVPixelFormat pix_fmt
, int to_buf
)
3690 AVVkFrame
*frame
= (AVVkFrame
*)f
->data
[0];
3691 VulkanFramesPriv
*fp
= hwfc
->internal
->priv
;
3692 VulkanDevicePriv
*p
= hwfc
->device_ctx
->internal
->priv
;
3693 FFVulkanFunctions
*vk
= &p
->vkfn
;
3696 VkPipelineStageFlagBits sem_wait_dst
[AV_NUM_DATA_POINTERS
];
3698 const int planes
= av_pix_fmt_count_planes(pix_fmt
);
3699 const AVPixFmtDescriptor
*desc
= av_pix_fmt_desc_get(pix_fmt
);
3701 VkImageMemoryBarrier img_bar
[AV_NUM_DATA_POINTERS
] = { 0 };
3702 VulkanExecCtx
*ectx
= to_buf
? &fp
->download_ctx
: &fp
->upload_ctx
;
3703 VkCommandBuffer cmd_buf
= get_buf_exec_ctx(hwfc
, ectx
);
3705 uint64_t sem_signal_values
[AV_NUM_DATA_POINTERS
];
3707 VkTimelineSemaphoreSubmitInfo s_timeline_sem_info
= {
3708 .sType
= VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO
,
3709 .pWaitSemaphoreValues
= frame
->sem_value
,
3710 .pSignalSemaphoreValues
= sem_signal_values
,
3711 .waitSemaphoreValueCount
= planes
,
3712 .signalSemaphoreValueCount
= planes
,
3715 VkSubmitInfo s_info
= {
3716 .sType
= VK_STRUCTURE_TYPE_SUBMIT_INFO
,
3717 .pNext
= &s_timeline_sem_info
,
3718 .pSignalSemaphores
= frame
->sem
,
3719 .pWaitSemaphores
= frame
->sem
,
3720 .pWaitDstStageMask
= sem_wait_dst
,
3721 .signalSemaphoreCount
= planes
,
3722 .waitSemaphoreCount
= planes
,
3725 for (int i
= 0; i
< planes
; i
++)
3726 sem_signal_values
[i
] = frame
->sem_value
[i
] + 1;
3728 if ((err
= wait_start_exec_ctx(hwfc
, ectx
)))
3731 /* Change the image layout to something more optimal for transfers */
3732 for (int i
= 0; i
< planes
; i
++) {
3733 VkImageLayout new_layout
= to_buf
? VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL
:
3734 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL
;
3735 VkAccessFlags new_access
= to_buf
? VK_ACCESS_TRANSFER_READ_BIT
:
3736 VK_ACCESS_TRANSFER_WRITE_BIT
;
3738 sem_wait_dst
[i
] = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT
;
3740 /* If the layout matches and we have read access skip the barrier */
3741 if ((frame
->layout
[i
] == new_layout
) && (frame
->access
[i
] & new_access
))
3744 img_bar
[bar_num
].sType
= VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER
;
3745 img_bar
[bar_num
].srcAccessMask
= 0x0;
3746 img_bar
[bar_num
].dstAccessMask
= new_access
;
3747 img_bar
[bar_num
].oldLayout
= frame
->layout
[i
];
3748 img_bar
[bar_num
].newLayout
= new_layout
;
3749 img_bar
[bar_num
].srcQueueFamilyIndex
= VK_QUEUE_FAMILY_IGNORED
;
3750 img_bar
[bar_num
].dstQueueFamilyIndex
= VK_QUEUE_FAMILY_IGNORED
;
3751 img_bar
[bar_num
].image
= frame
->img
[i
];
3752 img_bar
[bar_num
].subresourceRange
.levelCount
= 1;
3753 img_bar
[bar_num
].subresourceRange
.layerCount
= 1;
3754 img_bar
[bar_num
].subresourceRange
.aspectMask
= VK_IMAGE_ASPECT_COLOR_BIT
;
3756 frame
->layout
[i
] = img_bar
[bar_num
].newLayout
;
3757 frame
->access
[i
] = img_bar
[bar_num
].dstAccessMask
;
3763 vk
->CmdPipelineBarrier(cmd_buf
, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT
,
3764 VK_PIPELINE_STAGE_TRANSFER_BIT
, 0,
3765 0, NULL
, 0, NULL
, bar_num
, img_bar
);
3767 /* Schedule a copy for each plane */
3768 for (int i
= 0; i
< planes
; i
++) {
3769 ImageBuffer
*vkbuf
= (ImageBuffer
*)bufs
[i
]->data
;
3770 VkBufferImageCopy buf_reg
= {
3771 .bufferOffset
= buf_offsets
[i
],
3772 .bufferRowLength
= buf_stride
[i
] / desc
->comp
[i
].step
,
3773 .imageSubresource
.layerCount
= 1,
3774 .imageSubresource
.aspectMask
= VK_IMAGE_ASPECT_COLOR_BIT
,
3775 .imageOffset
= { 0, 0, 0, },
3779 get_plane_wh(&p_w
, &p_h
, pix_fmt
, w
, h
, i
);
3781 buf_reg
.bufferImageHeight
= p_h
;
3782 buf_reg
.imageExtent
= (VkExtent3D
){ p_w
, p_h
, 1, };
3785 vk
->CmdCopyImageToBuffer(cmd_buf
, frame
->img
[i
], frame
->layout
[i
],
3786 vkbuf
->buf
, 1, &buf_reg
);
3788 vk
->CmdCopyBufferToImage(cmd_buf
, vkbuf
->buf
, frame
->img
[i
],
3789 frame
->layout
[i
], 1, &buf_reg
);
3792 /* When uploading, do this asynchronously if the source is refcounted by
3793 * keeping the buffers as a submission dependency.
3794 * The hwcontext is guaranteed to not be freed until all frames are freed
3795 * in the frames_unint function.
3796 * When downloading to buffer, do this synchronously and wait for the
3797 * queue submission to finish executing */
3800 for (ref
= 0; ref
< AV_NUM_DATA_POINTERS
; ref
++) {
3803 if ((err
= add_buf_dep_exec_ctx(hwfc
, ectx
, &f
->buf
[ref
], 1)))
3806 if (ref
&& (err
= add_buf_dep_exec_ctx(hwfc
, ectx
, bufs
, planes
)))
3808 return submit_exec_ctx(hwfc
, ectx
, &s_info
, frame
, !ref
);
3810 return submit_exec_ctx(hwfc
, ectx
, &s_info
, frame
, 1);
3814 static int vulkan_transfer_data(AVHWFramesContext
*hwfc
, const AVFrame
*vkf
,
3815 const AVFrame
*swf
, int from
)
3819 AVVkFrame
*f
= (AVVkFrame
*)vkf
->data
[0];
3820 AVHWDeviceContext
*dev_ctx
= hwfc
->device_ctx
;
3821 AVVulkanDeviceContext
*hwctx
= dev_ctx
->hwctx
;
3822 VulkanDevicePriv
*p
= hwfc
->device_ctx
->internal
->priv
;
3823 FFVulkanFunctions
*vk
= &p
->vkfn
;
3826 AVBufferRef
*bufs
[AV_NUM_DATA_POINTERS
] = { 0 };
3827 size_t buf_offsets
[AV_NUM_DATA_POINTERS
] = { 0 };
3830 const int planes
= av_pix_fmt_count_planes(swf
->format
);
3832 int host_mapped
[AV_NUM_DATA_POINTERS
] = { 0 };
3833 const int map_host
= !!(p
->extensions
& FF_VK_EXT_EXTERNAL_HOST_MEMORY
);
3835 if ((swf
->format
!= AV_PIX_FMT_NONE
&& !av_vkfmt_from_pixfmt(swf
->format
))) {
3836 av_log(hwfc
, AV_LOG_ERROR
, "Unsupported software frame pixel format!\n");
3837 return AVERROR(EINVAL
);
3840 if (swf
->width
> hwfc
->width
|| swf
->height
> hwfc
->height
)
3841 return AVERROR(EINVAL
);
3843 /* For linear, host visiable images */
3844 if (f
->tiling
== VK_IMAGE_TILING_LINEAR
&&
3845 f
->flags
& VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
) {
3846 AVFrame
*map
= av_frame_alloc();
3848 return AVERROR(ENOMEM
);
3849 map
->format
= swf
->format
;
3851 err
= vulkan_map_frame_to_mem(hwfc
, map
, vkf
, AV_HWFRAME_MAP_WRITE
);
3855 err
= av_frame_copy((AVFrame
*)(from
? swf
: map
), from
? map
: swf
);
3856 av_frame_free(&map
);
3860 /* Create buffers */
3861 for (int i
= 0; i
< planes
; i
++) {
3864 VkExternalMemoryBufferCreateInfo create_desc
= {
3865 .sType
= VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO
,
3866 .handleTypes
= VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT
,
3869 VkImportMemoryHostPointerInfoEXT import_desc
= {
3870 .sType
= VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT
,
3871 .handleType
= VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT
,
3874 VkMemoryHostPointerPropertiesEXT p_props
= {
3875 .sType
= VK_STRUCTURE_TYPE_MEMORY_HOST_POINTER_PROPERTIES_EXT
,
3878 get_plane_wh(&p_w
, &p_h
, swf
->format
, swf
->width
, swf
->height
, i
);
3880 tmp
.linesize
[i
] = FFABS(swf
->linesize
[i
]);
3882 /* Do not map images with a negative stride */
3883 if (map_host
&& swf
->linesize
[i
] > 0) {
3885 offs
= (uintptr_t)swf
->data
[i
] % p
->hprops
.minImportedHostPointerAlignment
;
3886 import_desc
.pHostPointer
= swf
->data
[i
] - offs
;
3888 /* We have to compensate for the few extra bytes of padding we
3889 * completely ignore at the start */
3890 req_size
= FFALIGN(offs
+ tmp
.linesize
[i
] * p_h
,
3891 p
->hprops
.minImportedHostPointerAlignment
);
3893 ret
= vk
->GetMemoryHostPointerPropertiesEXT(hwctx
->act_dev
,
3894 import_desc
.handleType
,
3895 import_desc
.pHostPointer
,
3898 if (ret
== VK_SUCCESS
) {
3900 buf_offsets
[i
] = offs
;
3904 if (!host_mapped
[i
])
3905 req_size
= get_req_buffer_size(p
, &tmp
.linesize
[i
], p_h
);
3907 err
= create_buf(dev_ctx
, &bufs
[i
],
3908 from
? VK_BUFFER_USAGE_TRANSFER_DST_BIT
:
3909 VK_BUFFER_USAGE_TRANSFER_SRC_BIT
,
3910 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
,
3911 req_size
, p_props
.memoryTypeBits
, host_mapped
[i
],
3912 host_mapped
[i
] ? &create_desc
: NULL
,
3913 host_mapped
[i
] ? &import_desc
: NULL
);
3919 /* Map, copy image TO buffer (which then goes to the VkImage), unmap */
3920 if ((err
= map_buffers(dev_ctx
, bufs
, tmp
.data
, planes
, 0)))
3923 for (int i
= 0; i
< planes
; i
++) {
3927 get_plane_wh(&p_w
, &p_h
, swf
->format
, swf
->width
, swf
->height
, i
);
3929 av_image_copy_plane(tmp
.data
[i
], tmp
.linesize
[i
],
3930 (const uint8_t *)swf
->data
[i
], swf
->linesize
[i
],
3931 FFMIN(tmp
.linesize
[i
], FFABS(swf
->linesize
[i
])),
3935 if ((err
= unmap_buffers(dev_ctx
, bufs
, planes
, 1)))
3939 /* Copy buffers into/from image */
3940 err
= transfer_image_buf(hwfc
, vkf
, bufs
, buf_offsets
, tmp
.linesize
,
3941 swf
->width
, swf
->height
, swf
->format
, from
);
3944 /* Map, copy buffer (which came FROM the VkImage) to the frame, unmap */
3945 if ((err
= map_buffers(dev_ctx
, bufs
, tmp
.data
, planes
, 0)))
3948 for (int i
= 0; i
< planes
; i
++) {
3952 get_plane_wh(&p_w
, &p_h
, swf
->format
, swf
->width
, swf
->height
, i
);
3954 av_image_copy_plane_uc_from(swf
->data
[i
], swf
->linesize
[i
],
3955 (const uint8_t *)tmp
.data
[i
], tmp
.linesize
[i
],
3956 FFMIN(tmp
.linesize
[i
], FFABS(swf
->linesize
[i
])),
3960 if ((err
= unmap_buffers(dev_ctx
, bufs
, planes
, 1)))
3965 for (int i
= 0; i
< planes
; i
++)
3966 av_buffer_unref(&bufs
[i
]);
3971 static int vulkan_transfer_data_to(AVHWFramesContext
*hwfc
, AVFrame
*dst
,
3974 av_unused VulkanDevicePriv
*p
= hwfc
->device_ctx
->internal
->priv
;
3976 switch (src
->format
) {
3978 case AV_PIX_FMT_CUDA
:
3980 if ((p
->extensions
& FF_VK_EXT_EXTERNAL_WIN32_MEMORY
) &&
3981 (p
->extensions
& FF_VK_EXT_EXTERNAL_WIN32_SEM
))
3983 if ((p
->extensions
& FF_VK_EXT_EXTERNAL_FD_MEMORY
) &&
3984 (p
->extensions
& FF_VK_EXT_EXTERNAL_FD_SEM
))
3986 return vulkan_transfer_data_from_cuda(hwfc
, dst
, src
);
3989 if (src
->hw_frames_ctx
)
3990 return AVERROR(ENOSYS
);
3992 return vulkan_transfer_data(hwfc
, dst
, src
, 0);
3997 static int vulkan_transfer_data_to_cuda(AVHWFramesContext
*hwfc
, AVFrame
*dst
,
4003 AVVkFrameInternal
*dst_int
;
4004 VulkanFramesPriv
*fp
= hwfc
->internal
->priv
;
4005 const int planes
= av_pix_fmt_count_planes(hwfc
->sw_format
);
4006 const AVPixFmtDescriptor
*desc
= av_pix_fmt_desc_get(hwfc
->sw_format
);
4008 AVHWFramesContext
*cuda_fc
= (AVHWFramesContext
*)dst
->hw_frames_ctx
->data
;
4009 AVHWDeviceContext
*cuda_cu
= cuda_fc
->device_ctx
;
4010 AVCUDADeviceContext
*cuda_dev
= cuda_cu
->hwctx
;
4011 AVCUDADeviceContextInternal
*cu_internal
= cuda_dev
->internal
;
4012 CudaFunctions
*cu
= cu_internal
->cuda_dl
;
4013 CUDA_EXTERNAL_SEMAPHORE_WAIT_PARAMS s_w_par
[AV_NUM_DATA_POINTERS
] = { 0 };
4014 CUDA_EXTERNAL_SEMAPHORE_SIGNAL_PARAMS s_s_par
[AV_NUM_DATA_POINTERS
] = { 0 };
4016 dst_f
= (AVVkFrame
*)src
->data
[0];
4018 err
= prepare_frame(hwfc
, &fp
->upload_ctx
, dst_f
, PREP_MODE_EXTERNAL_EXPORT
);
4022 err
= CHECK_CU(cu
->cuCtxPushCurrent(cuda_dev
->cuda_ctx
));
4026 err
= vulkan_export_to_cuda(hwfc
, dst
->hw_frames_ctx
, src
);
4028 CHECK_CU(cu
->cuCtxPopCurrent(&dummy
));
4032 dst_int
= dst_f
->internal
;
4034 for (int i
= 0; i
< planes
; i
++) {
4035 s_w_par
[i
].params
.fence
.value
= dst_f
->sem_value
[i
] + 0;
4036 s_s_par
[i
].params
.fence
.value
= dst_f
->sem_value
[i
] + 1;
4039 err
= CHECK_CU(cu
->cuWaitExternalSemaphoresAsync(dst_int
->cu_sem
, s_w_par
,
4040 planes
, cuda_dev
->stream
));
4044 for (int i
= 0; i
< planes
; i
++) {
4045 CUDA_MEMCPY2D cpy
= {
4046 .dstMemoryType
= CU_MEMORYTYPE_DEVICE
,
4047 .dstDevice
= (CUdeviceptr
)dst
->data
[i
],
4048 .dstPitch
= dst
->linesize
[i
],
4051 .srcMemoryType
= CU_MEMORYTYPE_ARRAY
,
4052 .srcArray
= dst_int
->cu_array
[i
],
4056 get_plane_wh(&w
, &h
, hwfc
->sw_format
, hwfc
->width
, hwfc
->height
, i
);
4058 cpy
.WidthInBytes
= w
* desc
->comp
[i
].step
;
4061 err
= CHECK_CU(cu
->cuMemcpy2DAsync(&cpy
, cuda_dev
->stream
));
4066 err
= CHECK_CU(cu
->cuSignalExternalSemaphoresAsync(dst_int
->cu_sem
, s_s_par
,
4067 planes
, cuda_dev
->stream
));
4071 for (int i
= 0; i
< planes
; i
++)
4072 dst_f
->sem_value
[i
]++;
4074 CHECK_CU(cu
->cuCtxPopCurrent(&dummy
));
4076 av_log(hwfc
, AV_LOG_VERBOSE
, "Transfered Vulkan image to CUDA!\n");
4078 return prepare_frame(hwfc
, &fp
->upload_ctx
, dst_f
, PREP_MODE_EXTERNAL_IMPORT
);
4081 CHECK_CU(cu
->cuCtxPopCurrent(&dummy
));
4082 vulkan_free_internal(dst_f
);
4083 dst_f
->internal
= NULL
;
4084 av_buffer_unref(&dst
->buf
[0]);
4089 static int vulkan_transfer_data_from(AVHWFramesContext
*hwfc
, AVFrame
*dst
,
4092 av_unused VulkanDevicePriv
*p
= hwfc
->device_ctx
->internal
->priv
;
4094 switch (dst
->format
) {
4096 case AV_PIX_FMT_CUDA
:
4098 if ((p
->extensions
& FF_VK_EXT_EXTERNAL_WIN32_MEMORY
) &&
4099 (p
->extensions
& FF_VK_EXT_EXTERNAL_WIN32_SEM
))
4101 if ((p
->extensions
& FF_VK_EXT_EXTERNAL_FD_MEMORY
) &&
4102 (p
->extensions
& FF_VK_EXT_EXTERNAL_FD_SEM
))
4104 return vulkan_transfer_data_to_cuda(hwfc
, dst
, src
);
4107 if (dst
->hw_frames_ctx
)
4108 return AVERROR(ENOSYS
);
4110 return vulkan_transfer_data(hwfc
, src
, dst
, 1);
4114 static int vulkan_frames_derive_to(AVHWFramesContext
*dst_fc
,
4115 AVHWFramesContext
*src_fc
, int flags
)
4117 return vulkan_frames_init(dst_fc
);
4120 AVVkFrame
*av_vk_frame_alloc(void)
4122 return av_mallocz(sizeof(AVVkFrame
));
4125 const HWContextType ff_hwcontext_type_vulkan
= {
4126 .type
= AV_HWDEVICE_TYPE_VULKAN
,
4129 .device_hwctx_size
= sizeof(AVVulkanDeviceContext
),
4130 .device_priv_size
= sizeof(VulkanDevicePriv
),
4131 .frames_hwctx_size
= sizeof(AVVulkanFramesContext
),
4132 .frames_priv_size
= sizeof(VulkanFramesPriv
),
4134 .device_init
= &vulkan_device_init
,
4135 .device_create
= &vulkan_device_create
,
4136 .device_derive
= &vulkan_device_derive
,
4138 .frames_get_constraints
= &vulkan_frames_get_constraints
,
4139 .frames_init
= vulkan_frames_init
,
4140 .frames_get_buffer
= vulkan_get_buffer
,
4141 .frames_uninit
= vulkan_frames_uninit
,
4143 .transfer_get_formats
= vulkan_transfer_get_formats
,
4144 .transfer_data_to
= vulkan_transfer_data_to
,
4145 .transfer_data_from
= vulkan_transfer_data_from
,
4147 .map_to
= vulkan_map_to
,
4148 .map_from
= vulkan_map_from
,
4149 .frames_derive_to
= &vulkan_frames_derive_to
,
4151 .pix_fmts
= (const enum AVPixelFormat
[]) {